<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>The Dev Blog: Category Postgres</title>
    <link>http://devblog.famundo.com/articles/category/postgres</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Putting Family Management on Rails!</description>
    <item>
      <title>Adding Support for Functional Indexes in Rails</title>
      <description>&lt;p&gt;Rails migrations are a great tool, and one of the things I really love about rails. It made database changes phobia a thing of the past :-) But the migration support a pretty low common denominator as to what can be done without resorting to sending direct SQL commands. &lt;/p&gt;

&lt;p&gt;One of the things I use all the time and really miss in migrations, are functional indexes. Postgres supports those, and it's a shame not to use it. For those not aware of what a functional index is, it's an index that is built by calling a function for the row values to index, insted of using the actual value itself. The simplest use I have for it is when I want to make names case-insensitive when searching. So that a:  &lt;pre&gt;select * where lower(name) = 'test'&lt;/pre&gt; can actually use the index efficiently. &lt;/p&gt;

&lt;p&gt;The change works in such a way that if the database doesn't support functional indexes (as defined in the adapter in rails) it will fall back to generate the regular index. So the following statement in a migration:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_sql "&gt;add_index :users, :name, :functional =&amp;gt; 'lower(name)'&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Will create a regular index in MySQL, but will create a functional index in Postgres.&lt;/p&gt;

&lt;p&gt;Here is the diff agains rails 1.2.1. The changes can also be transfered to other rails versions as they are pretty simple:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Index&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;abstract&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;schema_statements&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;
&lt;span class="punct"&gt;===================================================================&lt;/span&gt;
&lt;span class="punct"&gt;---&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;abstract&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;schema_statements&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;revision&lt;/span&gt; &lt;span class="number"&gt;28&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="punct"&gt;+++&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;abstract&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;schema_statements&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;working&lt;/span&gt; &lt;span class="ident"&gt;copy&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="attribute"&gt;@@&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;186&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;14&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;186&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;16&lt;/span&gt; &lt;span class="attribute"&gt;@@&lt;/span&gt;
       &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;add_index&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;table_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;column_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{})&lt;/span&gt;
         &lt;span class="ident"&gt;column_names&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;column_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
         &lt;span class="ident"&gt;index_name&lt;/span&gt;   &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;index_name&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;table_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:column&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;column_names&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="ident"&gt;functional&lt;/span&gt;   &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;

         &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt; &lt;span class="punct"&gt;===&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt; &lt;span class="comment"&gt;# legacy support, since this param was a string&lt;/span&gt;
           &lt;span class="ident"&gt;index_type&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:unique&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;UNIQUE&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
           &lt;span class="ident"&gt;index_name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:name&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="ident"&gt;index_name&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;          &lt;span class="ident"&gt;functional&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:functional&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;supports_functional_indexes?&lt;/span&gt;
         &lt;span class="keyword"&gt;else&lt;/span&gt;
           &lt;span class="ident"&gt;index_type&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;options&lt;/span&gt;
         &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="punct"&gt;-&lt;/span&gt;        &lt;span class="ident"&gt;quoted_column_names&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;column_names&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;quote_column_name&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;, &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="ident"&gt;quoted_column_names&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;functional&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;column_names&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;quote_column_name&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;, &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;functional&lt;/span&gt;
         &lt;span class="ident"&gt;execute&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;CREATE &lt;span class="expr"&gt;#{index_type}&lt;/span&gt; INDEX &lt;span class="expr"&gt;#{quote_column_name(index_name)}&lt;/span&gt; ON &lt;span class="expr"&gt;#{table_name}&lt;/span&gt; (&lt;span class="expr"&gt;#{quoted_column_names}&lt;/span&gt;)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="constant"&gt;Index&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;abstract_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;
&lt;span class="punct"&gt;===================================================================&lt;/span&gt;
&lt;span class="punct"&gt;---&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;abstract_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;      &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;revision&lt;/span&gt; &lt;span class="number"&gt;28&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="punct"&gt;+++&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;abstract_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;      &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;working&lt;/span&gt; &lt;span class="ident"&gt;copy&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="attribute"&gt;@@&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;42&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;6&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;42&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;12&lt;/span&gt; &lt;span class="attribute"&gt;@@&lt;/span&gt;
         &lt;span class="constant"&gt;false&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="punct"&gt;+&lt;/span&gt;      &lt;span class="comment"&gt;# Does this adapter support functional indexes? Backend specific, as the&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;      &lt;span class="comment"&gt;# abstract adapter always returns +false+.&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;supports_functional_indexes?&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="constant"&gt;false&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;
       &lt;span class="comment"&gt;# Does this adapter support using DISTINCT within COUNT?  This is +true+&lt;/span&gt;
       &lt;span class="comment"&gt;# for all adapters except sqlite.&lt;/span&gt;
       &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;supports_count_distinct?&lt;/span&gt;
