<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Abdul Yadi's Blog</title>
	
	<link>http://abdulyadi.wordpress.com</link>
	<description>once upon a time in Batam</description>
	<lastBuildDate>Wed, 08 May 2013 03:41:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain="abdulyadi.wordpress.com" port="80" path="/?rsscloud=notify" registerProcedure="" protocol="http-post" />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Abdul Yadi's Blog</title>
		<link>http://abdulyadi.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://abdulyadi.wordpress.com/osd.xml" title="Abdul Yadi's Blog" />
	
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/AbdulyadisBlog" /><feedburner:info uri="abdulyadisblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://abdulyadi.wordpress.com/?pushpress=hub" /><feedburner:browserFriendly></feedburner:browserFriendly><item>
		<title>PgDBF: convert FoxPro to PostgreSQL’s non-Public Schema</title>
		<link>http://abdulyadi.wordpress.com/2013/01/06/pgdbf-convert-foxpro-to-postgresqls-non-public-schema/</link>
		<comments>http://abdulyadi.wordpress.com/2013/01/06/pgdbf-convert-foxpro-to-postgresqls-non-public-schema/#comments</comments>
		<pubDate>Sun, 06 Jan 2013 05:42:45 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=205</guid>
		<description><![CDATA[PgDBF: convert FoxPro to PostgreSQL&#8217;s non-Public Schema Recently, I have to migrate Foxpro tables into PostgreSQL. I have downloaded the latest version of PgDBF originally written by Kirk Strauser (http://sourceforge.net/projects/pgdbf/files/latest/download?source=files), and successfully built the package. It run well. All foxpro data can only be stored in public schema, PgDBF does not offer option for other [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=205&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<div style="font-weight:bold;text-align:center;">PgDBF: convert FoxPro to PostgreSQL&#8217;s non-Public Schema</div>
<div style="margin-top:5mm;">Recently, I have to migrate Foxpro tables into PostgreSQL. I have downloaded the latest version of PgDBF originally written by Kirk Strauser (<a href>http://sourceforge.net/projects/pgdbf/files/latest/download?source=files</a>), and successfully built the package. It run well. All foxpro data can only be stored in public schema, PgDBF does not offer option for other schema.</div>
<div style="margin-top:5mm;">For that purpose I have created a patch. Once the package rebuilt, I can issue command with &#8220;upper-cased S&#8221; option <span style="font-family:courier;font-size:10pt;font-weight:bold;">-S myschema</span> (assuming I have already had the lowercase-typed schema in my PostgreSQL database):</div>
<div style="margin-top:5mm;font-family:courier;font-size:10pt;font-weight:bold;text-align:center;">pgdbf -S myschema myfox.dbf</div>
<div style="margin-top:5mm;"><a href="http://abdulyadi.files.wordpress.com/2013/01/pgdbf_patch.doc">pgdbf_patch</a>:</div>
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-top:5mm;margin-right:50px;">
&#8212; pgdbf.c	2013-01-06 10:18:41.268248051 +0700<br />
+++ pgdbf_new.c	2013-01-06 11:14:17.766415632 +0700<br />
@@ -31,7 +31,7 @@</p>
<p> #include &#8220;pgdbf.h&#8221;</p>
<p>-#define STANDARDOPTS &#8220;cCdDeEhm:nNpPqQtTuU&#8221;<br />
+#define STANDARDOPTS &#8220;cCdDeEhm:nNpPqQtTuUS:&#8221;</p>
<p> int main(int argc, char **argv) {<br />
     /* Describing the DBF file */<br />
@@ -121,6 +121,8 @@<br />
     char *optinputcharset = NULL;<br />
 #endif</p>
<p>+	char *optcustomschema= NULL;<br />
+<br />
     strcpy(optvalidargs, STANDARDOPTS);<br />
 #if defined(HAVE_ICONV)<br />
     /* Note that the declaration for optvalidargs currently reserves exactly<br />
@@ -193,6 +195,9 @@<br />
         case &#8216;U&#8217;:<br />
             optusetruncatetable = 0;<br />
             break;<br />
+	case &#8216;S&#8217;:<br />
+		optcustomschema= optarg;<br />
+		break;<br />
         case &#8216;h&#8217;:<br />
         default:<br />
             /* If we got here because someone requested &#8216;-h&#8217;, exit<br />
@@ -211,9 +216,9 @@<br />
     if(optexitcode != -1) {<br />
         printf(<br />
 #if defined(HAVE_ICONV)<br />
-               &#8220;Usage: %s [-cCdDeEhtTuU] [-s encoding] [-m memofilename] filename [indexcolumn ...]\n&#8221;<br />
+               &#8220;Usage: %s [-cCdDeEhtTuU] [-s encoding] [-S customschema] [-m memofilename] filename [indexcolumn ...]\n&#8221;<br />
 #else<br />
-               &#8220;Usage: %s [-cCdDeEhtTuU] [-m memofilename] filename [indexcolumn ...]\n&#8221;<br />
+               &#8220;Usage: %s [-cCdDeEhtTuU] [-S customschema] [-m memofilename] filename [indexcolumn ...]\n&#8221;<br />
 #endif<br />
                &#8220;Convert the named XBase file into PostgreSQL format\n&#8221;<br />
                &#8220;\n&#8221;<br />
@@ -234,6 +239,7 @@<br />
 #if defined(HAVE_ICONV)<br />
                &#8221;  -s  the encoding used in the file, to be converted to UTF-8\n&#8221;<br />
 #endif<br />
+		&#8221;  -S  the custom postgresql schema\n&#8221;<br />
                &#8221;  -t  wrap a transaction around the entire series of statements (default)\n&#8221;<br />
                &#8221;  -T  do not use an enclosing transaction\n&#8221;<br />
                &#8221;  -u  issue a &#8216;TRUNCATE&#8217; command before inserting data\n&#8221;<br />
@@ -288,7 +294,7 @@<br />
      * is used for other things, like creating the names of indexes. Despite<br />
      * its name, baretablename may be surrounded by quote marks if the &#8220;-q&#8221;<br />
      * option for optusequotedtablename is given. */<br />
-    baretablename = malloc(strlen(dbffilename) + 1 + optusequotedtablename * 2);<br />
+    baretablename = malloc( (optcustomschema!=NULL ? (strlen(optcustomschema) + 1/*dot schema separator*/) : 0) + strlen(dbffilename) + 1 + optusequotedtablename * 2);<br />
     if(baretablename == NULL) {<br />
         exitwitherror(&#8220;Unable to allocate the bare tablename buffer&#8221;, 1);<br />
     }<br />
@@ -304,6 +310,12 @@<br />
     /* Create tablename and baretablename at the same time. */<br />
     t = tablename;<br />
     u = baretablename;<br />
+	if(optcustomschema!=NULL) {<br />
+		for(i=0,j=strlen(optcustomschema);i&lt;j;++i){<br />
+			*u++=tolower(optcustomschema[i]);<br />
+		}<br />
+		*u++ = &#039;.&#039;; //dot schema separator<br />
+	}<br />
     if(optusequotedtablename) *u++ = &#039;&quot;&#039;;<br />
     while(*s) {<br />
         if(*s == &#039;.&#039;) {
</p></div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/205/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/205/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=205&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2013/01/06/pgdbf-convert-foxpro-to-postgresqls-non-public-schema/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Who’s Birthday</title>
		<link>http://abdulyadi.wordpress.com/2012/10/24/whos-birthday/</link>
		<comments>http://abdulyadi.wordpress.com/2012/10/24/whos-birthday/#comments</comments>
		<pubDate>Wed, 24 Oct 2012 17:17:13 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=194</guid>
		<description><![CDATA[Finding who&#8217;s birthday on a day or over a period of days is always interesting. Finding it from a computer database is even more interesting. Here it is a table to start with (all works below is on PostgreSQL version 9.1.3): CREATE TABLE person ( id integer NOT NULL, dob date NOT NULL, CONSTRAINT &#8220;id [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=194&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Finding who&#8217;s birthday on a day or over a period of days is always interesting. Finding it from a computer database is even more interesting.</p>
<p>Here it is a table to start with (all works below is on PostgreSQL version 9.1.3):</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
CREATE TABLE person<br />
(<br />
<span style="padding-left:30px;">id integer NOT NULL,</span><br />
<span style="padding-left:30px;">dob date NOT NULL,<br />
<span style="padding-left:30px;">CONSTRAINT &#8220;id must be unique&#8221; PRIMARY KEY (id)<br />
)<br />
WITH (OIDS=FALSE);</p>
<p>Fill it with 500,000 dummy records with random birthday:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
INSERT INTO person<br />
WITH RECURSIVE t AS (<br />
<span style="padding-left:30px;">SELECT 1 AS id, DATE_PLI(&#8217;1970-01-01&#8242;::date, (RANDOM() * 5000)::integer ) AS dob<br />
<span style="padding-left:30px;">UNION ALL<br />
<span style="padding-left:30px;">SELECT t.id+1 AS id, DATE_PLI(&#8217;1970-01-01&#8242;::date, (RANDOM() * 5000)::integer ) AS dob FROM t<br />
<span style="padding-left:30px;">WHERE t.id&lt;500000<br />
)<br />
SELECT t.id, t.dob FROM t;
</p>
<p>Now let us examine a query to find out who&#8217;s birthday on Dec 30th 2012:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
EXPLAIN ANALYZE<br />
SELECT * FROM person WHERE DATE_PART(&#8216;MONTH&#8217;,dob)=DATE_PART(&#8216;MONTH&#8217;,&#8217;2012-12-30&#8242;::date) AND DATE_PART(&#8216;DAY&#8217;,dob)=DATE_PART(&#8216;DAY&#8217;,&#8217;2012-12-30&#8242;::date);
</p>
<p style="margin-left:30px;">Result:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
Seq Scan on person  (cost=0.00..14713.00 rows=12 width=8) (actual time=0.226..284.272 rows=1365 loops=1)<br />
<span style="padding-left:30px;">Filter: ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone) = 12::double precision) AND (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone) = 30::double precision))<br />
<span style="font-size:11pt;font-weight:bold;color:red;">Total runtime: 286.369 ms</span></p>
<p>Can we do it faster? with the help of <b>index</b>.</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
CREATE INDEX &#8220;person_idx_dob1&#8243; ON person USING btree<br />
<span style="padding-left:30px;">( INT4PL( DATE_PART(&#8216;MONTH&#8217;,dob)::integer*100, DATE_PART(&#8216;DAY&#8217;,dob)::integer ) );</p>
<p style="margin-left:30px;">Let us examine a query in different way so the index works:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
EXPLAIN ANALYZE<br />
SELECT * FROM person<br />
WHERE INT4PL(DATE_PART(&#8216;MONTH&#8217;,dob)::integer*100,DATE_PART(&#8216;DAY&#8217;,dob)::integer)=<br />
<span style="padding-left:30px;">INT4PL(DATE_PART(&#8216;MONTH&#8217;,&#8217;2012-12-30&#8242;::date)::integer*100,DATE_PART(&#8216;DAY&#8217;,&#8217;2012-12-30&#8242;::date)::integer);</p>
<p style="margin-left:30px;">Result:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
Bitmap Heap Scan on person  (cost=43.69..2443.18 rows=2500 width=8) (actual time=0.481..3.805 rows=1365 loops=1)<br />
<span style="padding-left:30px;">Recheck Cond: (int4pl(((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) = 1230)<br />
<span style="padding-left:30px;">-&gt;  Bitmap Index Scan on person_idx_dob1  (cost=0.00..43.06 rows=2500 width=0) (actual time=0.305..0.305 rows=1365 loops=1)<br />
<span style="padding-left:30px;">Index Cond: (int4pl(((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) = 1230)<br />
<span style="font-size:11pt;font-weight:bold;color:red;">Total runtime: 5.783 ms</span><span style="font-size:10pt;font-weight:bold;"> (previously 286.369 ms)</span></p>
<p style="margin-left:30px;">Yes, the index works and it is faster now.</p>
<div style="font-weight:bold;font-size:15pt;">More Challenges?</div>
<p>Finding who&#8217;s birthday over a period of days is more complex than what we have done on a single day. Specially when the period starts from a day close to end of year to a day next year.<br />
I have a trick to transform a date-of-birth to the form of:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
20000 + (month-part-of-a-date * 100) plus (day-part-of-a-date).</p>
<p>If the whole period is within a single year, then the start and stop date is transformed into:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
20000 + (month-part-of-the-start-date * 100) plus (day-part-of-the-start-date)<br />
20000 + (month-part-of-the-stop-date * 100) plus (day-part-of-the-stop-date)</p>
<p>But, if it crosses year border then it has lower and higher range detection. The lower range detection:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
10000 + (month-part-of-the-start-date * 100) plus (day-part-of-the-start-date)<br />
20000 + (month-part-of-the-stop-date * 100) plus (day-part-of-the-stop-date)</p>
<p style="margin-left:30px;">And for higher range detection:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
20000 + (month-part-of-the-start-date * 100) plus (day-part-of-the-start-date)<br />
30000 + (month-part-of-the-stop-date * 100) plus (day-part-of-the-stop-date)</p>
<p>Give it a try. To query who&#8217;s birthday between 1) Dec 30 2012 and Dec 31 2012, 2) Dec 30 2012 and Jan 01 2013</p>
<p style="margin-left:30px;">Period within single year: Dec 30 2012 and Dec 31 2012.</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
EXPLAIN ANALYZE<br />
SELECT * FROM person <br />
WHERE (<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,dob)::integer*100)), DATE_PART(&#8216;DAY&#8217;,dob)::integer) )<br />
<span style="padding-left:30px;">BETWEEN<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,&#8217;2012-12-30&#8242;::date)::integer*100)),DATE_PART(&#8216;DAY&#8217;,&#8217;2012-12-30&#8242;::date)::integer) )<br />
<span style="padding-left:30px;">AND<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,&#8217;2012-12-31&#8242;::date)::integer*100)),DATE_PART(&#8216;DAY&#8217;,&#8217;2012-12-31&#8242;::date)::integer) )<br />
);</p>
<p style="margin-left:30px;">Result:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
Seq Scan on person  (cost=0.00..32213.00 rows=2500 width=8) (actual time=0.504..611.400 rows=2715 loops=1)<br />
Filter: ((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 21230) AND <br />
(int4pl(int4pl(20000,((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 21231))<br />
<span style="font-size:11pt;font-weight:bold;color:red;">Total runtime: 614.999 ms</span></p>
<p style="margin-left:30px;">Period crosses years: Dec 30 2012 and Jan 01 2013:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
EXPLAIN ANALYZE<br />
SELECT * FROM person<br />
WHERE (<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,dob)::integer*100)), DATE_PART(&#8216;DAY&#8217;,dob)::integer) )<br />
<span style="padding-left:30px;">BETWEEN<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(10000,(DATE_PART(&#8216;MONTH&#8217;,&#8217;2012-12-30&#8242;::date)::integer*100)),DATE_PART(&#8216;DAY&#8217;,&#8217;2012-12-30&#8242;::date)::integer) )<br />
<span style="padding-left:30px;">AND<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,&#8217;2013-01-01&#8242;::date)::integer*100)),DATE_PART(&#8216;DAY&#8217;,&#8217;2013-01-01&#8242;::date)::integer) )<br />
<span style="padding-left:30px;">)<br />
OR<br />
(<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,dob)::integer*100)), DATE_PART(&#8216;DAY&#8217;,dob)::integer) )<br />
<span style="padding-left:30px;">BETWEEN<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,&#8217;2012-12-30&#8242;::date)::integer*100)),DATE_PART(&#8216;DAY&#8217;,&#8217;2012-12-30&#8242;::date)::integer) )<br />
<span style="padding-left:30px;">AND<br />
<span style="padding-left:30px;">( INT4PL( INT4PL(30000,(DATE_PART(&#8216;MONTH&#8217;,&#8217;2013-01-01&#8242;::date)::integer*100)),DATE_PART(&#8216;DAY&#8217;,&#8217;2013-01-01&#8242;::date)::integer) )<br />
);</p>
<p style="margin-left:30px;">Result:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
Seq Scan on person  (cost=0.00..57213.00 rows=4988 width=8) (actual time=1.232..1785.936 rows=4054 loops=1)<br />
Filter: (((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 11230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 20101)) OR<br />
((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 21230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 30101)))<br />
<span style="font-size:11pt;font-weight:bold;color:red;">Total runtime: 1791.009 ms</span></p>
<p>Can it be faster?</p>
<p style="margin-left:30px;">Create index:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
CREATE INDEX &#8220;person_idx_dob2&#8243; ON person USING btree<br />
<span style="padding-left:30px;">INT4PL( INT4PL(20000,(DATE_PART(&#8216;MONTH&#8217;,dob)::integer*100)), DATE_PART(&#8216;DAY&#8217;,dob)::integer) );</p>
<p style="margin-left:30px;">Re-run exactly the same query as above and see how the index works:</p>
<p style="margin-left:30px;">Period within single year: Dec 30 2012 and Dec 31 2012:</p>
<p style="margin-left:30px;">Result:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
Bitmap Heap Scan on person  (cost=49.96..2518.20 rows=2500 width=8) (actual time=0.829..6.969 rows=2715 loops=1)<br />
Recheck Cond: ((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 21230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 21231))<br />
-&gt;  Bitmap Index Scan on person_idx_dob2  (cost=0.00..49.34 rows=2500 width=0) (actual time=0.549..0.549 rows=2715 loops=1)<br />
Index Cond: ((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 21230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 21231))<br />
<span style="font-size:11pt;font-weight:bold;color:red;">Total runtime: 10.649 ms</span><span style="font-size:10pt;font-weight:bold;"> (previously 614.999 ms)</span></p>
<p style="margin-left:30px;">Period crosses years: Dec 30 2012 and Jan 01 2013:</p>
<p style="margin-left:30px;">Result:</p>
<p style="background-color:#f0f0f0;font-family:courier;font-size:9pt;margin-left:30px;">
Bitmap Heap Scan on person  (cost=101.17..2864.17 rows=4988 width=8) (actual time=1.552..9.987 rows=4054 loops=1)<br />
Recheck Cond: (((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 11230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 20101)) OR<br />
((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 21230) AND<br />
<br />(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 30101)))<br />
-&gt;  BitmapOr  (cost=101.17..101.17 rows=5000 width=0) (actual time=1.210..1.210 rows=0 loops=1)<br />
-&gt;  Bitmap Index Scan on person_idx_dob2  (cost=0.00..49.34 rows=2500 width=0) (actual time=0.495..0.495 rows=1339 loops=1)<br />
Index Cond: ((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 11230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 20101))<br />
-&gt;  Bitmap Index Scan on person_idx_dob2  (cost=0.00..49.34 rows=2500 width=0) (actual time=0.710..0.710 rows=2715 loops=1)<br />
Index Cond: ((int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &gt;= 21230) AND<br />
(int4pl(int4pl(20000, ((date_part(&#8216;MONTH&#8217;::text, (dob)::timestamp without time zone))::integer * 100)), (date_part(&#8216;DAY&#8217;::text, (dob)::timestamp without time zone))::integer) &lt;= 30101))<br />
<span style="font-size:11pt;font-weight:bold;color:red;">Total runtime: 15.224 ms</span><span style="font-size:10pt;font-weight:bold;"> (previously 1791.009 ms)</span></p>
<p>What about Feb 29th?</p>
<p style="margin-left:30px;">It must be filtered out if the year of period detection is not a leap year. And I do not have time to show you because I am in a hurry to say:</p>
<div style="font-weight:bold;font-size:15pt;color:blue;text-align:center;">Happy Birthday!</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/194/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/194/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=194&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2012/10/24/whos-birthday/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Consume SOAP Web Service from PostgreSQL User Defined Function in C</title>
		<link>http://abdulyadi.wordpress.com/2012/03/03/consume-soap-web-service-from-postgresql-user-defined-function-in-c/</link>
		<comments>http://abdulyadi.wordpress.com/2012/03/03/consume-soap-web-service-from-postgresql-user-defined-function-in-c/#comments</comments>
		<pubDate>Sat, 03 Mar 2012 19:14:17 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=174</guid>
		<description><![CDATA[In memoriam, Pipit F.Y.H (Oct 30, 1968 &#8211; Jan 15, 2012), we have passed precious moments, once in my lifetime. I have took a look directory of public SOAP web services at http://www.service-repository.com. Then an idea came across my mind to utilize gSOAP toolkit to develop some C code for a User Defined Function in [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=174&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<div>In memoriam, <b>Pipit F.Y.H</b> (Oct 30, 1968 &#8211; Jan 15, 2012), <i>we have passed precious moments, once in my lifetime</i>.</div>
<p><img width="130px" src="http://abdulyadi.files.wordpress.com/2012/03/pipit1.jpg?w=595" alt="f.y.h" /></p>
<div style="margin-top:5mm;">I have took a look directory of public SOAP web services at <a href="http://www.service-repository.com">http://www.service-repository.com</a>. Then an idea came across my mind to utilize <a href="http://www.cs.fsu.edu/~engelen/soap.html">gSOAP</a> toolkit to develop some C code for a User Defined Function in PostgreSQL, so I can consume service provided by <a href="http://www.service-repository.com/service/overview/1376273594">http://www.currencyserver.de/webservice/currencyserverwebservice.asmx?WSDL</a> to get currency rate through SQL command, such as <b><span style="font-family:courier;">SELECT provider, source, dest, rate FROM cy(&#8216;USD&#8217;, &#8216;IDR&#8217;)</span></b>.</div>
<div style="margin-top:5mm;">
<ul>
<li style="margin-top:2mm;">I download <a href="http://www.cs.fsu.edu/~engelen/soap.html">gSOAP</a> on my Ubuntu Laptop. Build and install it into <b><span style="font-family:courier;">/opt/gsoap</span></b> directory.</li>
<li style="margin-top:2mm;">Use gSOAP <b><span style="font-family:courier;">wsdl2h</span></b> to obtain the gSOAP header file <b><span style="font-family:courier;">cy.h</span></b> specification of the web service&#8217;s WSDL document:
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-right:50px;">/opt/gsoap/bin/wsdl2h -c -o cy.h <a href="http://www.currencyserver.de/webservice/currencyserverwebservice.asmx?WSDL" rel="nofollow">http://www.currencyserver.de/webservice/currencyserverwebservice.asmx?WSDL</a></div>
</li>
<li style="margin-top:2mm;">Generate a bunch of source, header, xml and nsmap files based on <b><span style="font-family:courier;">cy.h</span></b> header file:
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-right:50px;">/opt/gsoap/bin/soapcpp2 -1 -c -C -pcy cy.h</div>
</li>
<li style="margin-top:2mm;">Copy <b><span style="font-family:courier;">stdsoap2.c</span></b> from gSOAP source code distribution into current work directory.</li>
<li style="margin-top:2mm;">Create C source code <b><span style="font-family:courier;">cy.c</span></b> for PostgreSQL User Defined Functions with Version 1 Calling Conventions:
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-right:50px;">
#include &lt;postgres.h&gt;<br />
#include &lt;fmgr.h&gt;<br />
#ifdef PG_MODULE_MAGIC<br />
PG_MODULE_MAGIC;<br />
#endif</p>
<p>#include &lt;utils/builtins.h&gt;<br />
#include &lt;funcapi.h&gt;<br />
#include &#8220;cyH.h&#8221;<br />
#include &#8220;CurrencyServerWebServiceSoap.nsmap&#8221;</p>
<p>PG_FUNCTION_INFO_V1(cy);<br />
Datum cy(PG_FUNCTION_ARGS);</p>
<p>void errExit(struct soap* soap);<br />
void cleanExit(struct soap* soap);<br />
struct cyData{ struct soap* soap; char** provList; };</p>
<p>Datum cy(PG_FUNCTION_ARGS) {</p>
<div style="margin-left:25px;">
	struct FuncCallContext* funcctx;<br />
	TupleDesc tupdesc;</p>
<p>	if (SRF_IS_FIRSTCALL()) {</p>
<div style="margin-left:50px;">
		MemoryContext oldcontext;<br />
		funcctx = SRF_FIRSTCALL_INIT();<br />
        	oldcontext = MemoryContextSwitchTo(funcctx-&gt;multi_call_memory_ctx);<br />
		if(get_call_result_type(fcinfo, NULL, &amp;tupdesc) != TYPEFUNC_COMPOSITE) {</p>
<div style="margin-left:75px;">
			ereport(ERROR,</p>
<div style="margin-left:100px;">
				(	errcode(ERRCODE_FEATURE_NOT_SUPPORTED),<br />
					errmsg(&#8220;function returning record called in context &#8220;<br />
		                            &#8220;that cannot accept type record&#8221;)<br />
				)
</div>
<p>			);
</p></div>
<p>		}<br />
		funcctx-&gt;tuple_desc=BlessTupleDesc(tupdesc);<br />
		if(PG_NARGS()!=2)</p>
<div style="margin-left:75px;">
			elog(ERROR, &#8220;argument count must be %d&#8221;, 2);
</div>
<p>		struct cyData* pData=(struct cyData*)palloc(sizeof(struct cyData));<br />
		pData-&gt;soap=soap_new();<br />
		struct _ns1__getProviderList reqProvList;<br />
		struct _ns1__getProviderListResponse respProvList;<br />
		soap_default__ns1__getProviderList(pData-&gt;soap, &amp;reqProvList);<br />
		soap_default__ns1__getProviderListResponse(pData-&gt;soap, &amp;respProvList);<br />
		if(soap_call___ns2__getProviderList(pData-&gt;soap, NULL, NULL, &amp;reqProvList, &amp;respProvList)){</p>
<div style="margin-left:75px;">
			errExit(pData-&gt;soap);
</div>
<p>		}<br />
		char* delim=&#8221;, &#8220;;<br />
		char* ch=strtok(respProvList.getProviderListResult,delim);<br />
		int count=0;<br />
		while(ch){</p>
<div style="margin-left:75px;">
			pData-&gt;provList= count==0 ? (char**)palloc(++count*sizeof(char*))<br />
				: (char**)repalloc(pData-&gt;provList, ++count*sizeof(char*));<br />
			pData-&gt;provList[count-1]=pstrdup(ch);<br />
			ch=strtok(NULL,delim);
</div>
<p>		}<br />
		funcctx-&gt;max_calls=count;<br />
		funcctx-&gt;user_fctx=(void*)pData;</p>
<p>        	MemoryContextSwitchTo(oldcontext);
</div>
<p>	}</p>
<p>	funcctx = SRF_PERCALL_SETUP();</p>
<p>	if (funcctx-&gt;call_cntr max_calls) {</p>
<div style="margin-left:50px;">
		Datum result;<br />
		HeapTuple tuple;<br />
		bool isnull[]={false,false,false,false};</p>
<p>		struct cyData* pData=(struct cyData*)funcctx-&gt;user_fctx;</p>
<p>		struct _ns1__getCurrencyValue req;<br />
		struct _ns1__getCurrencyValueResponse resp;<br />
		soap_default__ns1__getCurrencyValue(pData-&gt;soap, &amp;req);</p>
<p>		req.provider=pData-&gt;provList[funcctx-&gt;call_cntr];<br />
		req.srcCurrency=TextDatumGetCString(PG_GETARG_DATUM(0));<br />
		req.dstCurrency=TextDatumGetCString(PG_GETARG_DATUM(1));<br />
		if(soap_call___ns2__getCurrencyValue(pData-&gt;soap, NULL, NULL, &amp;req, &amp;resp)){</p>
<div style="margin-left:75px;">
			errExit(pData-&gt;soap);
</div>
<p>		}<br />
		Datum values[]={</p>
<div style="margin-left:75px;">
			DirectFunctionCall1(textin, CStringGetDatum(pData-&gt;provList[funcctx-&gt;call_cntr])),<br />
			PG_GETARG_DATUM(0),<br />
			PG_GETARG_DATUM(1),<br />
			DirectFunctionCall1(float8_numeric, Float8GetDatum(resp.getCurrencyValueResult))
</div>
<p>		};</p>
<p>		tuple=heap_form_tuple(funcctx-&gt;tuple_desc, values, isnull);<br />
		result = HeapTupleGetDatum(tuple);</p>
<p>		SRF_RETURN_NEXT(funcctx, result);
</p></div>
<p>	} else {</p>
<div style="margin-left:50px;">
		struct cyData* pData=(struct cyData*)funcctx-&gt;user_fctx;<br />
		cleanExit(pData-&gt;soap);<br />
		SRF_RETURN_DONE(funcctx);
</div>
<p>	}
</div>
<p>}</p>
<p>void errExit(struct soap* soap) {</p>
<div style="margin-left:50px;">
	char buf[201]=&#8221;";<br />
	soap_sprint_fault(soap, buf, 200);<br />
	cleanExit(soap);<br />
	elog(ERROR, &#8220;%s&#8221;, buf);
</div>
<p>}</p>
<p>void cleanExit(struct soap* soap) {</p>
<div style="margin-left:50px;">
	soap_end(soap);<br />
	soap_free(soap);
</div>
<p>}
</div>
</li>
<li style="margin-top:2mm;">Create SQL skeleton for User Defined Functions <b><span style="font-family:courier;">cy.sql.in</span></b>:
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-right:50px;">
CREATE OR REPLACE FUNCTION cy(OUT provider text, INOUT source text, INOUT dest text, OUT rate numeric)<br />
RETURNS SETOF record<br />
AS &#8216;MODULE_PATHNAME&#8217;, &#8216;cy&#8217;  LANGUAGE C IMMUTABLE STRICT;<br />
GRANT EXECUTE ON FUNCTION cy(text, text) TO public;
</div>
</li>
<li style="margin-top:2mm;">Create <b><span style="font-family:courier;">Makefile</span></b> to comply with PostgreSQL build infrastructure for extensions (called PGXS):
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-right:50px;">
MODULE_big = cy<br />
OBJS = stdsoap2.o cyC.o cyClient.o cy.o<br />
DATA_built = cy.sql<br />
PG_CONFIG = /opt/pgsql/bin/pg_config<br />
PG_CPPFLAGS = -I/opt/gsoap/include<br />
PGXS := $(shell $(PG_CONFIG) &#8211;pgxs)<br />
include $(PGXS)
</div>
<p>Plase take note that my PostgreSQL resides in <b><span style="font-family:courier;">/opt/pgsql</span></b>.
</li>
<li style="margin-top:2mm;">Build and install everything:
<div style="background-color:#505050;color:white;font-family:monospace;font-size:10pt;margin-right:50px;">
abdul@mylaptop:~/wsdl/cy$ make<br />
abdul@mylaptop:~/wsdl/cy$ sudo make install<br />
abdul@mylaptop:~/wsdl/cy$ /opt/pgsql/bin/psql -U admin -h localhost -p 5432 -d test -f cy.sql
</div>
</li>
<li style="margin-top:2mm;">Login to database server:
<div style="background-color:#505050;color:white;font-family:monospace;font-size:10pt;margin-right:50px;">
abdul@mylaptop:~/wsdl/cy$ /opt/pgsql/bin/psql -U slony -h localhost -p 5432 test<br />
Password for user slony: <br />
psql (9.0.4)<br />
Type &#8220;help&#8221; for help.</p>
<p>test=#
</p></div>
</li>
<li style="margin-top:2mm;">Check my currency rate&#8230;
<div style="background-color:#505050;color:white;font-family:monospace;font-size:10pt;margin-right:50px;">
test=# SELECT * FROM cy(&#8216;USD&#8217;,'IDR&#8217;);<br />
 provider | source | dest |    rate    <br />
&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8211;+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;<br />
 3        | USD    | IDR  | 9094.34819<br />
 4        | USD    | IDR  |     9087.5<br />
 AVERAGE  | USD    | IDR  | 9090.92409<br />
(3 rows)</p>
<p>test=# SELECT * FROM cy(&#8216;EUR&#8217;,'IDR&#8217;);<br />
 provider | source | dest |       rate   <br /> <br />
&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8211;+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
 3        | EUR    | IDR  | 12020.0213983611<br />
 4        | EUR    | IDR  | 11993.8496462887<br />
 AVERAGE  | EUR    | IDR  | 12006.9261827403<br />
(3 rows)</p>
<p>test=# SELECT * FROM cy(&#8216;SGD&#8217;,'IDR&#8217;);<br />
 provider | source | dest |       rate      <br /> <br />
&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8211;+&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;<br />
 3        | SGD    | IDR  | 7272.91848469339<br />
 4        | SGD    | IDR  | 7257.45911065679<br />
 AVERAGE  | SGD    | IDR  | 7265.18348117957<br />
(3 rows)</p>
<p>test=#
</p></div>
<div style="margin-top:2mm;font-size:14pt;font-weight:bold;">Hi, it comes from the Public Web Service thousands miles away from my house, not from my database.</div>
</li>
</ul>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/174/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/174/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=174&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2012/03/03/consume-soap-web-service-from-postgresql-user-defined-function-in-c/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>

		<media:content url="http://abdulyadi.files.wordpress.com/2012/03/pipit1.jpg" medium="image">
			<media:title type="html">f.y.h</media:title>
		</media:content>
	</item>
		<item>
		<title>Detect Inactive Slony Node</title>
		<link>http://abdulyadi.wordpress.com/2011/07/18/detect-inactive-slony-node/</link>
		<comments>http://abdulyadi.wordpress.com/2011/07/18/detect-inactive-slony-node/#comments</comments>
		<pubDate>Mon, 18 Jul 2011 07:01:53 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=162</guid>
		<description><![CDATA[One concern in implementing Slony as PostgreSQL Replication System is that table sl_event easily growing to a huge number of record. So, I keep monitor its size on weekly basis. Its size ever reaches more than a million record. After doing some troubleshoot, I have found that it is caused by some inactive replication node [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=162&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>One concern in implementing Slony as PostgreSQL Replication System is that table <strong>sl_event</strong> easily growing to a huge number of record. So, I keep monitor its size on weekly basis. Its size ever reaches more than a million record.</p>
<p>After doing some troubleshoot, I have found that it is caused by some inactive replication node which does not confirm the changes message conveyed by the event. By re-activating slony daemon on the nodes, the problem goes away.</p>
<p>How to find out which nodes inactive? This is my query (assuimng the slony cluster name is <strong>clstr</strong>):</p>
<div style="font-family:courier;background-color:#efefef;">
SELECT t.con_received, t.ts FROM (<br />
    SELECT con_received, MAX(con_timestamp) ts<br />
    FROM    <strong>_clstr.</strong>sl_confirm GROUP BY con_received<br />
) t ORDER BY t.ts;
</div>
<p>
Following is example of the query outcome:<br />
 con_received |             ts<br />
&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
           24 | 2011-07-11 08:49:18.004292<br />
           26 | 2011-07-18 05:59:33.483955<br />
           30 | 2011-07-18 10:31:55.235895<br />
           31 | 2011-07-18 12:26:35.889352<br />
           22 | 2011-07-18 12:27:02.932156<br />
           21 | 2011-07-18 12:27:21.21836<br />
           15 | 2011-07-18 12:27:23.298656<br />
           18 | 2011-07-18 12:27:23.701799<br />
           17 | 2011-07-18 12:27:27.052192<br />
           28 | 2011-07-18 13:43:19.826342<br />
           11 | 2011-07-18 13:58:25.891667<br />
            1 | 2011-07-18 13:58:37.566528<br />
           29 | 2011-07-18 13:58:47.321221<br />
           16 | 2011-07-18 14:01:08.206147<br />
           13 | 2011-07-18 14:01:10.92797<br />
           19 | 2011-07-18 14:02:02.476146<br />
           14 | 2011-07-18 14:02:02.51104<br />
           20 | 2011-07-18 14:02:05.63391<br />
           27 | 2011-07-18 14:14:55.750242<br />
<br />
It tells us that node 24 has been inactive for 7 days relative to other nodes.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/162/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/162/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=162&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2011/07/18/detect-inactive-slony-node/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Transfer Binary from Photo File to Database Table</title>
		<link>http://abdulyadi.wordpress.com/2010/12/25/transfer-binary-from-photo-file-to-database-table/</link>
		<comments>http://abdulyadi.wordpress.com/2010/12/25/transfer-binary-from-photo-file-to-database-table/#comments</comments>
		<pubDate>Sat, 25 Dec 2010 11:11:02 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=144</guid>
		<description><![CDATA[In many web application, personal photo is saved as [*.jpg] file in a folder in server&#8217;s disk. The relation with personal ID in database is established by set the filename accordingly in format: nnnnn.jpg, e.g: 00001.jpg, 00002.jpg and so on. Once upon a time, I was in charge to move content of photo file into [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=144&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<div>In many web application, personal photo is saved as [*.jpg] file in a folder in server&#8217;s disk. The relation with personal ID in database is established by set the filename accordingly in format: <b>nnnnn.jpg</b>, e.g: <b>00001.jpg</b>, <b>00002.jpg</b> and so on.</div>
<div style="margin-top:5px;">Once upon a time, I was in charge to move content of photo file into database&#8217;s field, integrated with personal identity table. All works in Linux environment and PostgreSQL 9.0.</div>
<div style="margin-top:5px;">I want to share the story&#8230;.</div>
<div style="margin-top:5px;">Original setting: photo file is saved in folder: <b>/home/webuser/photo/</b> and person table resides in <b>persondb</b> database with DDL as follows:</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">
<div>CREATE TABLE person</div>
<div>(</div>
<div style="margin-left:2em;">id serial NOT NULL,</div>
<div style="margin-left:2em;">fullname text NOT NULL,</div>
<div style="margin-left:2em;">addres text NOT NULL,</div>
<div style="margin-left:2em;">CONSTRAINT &#8220;person: id must be unique&#8221; PRIMARY KEY (id)</div>
<div>) WITH (OIDS=FALSE);</div>
</p></div>
<p>	The table has been populated with hundreds of person records.
</p></div>
<div style="margin-top:10px;"><b>Part 1: Alter Table</b></div>
<div>Add a field to store photo bytearray:</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">ALTER TABLE person ADD COLUMN photo bytea;</div>
</div>
<div style="margin-top:10px;"><b>Part 2: Create C Source Code</b></div>
<div>Create <b>person.c</b>:</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">
<div>#include &lt;postgres.h&gt;</div>
<div>#include &lt;fmgr.h&gt;</div>
<div>#ifdef PG_MODULE_MAGIC</div>
<div style="margin-left:2em;">PG_MODULE_MAGIC;</div>
<div>#endif</div>
<div>#include &lt;lib/stringinfo.h&gt;</div>
<div>#include &lt;executor/spi.h&gt;</div>
<div>#include &lt;catalog/pg_type.h&gt;</div>
<div>#include &lt;utils/builtins.h&gt;</div>
<div>#include &lt;utils/bytea.h&gt;</div>
<div>#include &lt;catalog/pg_type.h&gt;</div>
<p></p>
<div>PG_FUNCTION_INFO_V1(person_photo);</div>
<div>Datum person_photo(PG_FUNCTION_ARGS);</div>
<p></p>
<div>Datum</div>
<div>person_photo(PG_FUNCTION_ARGS)</div>
<div>{</div>
<div style="margin-left:2em;">int32 personId;</div>
<div style="margin-left:2em;">StringInfoData photoFile;</div>
<div style="margin-left:2em;">StringInfoData photoBytea;</div>
<div style="margin-left:2em;">const char* PHOTO_PATH=&#8221;/home/webuser/photo/&#8221;;</div>
<div style="margin-left:2em;">const char* PHOTO_EXT=&#8221;jpg&#8221;;</div>
<div style="margin-left:2em;">FILE* f;</div>
<div style="margin-left:2em;">const size_t BUFFER_SIZE=5*1024;</div>
<div style="margin-left:2em;">char buf[BUFFER_SIZE];</div>
<div style="margin-left:2em;">size_t byteReadCount;</div>
<div style="margin-left:2em;">const int32 SQL_PARAM_COUNT=2;</div>
<div style="margin-left:2em;">Oid argTypes[SQL_PARAM_COUNT];</div>
<div style="margin-left:2em;">Datum vals[SQL_PARAM_COUNT];</div>
<p>
		////get function argument:BEGIN</p>
<div style="margin-left:2em;">if(PG_ARGISNULL(0)) {</div>
<div style="margin-left:4em;">elog(ERROR,&#8221;person id can not be NULL&#8221;);</div>
<div style="margin-left:2em;">i}</div>
<div style="margin-left:2em;">personId=PG_GETARG_INT32(0);</div>
<p>		////get function argument:END</p>
<p>		////read photo file:BEGIN			</p>
<div style="margin-left:2em;">photoBytea.data=0;</div>
<div style="margin-left:2em;">photoBytea.len=0;</div>
<div style="margin-left:2em;">initStringInfo(&amp;photoFile);</div>
<div style="margin-left:2em;">appendStringInfo(&amp;photoFile, &#8220;%s%05d.%s&#8221;, PHOTO_PATH, personId, PHOTO_EXT);</div>
<div style="margin-left:2em;">f=fopen(photoFile.data, &#8220;rb&#8221;);//open photo file</div>
<div style="margin-left:2em;">pfree(photoFile.data);</div>
<div style="margin-left:2em;">if(f){</div>
<div style="margin-left:4em;">initStringInfo(&amp;photoBytea);</div>
<div style="margin-left:4em;">while(!feof(f)){//keep reading until end of file</div>
<div style="margin-left:6em;">byteReadCount=fread(buf, 1, BUFFER_SIZE, f);</div>
<div style="margin-left:6em;">appendBinaryStringInfo(&amp;photoBytea, buf, byteReadCount);</div>
<div style="margin-left:4em;">}</div>
<div style="margin-left:4em;">fclose(f);</div>
<div style="margin-left:2em;">} else {</div>
<div style="margin-left:4em;">elog(NOTICE, &#8220;person with id %d does not have photo&#8221;, personId);</div>
<div style="margin-left:2em;">}</div>
<p>		////read photo file:END</p>
<p>		////save to database:BEGIN</p>
<div style="margin-left:2em;">if(photoBytea.len){</div>
<div style="margin-left:4em;">SPI_connect();</div>
<p></p>
<div style="margin-left:4em;">argTypes[0]=INT4OID;</div>
<div style="margin-left:4em;">argTypes[1]=BYTEAOID;</div>
<div style="margin-left:4em;">vals[0]=Int32GetDatum(personId);</div>
<div style="margin-left:4em;">vals[1]=DirectFunctionCall1(bytearecv, PointerGetDatum(&amp;photoBytea));</div>
<p></p>
<div style="margin-left:4em;">SPI_execute_with_args(&#8220;UPDATE person SET photo=$2 WHERE id=$1&#8243;, </div>
<div style="margin-left:6em;">SQL_PARAM_COUNT, argTypes, vals, NULL, FALSE, 1);</div>
<p></p>
<div style="margin-left:4em;">SPI_finish();</div>
<div style="margin-left:2em;">}</div>
<div style="margin-left:2em;">if(photoBytea.data){</div>
<div style="margin-left:4em;">pfree(photoBytea.data);</div>
<div style="margin-left:2em;">}</div>
<p>		////save to database:END</p>
<div style="margin-left:2em;">PG_RETURN_VOID();</div>
<div>}</div>
</p></div>
</div>
<div style="margin-top:10px;"><b>Part 3: Create SQL to Install Our Custom Library</b></div>
<div>Create <b>person.sql.in</b> in the same folder as <b>person.c</b>:</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">
<div>CREATE OR REPLACE FUNCTION person_photo(person_id integer)</div>
<div>RETURNS VOID</div>
<div>AS &#8216;MODULE_PATHNAME&#8217; LANGUAGE C VOLATILE;</div>
</p></div>
</div>
<div style="margin-top:10px;"><b>Part 4: Create Makefile</b></div>
<div>Create <b>Makefile</b> in the same folder as <b>person.c</b>:</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">
<div>MODULE_big = person</div>
<div>OBJS = person.o</div>
<div>DATA_built = person.sql</div>
<p></p>
<div>PG_CPPFLAGS := $(shell pg_config &#8211;includedir-server)</div>
<p></p>
<div>PGXS := $(shell pg_config &#8211;pgxs)</div>
<div>include $(PGXS)</div>
</p></div>
</div>
<div style="margin-top:10px;"><b>Part 5: Compile and Install</b></div>
<div>In the same folder as <b>Makefile</b>, run command <b>make</b> then <b>make install</b>. Make sure we have sufficient privilege to create file in PostgreSQL contrib and library folder. If everything goes fine then we will have two files:</p>
<ol>
<li>SQL file <b>person.sql</b> in PostgreSQL contrib directory.</li>
<li>Library file <b>person.so</b> in PostgreSQL library directory.</li>
</ol>
</div>
<div style="margin-top:10px;"><b>Part 6: Install Stored Procedure</b></div>
<div>Assuming we are in the same folder as <b>person.sql</b> and want to install stored procedure in <b>persondb</b> database (where table <b>person</b> exists) at host <b>server1</b>:</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">
<div>psql -U postgres -h server1 -f person.sql -d persondb</div>
</p></div>
</div>
<div style="margin-top:10px;"><b>Part 7: Move Photo From File to Table</b></div>
<div>All preparation has been set. It is time to login to PostgreSQL server and run the stored procedure (make sure folder <b>/home/webuser/photo/</b> is accessible by postgres user):</p>
<div style="font-family:courier;font-size:9pt;background-color:#f0f0f0;">
<div>psql -U postgres -h server1 persondb</div>
<div>Password for user postgres:<b>[your password]</b></div>
<div>postgres=#<b>SELECT person_photo(id) FROM person;</b></div>
</p></div>
<p>	Wait a moment, let PostgreSQL read photo files and store the binaries into field <b>photo</b>.
</div>
<div style="margin-top:10px;">My story ends&#8230;.</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/144/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/144/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=144&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2010/12/25/transfer-binary-from-photo-file-to-database-table/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>PgPool II 3.0: bug fixes for md5 authentication</title>
		<link>http://abdulyadi.wordpress.com/2010/09/25/pgpool-ii-3-0-bug-fixes/</link>
		<comments>http://abdulyadi.wordpress.com/2010/09/25/pgpool-ii-3-0-bug-fixes/#comments</comments>
		<pubDate>Sat, 25 Sep 2010 07:39:12 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=119</guid>
		<description><![CDATA[I have problem with PgPool II 3.0. I have downloaded the source code from http://pgfoundry.org/projects/pgpool. Extract and compile it successfully. Configure it just to have connection pooling enabled (other features: Replication, LoadBalance, Parallel Query are disabled). But, I can not connect to PostgreSQL 9.0 via PgPool port at 9999 with authentication mode set to md5 [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=119&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<div style="font-size:8.5pt;">
<div>I have problem with PgPool II 3.0. I have downloaded the source code from <a href="http://pgfoundry.org/projects/pgpool">http://pgfoundry.org/projects/pgpool</a>. Extract and compile it successfully. Configure it just to have connection pooling enabled (other features: Replication, LoadBalance, Parallel Query are disabled). But, I can not connect to PostgreSQL 9.0 via PgPool port at 9999 with authentication mode set to md5 in pg_hba.conf (pool_hba.conf is disabled).</div>
<p><div>After take some time to trace the source code, I have found bug in file <span style="font-family:courier;">pool_auth.c</span>. Inside function:</p>
<div style="font-family:courier;">static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)</div>
<div>variable <span style="font-family:courier;">int size</span> is declared but it never have the length of password.</div>
<p><div>4 steps to fix the problem:</div>
<ol>
<li>Modify forward declaration of function <span style="font-family:courier;">int read_password_packet(&#8230;)</span>, add <span style="font-family:courier;">int *pwdSize</span> as the fourth argument:
<div style="font-family:courier;background-color:#f0f0f0;">
<div>//static int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, 	char *password);</div>
<div style="color:red;">static int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, 	char *password, <b>int *pwdSize</b>);</div>
</p></div>
<li>Modify function body of function <span style="font-family:courier;">int read_password_packet(&#8230;)</span>. Watch that *pwdSize has the password length at the end of the function body:
<div style="font-family:courier;background-color:#f0f0f0;">
<div>/*</div>
<div>* Read password packet from frontend</div>
<div>*/</div>
<div>//static int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, 	char *password)</div>
<div style="color:red;">static int read_password_packet(POOL_CONNECTION *frontend, int protoMajor, 	char *password, <b>int *pwdSize</b>)</div>
<div>{</div>
<div>&nbsp;&nbsp;int size;</div>
<div>&nbsp;&nbsp;/* Read password packet */</div>
<div>&nbsp;&nbsp;if (protoMajor == PROTO_MAJOR_V2)</div>
<div>&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;if (pool_read(frontend, &amp;size, sizeof(size)))</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool_error(&#8220;read_password_packet: failed to read password packet size&#8221;);</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;else</div>
<div>&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;char k;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;if (pool_read(frontend, &amp;k, sizeof(k)))</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool_debug(&#8220;read_password_packet_password: failed to read password packet \&#8221;p\&#8221;");</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;if (k != &#8216;p&#8217;)</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool_error(&#8220;read_password_packet_password: password packet does not start with \&#8221;p\&#8221;");</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;if (pool_read(frontend, &amp;size, sizeof(size)))</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool_error(&#8220;read_password_packet_password: failed to read password packet size&#8221;);</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;if (pool_read(frontend, password, ntohl(size) &#8211; 4))</div>
<div>&nbsp;&nbsp;{</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pool_error(&#8220;read_password_packet: failed to read password (size: %d)&#8221;, ntohl(size) &#8211; 4);</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return -1;</div>
<div>&nbsp;&nbsp;}</div>
<div>&nbsp;&nbsp;<span style="font-weight:bold;color:red;">*pwdSize=size;</span> //now *pwdSize has password length</div>
<div>&nbsp;&nbsp;return 0;</div>
<div>}</div>
</p></div>
<li>Inside function
<div style="font-family:courier;">static int do_md5(POOL_CONNECTION *backend, POOL_CONNECTION *frontend, int reauth, int protoMajor)</div>
<div>add <span style="font-family:courier;">&amp;size</span> as fourth argument to every <span style="font-family:courier;">read_password_packet</span> function call, for example:</p>
<div style="font-family:courier;">read_password_packet(frontend, protoMajor, password, <span style="font-weight:bold;color:red;">&amp;size</span>)</div>
<li>Recompile and reinstall pgpool project.
</ol>
<p>Done. Now. I can login to PostgreSQL 9.0 smoothly through PgPool port: 9999.
</p></div>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/119/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/119/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=119&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2010/09/25/pgpool-ii-3-0-bug-fixes/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>dbi-link: fix error on insert/update/delete into/from remote mysql table</title>
		<link>http://abdulyadi.wordpress.com/2010/07/28/dbi-link-fix-error-on-insertupdatedelete-intofrom-remote-mysql-table/</link>
		<comments>http://abdulyadi.wordpress.com/2010/07/28/dbi-link-fix-error-on-insertupdatedelete-intofrom-remote-mysql-table/#comments</comments>
		<pubDate>Wed, 28 Jul 2010 02:33:58 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=112</guid>
		<description><![CDATA[I have installed dbi-link version 2.0.0 into my PostgreSQL 8.4 environment. The purpose is to query or modify remote mysql table from within postgresql user-defined-function. And whenever I try to insert/update/delete record into/from remote mysql table, I consistently get error message: ERROR: error from Perl function &#8220;shadow_trigger_func&#8221;: Can&#8217;t call method &#8220;quote&#8221; on an undefined value [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=112&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<div style="font-family:arial;font-size:10pt;">I have installed dbi-link version 2.0.0 into my PostgreSQL 8.4 environment. The purpose is to query or modify remote mysql table from within postgresql user-defined-function. And whenever I try to insert/update/delete record into/from remote mysql table, I consistently get error message:
</div>
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-top:.5em;">
ERROR: error from Perl function &#8220;shadow_trigger_func&#8221;: Can&#8217;t call method &#8220;quote&#8221; on an undefined value at line 61
</div>
<div style="font-family:arial;font-size:10pt;margin-top:.5em;">
So i go to the mentioned function and found out sub functions: <span style="font-family:courier;font-size:11pt;font-weight:bold;">make_pairs</span>, <span style="font-family:courier;font-weight:bold;">do_insert</span>, <span style="font-family:courier;font-weight:bold;">do_update</span> and <span style="font-family:courier;font-weight:bold;">do_delete</span> try to access variables: <span style="font-family:courier;font-weight:bold;">$data_source_id</span> and <span style="font-family:courier;font-weight:bold;">$table</span> which are declared locally in main function.
</div>
<div style="font-family:arial;font-size:10pt;margin-top:.5em;">
Knowing that problem, I have modified parameter passing as follows:
</div>
<p><div style="font-family:arial;font-size:10pt;margin-top:.5em;">
Within <b>main</b> function:
</div>
<div style="background-color:#f0f0f0;font-family:courier;font-size:10pt;margin-top:.5em;">
&#8230;<br />
if ($iud-&gt;{ $_TD-&gt;{new}{iud_action} }) {<br />
&nbsp;&nbsp;&nbsp;$iud-&gt;{ $_TD-&gt;{new}{iud_action} }-&gt;({<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;payload =&gt; $_TD-&gt;{new},<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b><span style="color:red;">tbl =&gt; $table,</span></b><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b><span style="color:red;">source_id =&gt; $data_source_id</span></b><br />
&nbsp;&nbsp;&nbsp;});<br />
}<br />
else {<br />
&nbsp;&nbsp;&nbsp;die &#8220;Trigger event was $_TD-&gt;{new}{iud_action}&lt;, but should have been one of I, U or D!&quot;<br />
}<br />
&#8230;
</div>
<div style="font-family:arial;font-size:10pt;margin-top:.5em;">
And inside sub functions: modify <b>$table</b> and <b>$data_source_id</b> into <b>$params-&gt;{tbl}</b> and <b>$params-&gt;{source_id}</b>, respectively.
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/112/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/112/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=112&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2010/07/28/dbi-link-fix-error-on-insertupdatedelete-intofrom-remote-mysql-table/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>Integrated Networks for Educational Research</title>
		<link>http://abdulyadi.wordpress.com/2010/05/24/integrated-networks-for-eduactional-research/</link>
		<comments>http://abdulyadi.wordpress.com/2010/05/24/integrated-networks-for-eduactional-research/#comments</comments>
		<pubDate>Mon, 24 May 2010 15:13:31 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=106</guid>
		<description><![CDATA[Linux Community at Batam, Indonesia has launched a web application dedicated for educational research by Indonesian teachers. We call it INFER: Integrated Networks For Educational Research (http://infer.gelora-batam.org). It is a Rich Internet Application developed using Ext-GWT, deployed on Tomcat5 and backed by PostgreSQL 8.4 (for its CTE feature). Statistic Probability Density function is calculated within [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=106&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>Linux Community at Batam, Indonesia has launched a web application dedicated for educational research by Indonesian teachers. We call it INFER: Integrated Networks For Educational Research (<a href="http://infer.gelora-batam.org" rel="nofollow">http://infer.gelora-batam.org</a>). It is a Rich Internet Application developed using Ext-GWT, deployed on Tomcat5 and backed by <strong>PostgreSQL 8.4</strong> (for its CTE feature). Statistic Probability Density function is calculated within stored procedure written in C, to wrap library provided by GSL (GNU Scientific Library).</p>
<p>At this moment, the service provides analytical tools for: Correlation and One way Analyses Of Variance (ANOVA) study, as well as Exams Item Validation tool (as online alternative for ITEMAN.EXE by Assessments Systems Corporation).</p>
<p>The project will be continually enhanced by Batam Linux Community for more analytical tools.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/106/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/106/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=106&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2010/05/24/integrated-networks-for-eduactional-research/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
		<item>
		<title>PLSQL for Curve Smoothing  </title>
		<link>http://abdulyadi.wordpress.com/2009/05/16/plsql-for-curve-smoothing/</link>
		<comments>http://abdulyadi.wordpress.com/2009/05/16/plsql-for-curve-smoothing/#comments</comments>
		<pubDate>Sat, 16 May 2009 03:39:19 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=62</guid>
		<description><![CDATA[In an engineering project, I have been assigned to a task constructing smooth curve for given sets of sample points. This is accomplished by implementing Cubic Splines and Thomas algorithm to solve linear algebraic equation. So, I write PLSQL stored procedure as follows: CREATE OR REPLACE FUNCTION spline( IN x_arr numeric[], IN y_arr numeric[], IN [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=62&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>In an engineering project, I have been assigned to a task constructing smooth curve for given sets of sample points. This is accomplished by implementing Cubic Splines and Thomas algorithm to solve linear algebraic equation. So, I write PLSQL stored procedure as follows:</p>
<div style="font-family:courier;font-size:8pt;background-color:#E0E0E0;">
CREATE OR REPLACE FUNCTION spline(<br />
	IN x_arr numeric[], IN y_arr numeric[], IN resolution numeric,<br />
	OUT xs numeric, OUT ys numeric)<br />
  RETURNS SETOF record AS<br />
$BODY$<br />
DECLARE<br />
&nbsp;&nbsp;x numeric[];<br />
&nbsp;&nbsp;y numeric[];<br />
&nbsp;&nbsp;e numeric[] DEFAULT &#8216;{}&#8217;::numeric[];<br />
&nbsp;&nbsp;f numeric[] DEFAULT &#8216;{}&#8217;::numeric[];<br />
&nbsp;&nbsp;g numeric[] DEFAULT &#8216;{}&#8217;::numeric[];<br />
&nbsp;&nbsp;r numeric[] DEFAULT &#8216;{}&#8217;::numeric[];<br />
&nbsp;&nbsp;f2 numeric[] DEFAULT &#8216;{}&#8217;::numeric[];<br />
&nbsp;&nbsp;count integer;<br />
&nbsp;&nbsp;i integer;<br />
&nbsp;&nbsp;j integer;<br />
&nbsp;&nbsp;idx integer;<br />
&nbsp;&nbsp;tmp numeric;<br />
BEGIN<br />
&nbsp;&nbsp;x:=x_arr;<br />
&nbsp;&nbsp;y:=y_arr;<br />
&nbsp;&nbsp;count:=ARRAY_UPPER(x,1);<br />
&nbsp;&nbsp;IF count&lt;3 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION &#8216;sample size must be &gt;=3&#8242;;<br />
&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;IF ARRAY_UPPER(y,1)&lt;&gt;count THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION &#8216;x and y array size must be identical&#8217;;<br />
&nbsp;&nbsp;END IF;</p>
<p>&#8212;&#8212;&#8211;sort x, ascendingly:<br />
&nbsp;&nbsp;FOR i IN 1..count-1 LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;idx:=i+1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR j IN i+2..count LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IF x[j]&lt;x[idx] THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;idx:=j;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;END LOOP;<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF x[idx]=x[i] THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE EXCEPTION &#8216;x values must be unique&#8217;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;ELSIF x[idx]&lt;x[i] THEN &#8211;swap<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tmp=x[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x[i]=x[idx];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x[idx]=tmp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tmp=y[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y[i]=y[idx];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;y[idx]=tmp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;END LOOP;</p>
<p>&#8212;&#8212;&#8211;prepare variables for Thomas algorithm<br />
&nbsp;&nbsp;FOR i IN 1..count LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF i=1 OR i=count THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e:= e || 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f:= f || 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g:= g || 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;r:= r || 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2:=f2 || 0.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CONTINUE;<br />
&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;e:= e || x[i] &#8211; x[i-1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;f:= f || 2*(x[i+1]-x[i-1]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;g:= g || x[i+1] &#8211; x[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;r:= r || ( (6/(x[i+1]-x[i])) * (y[i+1]-y[i]) )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ ( (6/(x[i]-x[i-1])) * (y[i-1]-y[i]) );<br />
&nbsp;&nbsp;&nbsp;&nbsp;f2:=f2 || 0.0;<br />
&nbsp;&nbsp;END LOOP;</p>
<p>&#8212;&#8212;&#8211;decomposition<br />
&nbsp;&nbsp;FOR i IN 2..count LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF f[i-1]&lt;&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e[i]:=e[i]/f[i-1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;&nbsp;&nbsp;f[i]:=f[i]-(e[i]*g[i-1]);<br />
&nbsp;&nbsp;END LOOP;</p>
<p>&#8212;&#8212;&#8211;forward substitution<br />
&nbsp;&nbsp;FOR i IN 2..count LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;r[i]:=r[i]-(e[i]*r[i-1]);<br />
&nbsp;&nbsp;END LOOP;</p>
<p>&#8212;&#8212;&#8211;backward substitution<br />
&nbsp;&nbsp;FOR i IN REVERSE count-1..1 LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;IF f[i]&lt;&gt;0 THEN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;f2[i]:=(r[i] &#8211; (g[i]*f2[i+1])) / f[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;END IF;<br />
&nbsp;&nbsp;END LOOP;</p>
<p>&#8212;&#8212;&#8211;do interpolation<br />
&nbsp;&nbsp;FOR i IN 2..count LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;xs:=x[i-1]-resolution;<br />
&nbsp;&nbsp;&nbsp;&nbsp;LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xs:=xs+resolution;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXIT WHEN i=count AND xs&gt;x[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXIT WHEN i=x[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ys:= ( (f2[i-1] * (x[i]-xs)^3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+ (f2[i] * (xs-x[i-1])^3)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) / (6*(x[i]-x[i-1]));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ys:= ys +  (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(y[i-1]/(x[i]-x[i-1])) -<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(f2[i-1]*(x[i]-x[i-1])/6)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) * (x[i]-xs);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ys:= ys + (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(y[i]/(x[i]-x[i-1])) -<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(f2[i]*(x[i]-x[i-1])/6)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;) * (xs-x[i-1]);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RETURN NEXT;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;EXIT WHEN xs&gt;=x[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;END LOOP;<br />
&nbsp;&nbsp;END LOOP;</p>
<p>&nbsp;&nbsp;RETURN;<br />
END;<br />
$BODY$<br />
  LANGUAGE &#8216;plpgsql&#8217; IMMUTABLE STRICT;
</p></div>
<p>The stored procedure takes 3 input arguments and 2 outs. <b>x_arr</b> and <b> y_arr</b> are sample points&#8217; <b>x</b> and <b>y</b>. With <b>resolution</b>, you can determine the resolution of smoothed curve&#8217;s <b>x</b>.</p>
<p>Output arguments: <b>xs</b> and <b>ys</b> contain the set of <b>x</b> and <b>y</b> of smoothed curve, respectively.</p>
<p>Let us use the function. At first, we have sample points:</p>
<table width="60%" border="0">
<tr>
<th width="10%" align="center">#</th>
<th width="45%" align="center">x</th>
<th width="45%" align="center">y</th>
</tr>
<tr>
<td align="center">1</td>
<td align="center">3.3</td>
<td align="center">1.2</td>
</tr>
<tr>
<td align="center">2</td>
<td align="center">4.2</td>
<td align="center">-1.1</td>
</tr>
<tr>
<td align="center">3</td>
<td align="center">6.8</td>
<td align="center">1.5</td>
</tr>
<tr>
<td align="center">4</td>
<td align="center">8.2</td>
<td align="center">1.2</td>
</tr>
<tr>
<td align="center">5</td>
<td align="center">10.2</td>
<td align="center">2.5</td>
</tr>
</table>
<p>Call the function, supply x and y array as displayed on above table, set resolution to <b>0.1</b>:</p>
<div style="font-family:courier;font-size:8pt;background-color:#E0E0E0;">
SELECT * FROM spline(<br />
&nbsp;&nbsp;&#8217;{3.3,4.2,6.8,8.2,10.2}&#8217;::numeric[],<br />
&nbsp;&nbsp; &#8216;{1.2,-1.1,1.5,1.2,2.5}&#8217;::numeric[],<br />
&nbsp;&nbsp;0.1);
</div>
<p>We will have set of records containing <b>xs</b> and <b>ys</b>.:</p>
<div style="font-family:courier;font-size:8pt;background-color:#E0E0E0;">
xs&nbsp;&nbsp;ys<br />
3.3&nbsp;&nbsp;1.199999999999999970<br />
3.4&nbsp;&nbsp;0.8860175045157231811<br />
3.5&nbsp;&nbsp;0.5764170295261004851<br />
3.6&nbsp;&nbsp;0.2755805955257859750<br />
3.7&nbsp;&nbsp;-0.0121097769905662565<br />
3.8&nbsp;&nbsp;-0.28227206752830211620<br />
&#8230; and so on
</div>
<p>Let us put them in graph:<br />
<img src="http://abdulyadi.files.wordpress.com/2009/05/curve.jpg?w=595" alt="curve" title="curve"   class="aligncenter size-full wp-image-92" /></p>
<p>The blue-y1 and red-y2 are sample and interpolation points as returned by the <b>spline</b> function, respectively.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/62/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/62/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=62&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2009/05/16/plsql-for-curve-smoothing/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>

		<media:content url="http://abdulyadi.files.wordpress.com/2009/05/curve.jpg" medium="image">
			<media:title type="html">curve</media:title>
		</media:content>
	</item>
		<item>
		<title>Tree-structured data and Nested Hash</title>
		<link>http://abdulyadi.wordpress.com/2009/02/06/tree-structured-data-and-nested-hash/</link>
		<comments>http://abdulyadi.wordpress.com/2009/02/06/tree-structured-data-and-nested-hash/#comments</comments>
		<pubDate>Fri, 06 Feb 2009 09:12:34 +0000</pubDate>
		<dc:creator>abdulyadi</dc:creator>
				<category><![CDATA[PostgreSQL]]></category>

		<guid isPermaLink="false">http://abdulyadi.wordpress.com/?p=50</guid>
		<description><![CDATA[I have just accomplished a task to transfer tree-formed data structure from client application environment into PostgreSQL PLSQL body function. The tree at client side is structured as shown below: &#160;&#160;&#124;&#8211;Manager1 &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124; &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#8211;Senior1 &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#8211;Junior1 &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#8211;Junior2 &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124; &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#8211;Senior2 &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#8211;Junior3 &#160;&#160;&#124;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#8211;Junior4 &#160;&#160;&#124;&#160;&#160; &#160;&#160;&#124;&#8211;Manager2 &#160;&#160;&#160;&#160;&#160;&#160;&#124; &#160;&#160;&#160;&#160;&#160;&#160;&#124;&#8211;Senior3 &#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#8211;Junior5 &#160;&#160;&#160;&#160;&#160;&#160;&#124;&#160;&#160;&#160;&#160;&#124;&#8211;Junior6 &#160;&#160;&#160;&#160;&#160;&#160;&#124; &#160;&#160;&#160;&#160;&#160;&#160;&#124;&#8211;Senior4 &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#8211;Junior7 &#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#124;&#8211;Junior8 Instead of send the item pieces [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=50&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
				<content:encoded><![CDATA[<p>I have just accomplished a task to transfer tree-formed data structure from client application environment into PostgreSQL PLSQL body function. The tree at client side is structured as shown below:</p>
<div style="background-color:#E0E0E0;">
<p>&nbsp;&nbsp;|&#8211;Manager1<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Senior1<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior1<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior2<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Senior2<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior3<br />
&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior4<br />
&nbsp;&nbsp;|&nbsp;&nbsp;<br />
&nbsp;&nbsp;|&#8211;Manager2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Senior3<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior5<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior6<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Senior4<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior7<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|&#8211;Junior8
</p></div>
<p>Instead of send the item pieces one by one, I want to send all the items at once.</p>
<h3>PLSQL Function (convert array of ltree into nested hash)</h3>
<p>I decide to package the tree items in the array of LTREE field type provided in PostgreSQL contrib module by Teodor Sigaev and Oleg Bartunov. Later in the function body, I convert the LTREE array into HSTORE (again thanks to Teodor Sigaev and Oleg Bartunov). HSTORE maps key to value. Both are string types. But in my case, the hash contains key which point to another hash, creating nested hash.</p>
<p>Following is the stored procedure in PLSQL created on Postgresql 8.3.1:</p>
<div style="background-color:#E0E0E0;font-family:courier;font-size:8pt;">
CREATE OR REPLACE FUNCTION organization(IN trees ltree[]) RETURNS void AS<br />
$BODY$<br />
DECLARE<br />
&#8212;&#8212;&#8211;ltree[] will be converted to nested hash:<br />
&#8212;&#8212;&#8212;&#8212;-hash_mgr=&gt;hash_snr=&gt;array(Juniors)<br />
&nbsp;&nbsp;&nbsp;&nbsp;i integer;<br />
&nbsp;&nbsp;&nbsp;&nbsp;count integer;<br />
&nbsp;&nbsp;&nbsp;&nbsp;hash_mgr hstore;<br />
&nbsp;&nbsp;&nbsp;&nbsp;hash_snr hstore;<br />
&nbsp;&nbsp;&nbsp;&nbsp;tree ltree;<br />
&nbsp;&nbsp;&nbsp;&nbsp;arr text[];<br />
&nbsp;&nbsp;&nbsp;&nbsp;mgr text;<br />
&nbsp;&nbsp;&nbsp;&nbsp;snr text;<br />
&nbsp;&nbsp;&nbsp;&nbsp;jnr text;<br />
&nbsp;&nbsp;&nbsp;&nbsp;k1 text; v1 text;<br />
&nbsp;&nbsp;&nbsp;&nbsp;k2 text; v2 text;<br />
BEGIN<br />
&nbsp;&nbsp;&nbsp;&nbsp;count:=ARRAY_UPPER(trees,1);<br />
&#8212;&#8212;&#8211;convert array of trees into nested hash:<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR i IN 1..count LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tree:=trees[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mgr:=SUBLTREE(tree,0,1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;snr:=SUBLTREE(tree,1,2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jnr:=SUBLTREE(tree,2,3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash_snr:=(hash_mgr-&gt;mgr)::hstore;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr:=(hash_snr-&gt;snr)::text[];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arr:=COALESCE(arr,&#8217;{}&#8217;::text[]) || jnr;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash_snr:=COALESCE( hash_snr||(snr=&gt;arr::text),snr=&gt;arr::text);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hash_mgr:=COALESCE( hash_mgr||(mgr=&gt;hash_snr::text),mgr=&gt;hash_snr::text);<br />
&nbsp;&nbsp;&nbsp;&nbsp;END LOOP;<br />
&#8212;&#8212;&#8211;now we hava nested hash<br />
&#8212;&#8212;&#8211;usage 1: get Junior1 and Junior2:<br />
&nbsp;&nbsp;&nbsp;&nbsp;arr:=((hash_mgr-&gt;&#8217;Manager1&#8242;)::hstore)-&gt;&#8217;Senior1&#8242;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;RAISE NOTICE &#8216;% %&#8217;,arr[1],arr[2];<br />
&#8212;&#8212;&#8211;navigate all items<br />
&nbsp;&nbsp;&nbsp;&nbsp;FOR k1, v1 IN SELECT key, value FROM EACH(hash_mgr) LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE NOTICE &#8216;manager: %&#8217;,k1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FOR k2, v2 IN SELECT key, value FROM EACH(v1::hstore) LOOP<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE NOTICE &#8216;    senior: %&#8217;,k2;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE NOTICE &#8216;      junior: %&#8217;,(v2::text[])[1];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RAISE NOTICE &#8216;      junior: %&#8217;,(v2::text[])[2];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;END LOOP;<br />
&nbsp;&nbsp;&nbsp;&nbsp;END LOOP;<br />
&nbsp;&nbsp;&nbsp;&nbsp;RETURN;<br />
END;$BODY$<br />
LANGUAGE &#8216;plpgsql&#8217; STABLE;
</div>
<p>Let&#8217;s start from lowest level. Hash <b>hash_snr</b> maps &#8220;senior&#8221; to array of juniors.<br />
Go up one level, hash <b>hash_mgr</b> maps &#8220;manager&#8221; to hash <b>hash_snr</b>.</p>
<p>To use the function, client application should invoke it as follows:</p>
<div style="background-color:#E0E0E0;font-family:courier;font-size:8pt;">
SELECT organization(&#8216;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;Manager1.Senior1.Junior1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;Manager1.Senior1.Junior2,<br />
&nbsp;&nbsp;&nbsp;&nbsp;Manager1.Senior2.Junior3,<br />
&nbsp;&nbsp;&nbsp;&nbsp;Manager1.Senior2.Junior4,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manager2.Senior3.Junior5,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manager2.Senior3.Junior6,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manager2.Senior4.Junior7,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Manager2.Senior4.Junior8<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&#8217;);
</div>
<p>Take note RAISE NOTICE at the lower portion of function body. It will give us messages as follows:</p>
<div style="background-color:#E0E0E0;font-family:courier;font-size:8pt;">
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;Junior1 Junior2<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;manager: Manager1<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;senior: Senior1<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior1<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior2<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;senior: Senior2<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior3<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior4<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;manager: Manager2<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;senior: Senior3<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior5<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior6<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;senior: Senior4<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior7<br />
NOTICE:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;junior: Junior8
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/abdulyadi.wordpress.com/50/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/abdulyadi.wordpress.com/50/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=abdulyadi.wordpress.com&#038;blog=5629914&#038;post=50&#038;subd=abdulyadi&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://abdulyadi.wordpress.com/2009/02/06/tree-structured-data-and-nested-hash/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://2.gravatar.com/avatar/2b8e51e57db241b6e5add5249348c31c?s=96&amp;d=http%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D96" medium="image">
			<media:title type="html">abdulyadi</media:title>
		</media:content>
	</item>
	</channel>
</rss>