&lt;span class="constant"&gt;Index&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;postgresql_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;
&lt;span class="punct"&gt;===================================================================&lt;/span&gt;
&lt;span class="punct"&gt;---&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;postgresql_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;revision&lt;/span&gt; &lt;span class="number"&gt;28&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="punct"&gt;+++&lt;/span&gt; &lt;span class="ident"&gt;activerecord&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;postgresql_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;working&lt;/span&gt; &lt;span class="ident"&gt;copy&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="attribute"&gt;@@&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;111&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;6&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;111&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt; &lt;span class="attribute"&gt;@@&lt;/span&gt;
         &lt;span class="number"&gt;63&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="punct"&gt;+&lt;/span&gt;      &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;supports_functional_indexes?&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="constant"&gt;true&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;
       &lt;span class="comment"&gt;# QUOTING ==================================================&lt;/span&gt;

       &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;quote&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;column&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 29 Jan 2007 13:48:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:0c8dafb1-aebc-41a5-8313-21e899d31745</guid>
      <author>guy.naor@famundo.com (Guy Naor)</author>
      <link>http://devblog.famundo.com/articles/2007/01/29/adding-support-for-functional-indexes-in-rails</link>
      <category>Rails</category>
      <category>Ruby</category>
      <category>Postgres</category>
    </item>
    <item>
      <title>Improving Postgres LISTEN/NOTIFY Support in Ruby/Rails</title>
      <description>&lt;p&gt;The &lt;a href="http://www.postgresql.org"&gt;Postgres&lt;/a&gt; DB server has a very cool mechanism for passing messages between the backend and clients and between the clients, using a simple LISTEN and NOTIFY system. &lt;/p&gt;

&lt;p&gt;The way it works is that any client can register to LISTEN to a named event, and whenever any other client (or the backend using triggers/functions) issues a NOTIFY command for the named event, all listening clients will be notified of it. You can find the full documentation &lt;a href="http://www.postgresql.org/docs/8.1/interactive/sql-notify.html"&gt;here&lt;/a&gt; and &lt;a href="http://www.postgresql.org/docs/8.1/interactive/sql-listen.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A usage scenario is a background process that need to act at specific times based on database changes. The process can sleep not consuming any CPU, until a notification arrives, it wakes up does it's thing, and go back to sleep. It can also be used to keep cache consistency or to manage locks between clients. And many other scenarios.&lt;/p&gt;

&lt;p&gt;The ruby postgres driver (C based version) has some support for this using the get_notify method. But it has some limitations which I wanted to remove:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Notifications arrive at the client whenever they are sent, but to know they arrived you need to poll the library, in effect making it again a poll solution. I wanted to change it to a solution that uses no CPU while waiting, and also isn't dependant on polling intervals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Currently you have to issue a query to know that the notification arrived. This makes the polling solution even less attractive as you have to generate some query to know if something arrived. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Postgres library provides a function called PQconsumeInput that solves the problem of having to send a query to see if a notification arrives. Once executed, calling get_notify will return any waiting notifications (call it multiple times until a nil is returned, as each call returns one notification). &lt;/p&gt;

&lt;p&gt;To completely remove the need to poll (even with PQconsumeInput you still need to poll) I added another function based on an &lt;a href="http://www.postgresql.org/docs/8.1/interactive/libpq-example.html"&gt;example&lt;/a&gt; from the Postgres documentation. This functions will get the current connection socket, and using a select() (system one, not sql) wait for any new activity on the socket. Once a notification arrives, the select() will stop blocking, and we can call consume_input and then get_notify() to get any waiting notifications. Put it in a loop and go back to waiting after handling the incoming events, and you have a  process that waits for notifications without using any CPU time while waiting.&lt;/p&gt;

&lt;p&gt;Please note that in order to use those new functions in rails applications you have to use the raw_connection:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;ActiveRecord::Base.connection.raw_connection.consume_input&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here is diff to the Ruby driver (you will need to recompile it). If you would like to also have the patched C file, let me know.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;--- ruby-postgres-0.7.1/postgres.c   2003-01-05 17:38:20.000000000 -0800
+++ postgres.c  2006-12-04 13:04:55.000000000 -0800
@@ -439,6 +439,40 @@
     return ary;
 }

+
+static VALUE
+pgconn_consume_input(obj)
+    VALUE obj;
+{
+    PGconn *conn = get_pgconn(obj);
+    if (PQconsumeInput(conn) == 0)
+      rb_raise(rb_ePGError, PQerrorMessage(conn));
+    return Qnil;
+}
+
+
+static VALUE
+pgconn_wait_for_activity(obj)
+    VALUE obj;
+{
+    fd_set input_mask;
+    PGconn *conn = get_pgconn(obj);
+    int    sock  = PQsocket(conn);
+
+    if (sock &amp;lt; 0)
+         rb_raise(rb_ePGError, &amp;quot;Bad connection socket&amp;quot;);
+
+    FD_ZERO(&amp;amp;input_mask);
+    FD_SET(sock, &amp;amp;input_mask);
+
+    /* Wait for something to happen on the socket */
+    if (select(sock + 1, &amp;amp;input_mask, NULL, NULL, NULL) &amp;lt; 0)
+        rb_raise(rb_ePGError, &amp;quot;Socket select() failed&amp;quot;);
+
+    return Qnil;
+}
+
+
 static VALUE pg_escape_regex;
 static VALUE pg_escape_str;
 static ID    pg_gsub_bang_id;
@@ -1443,6 +1477,8 @@
     rb_define_method(rb_cPGconn, &amp;quot;getline&amp;quot;, pgconn_getline, 0);
     rb_define_method(rb_cPGconn, &amp;quot;endcopy&amp;quot;, pgconn_endcopy, 0);
     rb_define_method(rb_cPGconn, &amp;quot;notifies&amp;quot;, pgconn_notifies, 0);
+    rb_define_method(rb_cPGconn, &amp;quot;consume_input&amp;quot;, pgconn_consume_input, 0);
+    rb_define_method(rb_cPGconn, &amp;quot;wait_for_activity&amp;quot;, pgconn_wait_for_activity, 0);

 #ifdef HAVE_PQSETCLIENTENCODING
     rb_define_method(rb_cPGconn, &amp;quot;client_encoding&amp;quot;,pgconn_client_encoding, 0);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Thu, 07 Dec 2006 07:00:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:5f05e109-9b42-4472-a3eb-358a876717f8</guid>
      <author>guy.naor@famundo.com (Guy Naor)</author>
      <link>http://devblog.famundo.com/articles/2006/12/07/improving-postgres-listen-notify-support-in-ruby-rails</link>
      <category>Rails</category>
      <category>Ruby</category>
      <category>Postgres</category>
    </item>
    <item>
      <title>Fixing Rails for Postgres Schemas</title>
      <description>&lt;p&gt;Postgres has a very powerful feature in the schemas, especially with the schema search_path. Using it I can have multiple separate families, all using the same database connection, but also fully separated (with a different user to access the schema files). Using the search path and the SESSION AUTHORIZATION it is completely transparent to rails. I'll have a later post explaining how to use this technique in a rails application.&lt;/p&gt;

&lt;p&gt;The cool thing about the search_path is that you can have multiple instances of the same table in different schemas, and using SET SESSION AUTHORIZATION, you can see a different table each time. Rails works great with this.&lt;/p&gt;

&lt;p&gt;But there's a small bug in the postgres driver for handling sequences. (The bug doesn't show up in development mode because the objects are reloaded all the time.) When postgres loads the sequence name used for the auto increment keys (serial type in postgres), it adds the schema to the sequence name. So instead of messages_id_seq, it will return public.messages_id_seq. If another request coming in, tries to insert a record, the call to SELECT currval() will return the wrong sequence, and if (like I do) there's user security between schemas, you get an access error and the insert fails.&lt;/p&gt;

&lt;p&gt;The fix is very simple - just return the unqualified sequence name, as the rest of the access in rails is unqualified. &lt;/p&gt;

&lt;p&gt;I'm posting a ticket with the fix and a test file for it. The fix to the rails edge is the following (in diff format):&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="constant"&gt;Index&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;postgresql_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt;
&lt;span class="punct"&gt;===================================================================&lt;/span&gt;
&lt;span class="punct"&gt;---&lt;/span&gt; &lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;postgresql_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;revision&lt;/span&gt; &lt;span class="number"&gt;4414&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="punct"&gt;+++&lt;/span&gt; &lt;span class="ident"&gt;lib&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;active_record&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;connection_adapters&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="ident"&gt;postgresql_adapter&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;rb&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;working&lt;/span&gt; &lt;span class="ident"&gt;copy&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
&lt;span class="attribute"&gt;@@&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;296&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;8&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="number"&gt;296&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;9&lt;/span&gt; &lt;span class="attribute"&gt;@@&lt;/span&gt;
               &lt;span class="constant"&gt;AND&lt;/span&gt; &lt;span class="keyword"&gt;def&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;adsrc&lt;/span&gt; ~&lt;span class="punct"&gt;*&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;nextval&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
           &lt;span class="ident"&gt;end_sql&lt;/span&gt;
         &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="punct"&gt;-&lt;/span&gt;        &lt;span class="comment"&gt;# check for existence of . in sequence name as in public.foo_sequence.  if it does not exist, join the current namespace&lt;/span&gt;
&lt;span class="punct"&gt;-&lt;/span&gt;        &lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;last&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;last&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{result[1]}&lt;/span&gt;.&lt;span class="expr"&gt;#{result[2]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="comment"&gt;# check for existence of . in sequence name as in public.foo_sequence.  if it does not exist, return unqualified sequence&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="comment"&gt;# We cannot qualify unqualified sequences, as rails doesn't qualify any table access, using the search path&lt;/span&gt;
&lt;span class="punct"&gt;+&lt;/span&gt;        &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;result&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;last&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
       &lt;span class="keyword"&gt;rescue&lt;/span&gt;
         &lt;span class="constant"&gt;nil&lt;/span&gt;
       &lt;span class="keyword"&gt;end&lt;/span&gt;
                                                                                                                                &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 03 Jun 2006 18:26:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:d80f4e6dbdf447842e66d1df15ff7c23</guid>
      <author>guy.naor@famundo.com (Guy Naor)</author>
      <link>http://devblog.famundo.com/articles/2006/06/03/fixing-rails-for-postgres-schemas</link>
      <category>Rails</category>
      <category>Postgres</category>
      <trackback:ping>http://devblog.famundo.com/articles/trackback/17</trackback:ping>
    </item>
    <item>
      <title>And So It Starts</title>
      <description>&lt;p&gt;It wasn't too long ago that my main development language was C++ on Windows. But when I decided I want to do web development, this just plain didn't make sense. Enter Ruby and Rails!&lt;/p&gt;

&lt;p&gt;I was on a search for a good web development environment, and looked at many of the options available, but none seemed to meet my requirements. Java was too heavy (I did do Java development in the past, but that was long ago), I didn't like the then available Python stacks and I really dislike all the .NET stuff. Call it too many years on Windows, or a dislike to proprietary systems, but I just won't touch it.&lt;/p&gt;

&lt;p&gt;While searching, I stumbled upon &lt;a href="http://www.rubyonrails.com"&gt;RubyOnRails&lt;/a&gt;. I was weary of all the promises I read about it, but playing with it a bit proved me wrong. What a refreshing surprise!!! &lt;/p&gt;

&lt;p&gt;Then came the need to do a 180 degree turn in my head. From the strict mindset of C++ to the "crazy" way Ruby and the other dynamic languages do things. I had no prior Ruby experience, so it required lots of learning. Luckily I had lots of experience with Linux and all related technologies, so this part was taken care of.&lt;/p&gt;

&lt;p&gt;A few weeks after starting learning, I switched my dev environment from Visual Studio on Windows to Eclipse on Fedora Core 4 (past experience with RedHat made it my choice), and I can't be happier :-). &lt;/p&gt;

&lt;p&gt;Some dev choices I have made so far:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OS - Linux FC4&lt;/li&gt;
&lt;li&gt;IDE - Eclipse with RadRails&lt;/li&gt;
&lt;li&gt;Source control - Subversion&lt;/li&gt;
&lt;li&gt;Database - PostgreSQL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Come visit this blog for some development ideas and solutions related to my new development journey. And for details as I take an amazing new application online.&lt;/p&gt;</description>
      <pubDate>Sat, 28 Jan 2006 15:44:00 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:7056d6af8eee779c149bdbbdf3764191</guid>
      <author>guy.naor@famundo.com (Guy Naor)</author>
      <link>http://devblog.famundo.com/articles/2006/01/28/and-so-it-starts</link>
      <category>Rails</category>
      <category>Ruby</category>
      <category>Postgres</category>
      <category>Linux</category>
      <trackback:ping>http://devblog.famundo.com/articles/trackback/1</trackback:ping>
    </item>
  </channel>
</rss>
