<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Ray::Apps.blog</title>
 <link href="http://blog.rayapps.com/atom.xml" rel="self"/>
 <link href="http://blog.rayapps.com/"/>
 <updated>2013-03-11T23:01:27+02:00</updated>
 <id>http://blog.rayapps.com/</id>
 <author>
   <name>Raimonds Simanovskis</name>
   <email>raimonds.simanovskis@gmail.com</email>
 </author>

 
 <entry>
   <title>7 things that can go wrong with Ruby 1.9 string encodings</title>
   <link href="http://blog.rayapps.com/2013/03/11/7-things-that-can-go-wrong-with-ruby-19-string-encodings/"/>
   <updated>2013-03-11T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2013/03/11/7-things-that-can-go-wrong-with-ruby-19-string-encodings</id>
   <content type="html">&lt;p&gt;Good news, I am back in blogging :) In recent years I have spent my time primarily on &lt;a href=&quot;https://eazybi.com&quot;&gt;eazyBI&lt;/a&gt; business intelligence application development where I use &lt;a href=&quot;http://jruby.org/&quot;&gt;JRuby&lt;/a&gt;, &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt;, &lt;a href=&quot;https://github.com/rsim/mondrian-olap&quot;&gt;mondrian-olap&lt;/a&gt; and many other technologies and libraries and have gathered new experience that I wanted to share with others.&lt;/p&gt;

&lt;p&gt;Recently I did eazyBI migration from JRuby 1.6.8 to latest JRuby 1.7.3 version as well as finally migrated from Ruby 1.8 mode to Ruby 1.9 mode. Initial migration was not so difficult and was done in one day (thanks to unit tests which caught majority of differences between Ruby 1.8 and 1.9 syntax and behavior).&lt;/p&gt;

&lt;p&gt;But then when I thought that everything is working fine I got quite many issues related to Ruby 1.9 string encodings which unfortunately were not identified by test suite and also not by my initial manual tests. Therefore I wanted to share these issues which might help you to avoid these issues in your Ruby 1.9 applications.&lt;/p&gt;

&lt;p&gt;If you are new to Ruby 1.9 string encodings then at first read, for example, tutorials about &lt;a href=&quot;http://blog.grayproductions.net/articles/ruby_19s_string&quot;&gt;Ruby 1.9 String&lt;/a&gt; and &lt;a href=&quot;http://blog.grayproductions.net/articles/ruby_19s_three_default_encodings&quot;&gt;Ruby 1.9 Three Default Encodings&lt;/a&gt;, as well as &lt;a href=&quot;http://yehudakatz.com/2010/05/05/ruby-1-9-encodings-a-primer-and-the-solution-for-rails/&quot;&gt;Ruby 1.9 Encodings: A Primer and the Solution for Rails&lt;/a&gt; is useful.&lt;/p&gt;

&lt;h3 id=&quot;toc_9&quot;&gt;1. Encoding header in source files&lt;/h3&gt;

&lt;p&gt;I will start with the easy one - if you use any Unicode characters in your Ruby source files then you need to add&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# encoding: utf-8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;magic comment line in the beginning of your source file. This was easy as it was caught by unit tests :)&lt;/p&gt;

&lt;h3 id=&quot;toc_10&quot;&gt;2. Nokogiri XML generation&lt;/h3&gt;

&lt;p&gt;The next issues were with XML generation using Nokogiri gem when XML contains Unicode characters. For example,&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;nokogiri&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;Nokogiri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:XML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dummy&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;āčē&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;will give the following result when using MRI 1.9:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;dummy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&amp;amp;#x101;&amp;amp;#x10D;&amp;amp;#x113;&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;which might not be what you expect if you would like to use UTF-8 encoding also for Unicode characters in generated XML file. If you execute the same ruby code in JRuby 1.7.3 in default Ruby 1.9 mode then you get:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;dummy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;āčē&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;which seems OK. But actually it is not OK if you look at generated string encoding:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Encoding:US-ASCII&amp;gt;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inspect&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;&amp;lt;?xml version=\&amp;quot;1.0\&amp;quot;?&amp;gt;\n&amp;lt;dummy name=\&amp;quot;\xC4\x81\xC4\x8D\xC4\x93\&amp;quot;/&amp;gt;\n&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;In case of JRuby you see that &lt;code&gt;doc.to_xml&lt;/code&gt; encoding is US-ASCII (which is 7 bit encoding) but actual content is using UTF-8 8-bit encoded characters. As a result you might get &lt;code&gt;ArgumentError: invalid byte sequence in US-ASCII&lt;/code&gt; exceptions later in your code.&lt;/p&gt;

&lt;p&gt;Therefore it is better to tell Nokogiri explicitly that you would like to use UTF-8 encoding in generated XML:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;Nokogiri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:XML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:encoding&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dummy&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;āčē&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Encoding:UTF-8&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;dummy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;āčē&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;toc_11&quot;&gt;3. CSV parsing&lt;/h3&gt;

&lt;p&gt;If you do CSV file parsing in your application then the first thing you have to do is to replace FasterCSV gem (that you probably used in Ruby 1.8 application) with standard Ruby 1.9 CSV library.&lt;/p&gt;

&lt;p&gt;If you process user uploaded CSV files then typical problem is that even if you ask to upload files in UTF-8 encoding then quite often you will get files in different encodings (as Excel is quite bad at producing UTF-8 encoded CSV files).&lt;/p&gt;

&lt;p&gt;If you used FasterCSV library with non-UTF-8 encoded strings then you get ugly result but nothing will blow up:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FasterCSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xE2&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [[&amp;quot;\342&amp;quot;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If you do the same in Ruby 1.9 with CSV library then you will get ArgumentError exception.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\xE2&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; ArgumentError: invalid byte sequence in UTF-8&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;It means that now you need to rescue and handle ArgumentError exceptions in all places where you try to parse user uploaded CSV files to be able to show user friendly error messages.&lt;/p&gt;

&lt;p&gt;The problem with standard CSV library is that it is not handling ArgumentError exceptions and is not wrapping them in MalformedCSVError exception with information in which line this error happened (as it is done with other CSV format exceptions) which makes debugging very hard. Therefore I also &amp;quot;monkey patched&amp;quot; &lt;code&gt;CSV#shift&lt;/code&gt; method to add ArgumentError exception handling.&lt;/p&gt;

&lt;h3 id=&quot;toc_12&quot;&gt;4. YAML serialized columns&lt;/h3&gt;

&lt;p&gt;ActiveRecord has standard way how to serialize more complex data types (like Array or Hash) in database text column. You use &lt;code&gt;serialize&lt;/code&gt; method to declare serializable attributes in your ActiveRecord model class definition. By default YAML format (using &lt;code&gt;YAML.dump&lt;/code&gt; method for serialization) is used to serialize Ruby object to text that is stored in database.&lt;/p&gt;

&lt;p&gt;But you can get big problems if your data contains string with Unicode characters as YAML implementation significantly changed between Ruby 1.8 and 1.9 versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 1.8 used so-called Syck library&lt;/li&gt;
&lt;li&gt;JRuby in 1.8 mode used Java based implementation that tried to ack like Syck&lt;/li&gt;
&lt;li&gt;Ruby 1.9 and JRuby in 1.9 mode use new Psych library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lets try to see results what happens with YAML serialization of simple Hash with string value which contains Unicode characters.&lt;/p&gt;

&lt;p&gt;On MRI 1.8:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ace āčē&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;--- \n:name: !binary |\n  YWNlIMSBxI3Ekw==\n\n&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;On JRuby 1.6.8 in Ruby 1.8 mode:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ace āčē&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;--- \n:name: \&amp;quot;ace \\xC4\\x81\\xC4\\x8D\\xC4\\x93\&amp;quot;\n&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;On MRI 1.9 or JRuby 1.7.3 in Ruby 1.9 mode:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ace āčē&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;---\n:name: ace āčē\n&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So as we see all results are different. But now lets see what happens after we migrated our Rails application from Ruby 1.8 to Ruby 1.9. All our data in database is serialized using old YAML implementations but now when loaded in our application they are deserialized back using new Ruby 1.9 YAML implementation.&lt;/p&gt;

&lt;p&gt;When using MRI 1.9:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;--- &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:name: !binary |&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  YWNlIMSBxI3Ekw==&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:name=&amp;gt;&amp;quot;ace \xC4\x81\xC4\x8D\xC4\x93&amp;quot;}&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;--- &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:name: !binary |&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  YWNlIMSBxI3Ekw==&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Encoding:ASCII-8BIT&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So the string that we get back from database is no more in UTF-8 encoding but in ASCII-8BIT encoding and when we will try to concatenate it with UTF-8 encoded strings we will get &lt;code&gt;Encoding::CompatibilityError: incompatible character encodings: ASCII-8BIT and UTF-8&lt;/code&gt; exceptions.&lt;/p&gt;

&lt;p&gt;When using JRuby 1.7.3 in Ruby 1.9 mode then result again will be different:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;--- &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:name: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ace &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xC4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;x81&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xC4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;x8D&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xC4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;x93&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {:name=&amp;gt;&amp;quot;ace Ä\u0081Ä\u008DÄ\u0093&amp;quot;}&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;--- &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:name: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ace &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xC4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;x81&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xC4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;x8D&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;xC4&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;x93&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoding&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; #&amp;lt;Encoding:UTF-8&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So now result string has UTF-8 encoding but the actual string is damaged. It means that we will not even get exceptions when concatenating result with other UTF-8 strings, we will just notice some strange garbage instead of Unicode characters.&lt;/p&gt;

&lt;p&gt;The problem is that there is no good solution how to convert your database data from old YAML serialization to new one. In MRI 1.9 at least it is possible to switch back YAML to old Syck implementation but in JRuby 1.7 when using Ruby 1.9 mode it is not possible to switch to old Syck implementation.&lt;/p&gt;

&lt;p&gt;Current workaround that I did is that I made modified serialization class that I used in all model class definitions (this works in Rails 3.2 and maybe in earlier Rails 3.x versions as well):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;serialize&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:some_column&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;YAMLColumn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;code&gt;YAMLColumn&lt;/code&gt; implementation is a copy from original &lt;code&gt;ActiveRecord::Coders::YAMLColumn&lt;/code&gt; implementation. I modified &lt;code&gt;load&lt;/code&gt; method to the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil?&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^---/&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# if yaml sting contains old Syck-style encoded UTF-8 characters&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# then replace them with corresponding UTF-8 characters&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# FIXME: is there better alternative to eval?&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/\\x[0-9A-F]{2}/&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gsub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/(\\x[0-9A-F]{2})+/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;force_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nil?&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SerializationTypeMismatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;Attribute was supposed to be a &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object_class&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, but was a &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RESCUE_ERRORS&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;yaml&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Currently this patched version will work on JRuby where just non-ASCII characters are replaced by &lt;code&gt;\xNN&lt;/code&gt; style fragments (byte with hex code NN). When loading existing data from database we check if it has any such \xNN fragment and if yes then these fragments are replaced with corresponding UTF-8 encoded characters. If anyone has better suggestion for implementation without using &lt;code&gt;eval&lt;/code&gt; then please let me know in comments :)&lt;/p&gt;

&lt;p&gt;If you need to create something similar for MRI then you would probably need to search if database text contains &lt;code&gt;!binary |&lt;/code&gt; fragment and if yes then somehow transform it to corresponding UTF-8 string. Anyone has some working example for this?&lt;/p&gt;

&lt;h3 id=&quot;toc_13&quot;&gt;5. Sending binary data with default UTF-8 encoding&lt;/h3&gt;

&lt;p&gt;I am using &lt;a href=&quot;https://rubygems.org/gems/spreadsheet&quot;&gt;spreadsheet gem&lt;/a&gt; to generate dynamic Excel export files. The following code was used to get generated spreadsheet as String:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;Spreadsheet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:Workbook&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ... generate spreadsheet ...&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And then this string was sent back to browser using controller &lt;code&gt;send_data&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;The problem was that in Ruby 1.9 mode by default &lt;code&gt;StringIO&lt;/code&gt; will generate strings with UTF-8 encoding. But Excel format is binary format and as a result &lt;code&gt;send_data&lt;/code&gt; failed with exceptions that UTF-8 encoded string contains non-UTF-8 byte sequences.&lt;/p&gt;

&lt;p&gt;The fix was to set StringIO buffer encoding to &lt;code&gt;ASCII-8BIT&lt;/code&gt; (or you can use alias &lt;code&gt;BINARY&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_encoding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;ASCII-8BIT&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So you need to remember that in all places where you handle binary data you cannot use strings with default UTF-8 encoding but need to specify ASCII-8BIT encoding.&lt;/p&gt;

&lt;h3 id=&quot;toc_14&quot;&gt;6. JRuby Java file.encoding property&lt;/h3&gt;

&lt;p&gt;Last two issues were JRuby and Java specific. Java has system property &lt;code&gt;file.encoding&lt;/code&gt; which is not related just to file encoding but determines default character set and string encoding in many places.&lt;/p&gt;

&lt;p&gt;If you do not specify &lt;code&gt;file.encoding&lt;/code&gt; explicitly then Java VM on startup will try to determine its default value based on host operating system &amp;quot;locale&amp;quot;. On Linux it might be that it will be set to UTF-8, on Mac OS X by default it will be MacRoman, on Windows it will depend on Windows default locale setting (which will not be UTF-8). Therefore it is always better to set explicitly &lt;code&gt;file.encoding&lt;/code&gt; property for Java applications (e.g. using &lt;code&gt;-Dfile.encoding=UTF-8&lt;/code&gt; command line flag).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;file.encoding&lt;/code&gt; will determine which default character set &lt;code&gt;java.nio.charset.Charset.defaultCharset()&lt;/code&gt; method call will return. And even if you change &lt;code&gt;file.encoding&lt;/code&gt; property during runtime it will not change &lt;code&gt;java.nio.charset.Charset.defaultCharset()&lt;/code&gt; result which is cached during startup.&lt;/p&gt;

&lt;p&gt;JRuby uses &lt;code&gt;java.nio.charset.Charset.defaultCharset()&lt;/code&gt; in very many places to get default system encoding and uses it in many places when constructing Ruby strings. If &lt;code&gt;java.nio.charset.Charset.defaultCharset()&lt;/code&gt; will not return UTF-8 character set then it might result in problems when using Ruby strings with UTF-8 encoding. Therefore in JRuby startup scripts (&lt;code&gt;jruby&lt;/code&gt;, &lt;code&gt;jirb&lt;/code&gt; and others) &lt;code&gt;file.encoding&lt;/code&gt; property is always set to &lt;code&gt;UTF-8&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So if you start your JRuby application in standard way using &lt;code&gt;jruby&lt;/code&gt; script then you should have &lt;code&gt;file.encoding&lt;/code&gt; set to &lt;code&gt;UTF-8&lt;/code&gt;. You can check it in your application using &lt;code&gt;ENV_JAVA[&amp;#39;file.encoding&amp;#39;]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But if you start your JRuby application in non-standard way (e.g. you have JRuby based plugin for some other Java application) then you might not have &lt;code&gt;file.encoding&lt;/code&gt; set to &lt;code&gt;UTF-8&lt;/code&gt; and then you need to worry about it :)&lt;/p&gt;

&lt;h3 id=&quot;toc_15&quot;&gt;7. JRuby Java string to Ruby string conversion&lt;/h3&gt;

&lt;p&gt;I got &lt;code&gt;file.encoding&lt;/code&gt; related issue in &lt;a href=&quot;https://marketplace.atlassian.com/plugins/com.eazybi.jira.plugins.eazybi-jira&quot;&gt;eazyBI reports and charts plugin for JIRA&lt;/a&gt;. In this case eazyBI plugin is OSGi based plugin for &lt;a href=&quot;http://atlassian.com/software/jira/overview/&quot;&gt;JIRA issue tracking system&lt;/a&gt; and JRuby is running as a scripting container inside OSGi bundle.&lt;/p&gt;

&lt;p&gt;JIRA startup scripts do not specify &lt;code&gt;file.encoding&lt;/code&gt; default value and as a result it typically is set to operating system default value. For example, on my Windows test environment it is set to Windows-1252 character set.&lt;/p&gt;

&lt;p&gt;If you call Java methods of Java objects from JRuby then it will automatically convert &lt;code&gt;java.lang.String&lt;/code&gt; objects to Ruby &lt;code&gt;String&lt;/code&gt; objects but Ruby strings in this case will use encoding based on &lt;code&gt;java.nio.charset.Charset.defaultCharset()&lt;/code&gt;. So even when Java string (which internally uses UTF-16 character set for all strings) can contain any Unicode character it will be returned to Ruby not as string with UTF-8 encoding but in my case will return with Windows-1252 encoding. As a result all Unicode characters which are not in this Windows-1252 character set will be lost.&lt;/p&gt;

&lt;p&gt;And this is very bad because everywhere else in JIRA it does not use &lt;code&gt;java.nio.charset.Charset.defaultCharset()&lt;/code&gt; and can handle and store all Unicode characters even when &lt;code&gt;file.encoding&lt;/code&gt; is not set to UTF-8.&lt;/p&gt;

&lt;p&gt;Therefore I finally managed to create a workaround which forces that all Java strings are converted to Ruby strings using UTF-8 encoding.&lt;/p&gt;

&lt;p&gt;I created custom Java string converter based on standard one in &lt;code&gt;org.jruby.javasupport.JavaUtil&lt;/code&gt; class:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kn&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;eazybi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;jira&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.jruby.javasupport.JavaUtil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.jruby.Ruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.jruby.RubyString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;org.jruby.runtime.builtin.IRubyObject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RailsPluginJavaUtil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JavaUtil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;JavaConverter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JAVA_STRING_CONVERTER&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JavaUtil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;JavaConverter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IRubyObject&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getNil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// PATCH: always convert Java string to Ruby string with UTF-8 encoding&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// return RubyString.newString(runtime, (String)object);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RubyString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;newUnicodeString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IRubyObject&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Object&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IRubyObject&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[])&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toJava&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Then in my plugin initialization Ruby code I dynamically replaced standard Java string converter to my customized converter:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;java_converters_field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javasupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;JavaUtil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;java_class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;declared_field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;JAVA_CONVERTERS&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;java_converters_field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;accessible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;java_converters&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;java_converters_field&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;static_value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_java&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;java_converters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;java&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;java_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eazybi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jira&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RailsPluginJavaUtil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;JAVA_STRING_CONVERTER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And as a result now all Java strings that were returned by Java methods were converted to Ruby strings using UTF-8 encoding and not using encoding from &lt;code&gt;file.encoding&lt;/code&gt; Java property.&lt;/p&gt;

&lt;h3 id=&quot;toc_16&quot;&gt;Final thoughts&lt;/h3&gt;

&lt;p&gt;My main conclusions from solving all these string encoding issues are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use UTF-8 encoding as much as possible. Handling conversions between different encodings will be much more harder than you will expect.&lt;/li&gt;
&lt;li&gt;Use example strings with Unicode characters in your tests. I didn&amp;#39;t identify all these issues initially when running tests after migration because not all tests were using example strings with Unicode characters. So next time instead of using &lt;code&gt;&amp;quot;dummy&amp;quot;&lt;/code&gt; string in your test use &lt;code&gt;&amp;quot;dummy āčē&amp;quot;&lt;/code&gt; everywhere :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And please let me know (in comments) if you have better or alternative solutions for the issues that I described here.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Easy Business Intelligence with eazyBI</title>
   <link href="http://blog.rayapps.com/2011/09/11/easy-business-intelligence-with-eazybi/"/>
   <updated>2011-09-11T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2011/09/11/easy-business-intelligence-with-eazybi</id>
   <content type="html">&lt;p&gt;I have been interested in business intelligence and data warehouse solutions for quite a while. And I have seen that traditional data warehouse and business intelligence tool implementations take quite a long time and cost a lot to set up infrastructure, develop or implement business intelligence software and train users. And many business users are not using business intelligence tools because they are too hard to learn and use.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://eazybi.com&quot;&gt;&lt;img src=&quot;/images/eazybi.png&quot; style=&quot;float: left; margin: 20px;&quot;/&gt;&lt;/a&gt;Therefore some while ago a had an idea of developing easy-to-use business intelligence web application that you could implement and start to use right away and which would focus on ease-of-use and not on too much unnecessary features. And result of this idea is &lt;a href=&quot;https://eazybi.com&quot;&gt;eazyBI&lt;/a&gt; which after couple months of beta testing now is launched in production.&lt;/p&gt;

&lt;h3 id=&quot;toc_3&quot;&gt;Many sources of data&lt;/h3&gt;

&lt;p&gt;One of the first issues in data warehousing is that you need to prepare / import / aggregate data that you would like to analyze. It&amp;#39;s hard to create universal solution for this issue therefore I am building several predefined ways how to upload or prepare your data for analysis.&lt;/p&gt;

&lt;p&gt;In the simplest case if you have source data in CSV (comma-separated values) format or you can export your data in CSV format then you can &lt;a href=&quot;https://eazybi.com/help/demo-example&quot;&gt;upload these files to eazyBI&lt;/a&gt;, map columns to &lt;a href=&quot;https://eazybi.com/help/overview&quot;&gt;dimensions and measures&lt;/a&gt; and start to analyze and create reports from uploaded data.&lt;/p&gt;

&lt;p&gt;If you are already using some software-as-a-service web applications and would like to have better analysis tools to analyze your data in these applications then eazyBI will provide standard integrations for data import and will create initial sample reports. Currently the first integrations are with &lt;a href=&quot;https://eazybi.com/help/basecamp&quot;&gt;37signals Basecamp project collaboration application&lt;/a&gt; as well as you can &lt;a href=&quot;https://eazybi.com/help/demo-twitter&quot;&gt;import and analyze your Twitter timeline&lt;/a&gt;. More standard integrations with other applications will follow (please let me know if you would be interested in some particular integration).&lt;/p&gt;

&lt;p&gt;One of the main limiting factors for business intelligence as a service solutions is that many businesses are not ready to upload their data to service providers - both because of security concerns as well as uploading of big data volumes takes quite a long time. &lt;a href=&quot;https://eazybi.com/help/remote-setup&quot;&gt;Remote eazyBI solution&lt;/a&gt; is unique solution which allows you to use eazyBI business intelligence as a service application with your existing data in your existing databases. You just need to download and set up remote eazyBI application and start to analyze your data. As a result you get the benefits of fast implementation of business intelligence as a service but without the risks of uploading your data to service provider.&lt;/p&gt;

&lt;h3 id=&quot;toc_4&quot;&gt;Easy-to-use&lt;/h3&gt;

&lt;p&gt;Many existing business intelligence tools suffer from too many features which make them complicated to use and you need special business intelligence tool consultants which will create reports and dashboards for business users.&lt;/p&gt;

&lt;p&gt;Therefore my goal for eazyBI is to make it with less features but any feature that is added should be easy-to-use. With simple drag-and-drop and couple clicks you can select dimensions by which you want to analyze data and start with summaries and then drill into details. Results can be viewed as traditional tables or as different bar, line, pie, timeline or map charts. eazyBI is easy and fun to use as you play with your data.&lt;/p&gt;

&lt;h3 id=&quot;toc_5&quot;&gt;Share reports with others&lt;/h3&gt;

&lt;p&gt;When you have created some report which you would like to share with other your colleagues, customers or partners then you can either send link to report or you can also embed report into other HTML pages. Here is example of embedded report from demo eazyBI account:&lt;/p&gt;

&lt;div style=&quot;text-align:center;&quot;&gt;&lt;iframe width=&quot;750&quot; height=&quot;475&quot; src=&quot;https://eazybi.com/accounts/1/embed/report/111?dashboard_id=6&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;Embedded reports are fully dynamic and will show latest data when page will be refreshed. They can be embedded in company intranets, wikis or blogs or any other web pages.&lt;/p&gt;

&lt;h3 id=&quot;toc_6&quot;&gt;Open web technologies&lt;/h3&gt;

&lt;p&gt;eazyBI user interface is built with open HTML5/CSS3/JavaScript technologies which allows to use it both on desktop browsers as well as on mobile devices like iPad (you will be able to open reports even on mobile phones like iPhone or Android but of course because of screen size it will be harder to use). And if you will use modern browser like Chrome, Firefox, Safari or Internet Explorer 9 then eazyBI will be also very fast and responsive. I believe that speed should be one of the main features of any application therefore I am optimizing eazyBI to be as fast as possible.&lt;/p&gt;

&lt;p&gt;In the backend eazyBI uses open source &lt;a href=&quot;http://mondrian.pentaho.com/&quot;&gt;Mondrian OLAP engine&lt;/a&gt; and &lt;a href=&quot;https://github.com/rsim/mondrian-olap&quot;&gt;mondrian-olap&lt;/a&gt; JRuby library that I have created and open-sourced during eazyBI development.&lt;/p&gt;

&lt;h3 id=&quot;toc_7&quot;&gt;No big initial investments&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://eazybi.com/pricing&quot;&gt;eazyBI pricing&lt;/a&gt; is based on monthly subscription starting from $20 per month. There is also free plan for single user as well as you can publish public data for free. And you don&amp;#39;t need to make long-term commitments - you just pay for the service when you use it and you can cancel it anytime when you don&amp;#39;t need it anymore.&lt;/p&gt;

&lt;h3 id=&quot;toc_8&quot;&gt;Try it out&lt;/h3&gt;

&lt;p&gt;If this sounds interesting to you then please &lt;a href=&quot;https://eazybi.com/sign_up&quot;&gt;sign up for eazyBI&lt;/a&gt; and try to upload and analyze your data. And if you have any suggestions or questions about eazyBI then &lt;a href=&quot;mailto:support@eazybi.com&quot;&gt;please let me know&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S.&lt;/strong&gt; Also I wanted to mention that by subscribing to eazyBI you will also support &lt;a href=&quot;https://github.com/rsim&quot;&gt;my work on open-source&lt;/a&gt;. If you are user of my open-source libraries then I will appreciate if you will become eazyBI user as well :) But in case if you do not need solution like eazyBI you could support me by tweeting and blogging about eazyBI, will be thankful for that as well.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Oracle enhanced adapter 1.4.0 and Readme Driven Development</title>
   <link href="http://blog.rayapps.com/2011/08/09/oracle-enhanced-adapter-1-4-0-and-readme-driven-development/"/>
   <updated>2011-08-09T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2011/08/09/oracle-enhanced-adapter-1-4-0-and-readme-driven-development</id>
   <content type="html">&lt;p&gt;I just released &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter&lt;/a&gt; version 1.4.0 and here is the summary of main changes.&lt;/p&gt;

&lt;h3 id=&quot;toc_0&quot;&gt;Rails 3.1 support&lt;/h3&gt;

&lt;p&gt;Oracle enhanced adapter GitHub version was working with Rails 3.1 betas and release candidate versions already but it was not explicitly stated anywhere that you should use git version with Rails 3.1. Therefore I am releasing new version 1.4.0 which is passing all tests with latest Rails 3.1 release candidate. As I &lt;a href=&quot;http://blog.rayapps.com/2011/01/05/oracle-enhanced-adapter-1-3-2-is-released/&quot;&gt;wrote before&lt;/a&gt; main changes in ActiveRecord 3.1 are that it using prepared statement cache and using bind variables in many statements (currently in select by primary key, insert and delete statements) which result in better performance and better database resources usage.&lt;/p&gt;

&lt;p&gt;To follow up how Oracle enhanced adapter is working with different Rails versions and different Ruby implementations I have set up &lt;a href=&quot;http://ci.rayapps.com/job/oracle_enhanced/&quot;&gt;Continuous Integration server&lt;/a&gt; to run tests on different version combinations. At the moment of writing everything was green :)&lt;/p&gt;

&lt;h3 id=&quot;toc_1&quot;&gt;Other bug fixes and improvements&lt;/h3&gt;

&lt;p&gt;Main fixes and improvements in this version are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;On JRuby I switched from using old &lt;code&gt;ojdbc14.jar&lt;/code&gt; JDBC driver to latest &lt;code&gt;ojdbc6.jar&lt;/code&gt; (on Java 6) or &lt;code&gt;ojdbc5.jar&lt;/code&gt; (on Java 5). And JDBC driver can be located in Rails application &lt;code&gt;./lib&lt;/code&gt; directory as well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;RAW&lt;/code&gt; data type is now supported (which is quite often used in legacy databases instead of nowadays recommended &lt;code&gt;CLOB&lt;/code&gt; and &lt;code&gt;BLOB&lt;/code&gt; types).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;rake db:create&lt;/code&gt; and &lt;code&gt;rake db:drop&lt;/code&gt; can be used to create development or test database schemas.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support for virtual columns in improved (only working on Oracle 11g database).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Default table, index, CLOB and BLOB tablespaces can be specified (if your DBA is insisting on putting everything in separate tablespaces :)).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Several improvements for context index additional options and definition dump.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See list of &lt;a href=&quot;https://github.com/rsim/oracle-enhanced/blob/master/History.txt&quot;&gt;all enhancements and bug fixes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to have a new feature in Oracle enhanced adapter then the best way is to implement it by yourself and write some tests for that feature and send me pull request. In this release I have included commits from five new contributors and two existing contributors - so it is not so hard to start contributing to open source!&lt;/p&gt;

&lt;h3 id=&quot;toc_2&quot;&gt;Readme Driven Development&lt;/h3&gt;

&lt;p&gt;One of the worst parts of Oracle enhanced adapter so far was that for new users it was quite hard to understand how to start to use it and what are all additional features that Oracle enhanced adapter provides. There were many blog posts in this blog, there were wiki pages, there were posts in discussion forums. But all this information was in different places and some posts were already outdated and therefore for new users it was hard to understand how to start.&lt;/p&gt;

&lt;p&gt;After &lt;a href=&quot;http://tom.preston-werner.com/2010/08/23/readme-driven-development.html&quot;&gt;reading about Readme Driven Development&lt;/a&gt; and &lt;a href=&quot;http://igniterailsconf.com/speakers/677-matt-parker&quot;&gt;watching presentation about Readme Driven Development&lt;/a&gt; I knew that README of Oracle enhanced adapter was quite bad and should be improved (in my other projects I am already trying to be better but this was my first one :)).&lt;/p&gt;

&lt;p&gt;Therefore I have written &lt;a href=&quot;https://github.com/rsim/oracle-enhanced#readme&quot;&gt;new README of Oracle enhanced adapter&lt;/a&gt; which includes main installation, configuration, usage and troubleshooting tasks which previously was scattered across different other posts. If you find that some important information is missing or outdated then please submit patches to README as well so that it stays up to date and with relevant information.&lt;/p&gt;

&lt;p&gt;If you have any questions please use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;discussion group&lt;/a&gt; or &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/issues&quot;&gt;report issues at GitHub&lt;/a&gt; or post comments here.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Recent conference presentations</title>
   <link href="http://blog.rayapps.com/2011/06/03/recent-conference-presentations/"/>
   <updated>2011-06-03T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2011/06/03/recent-conference-presentations</id>
   <content type="html">&lt;p&gt;Recently I has not posted any new posts as I was busy with some new projects as well as during May attended several conferences and in some I also did presentations. Here I will post slides from these conferences. If you are interested in some of these topics then ask me to come to you as well and talk about these topics :)&lt;/p&gt;
&lt;h3&gt;Agile Riga Day&lt;/h3&gt;
&lt;p&gt;In March I spoke at &lt;a href=&quot;http://www.agilerigaday.lv&quot;&gt;Agile Riga Day&lt;/a&gt; (organized by &lt;a href=&quot;http://www.agile-latvia.org&quot;&gt;Agile Latvia&lt;/a&gt;) about my experience and recommendations how to adopt Agile practices in iterative style.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;width:425px;&quot; id=&quot;__ss_7158771&quot;&gt; &lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/rsim/how-to-adopt-agile-at-your-organization&quot; title=&quot;How to Adopt Agile at Your Organization&quot;&gt;How to Adopt Agile at Your Organization&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/7158771&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt; &lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;RailsConf&lt;/h3&gt;
&lt;p&gt;In May I travelled to &lt;a href=&quot;http://en.oreilly.com/rails2011&quot;&gt;RailsConf&lt;/a&gt; in Baltimore and I hosted traditional &lt;a href=&quot;http://en.oreilly.com/rails2011/public/schedule/detail/19366&quot;&gt;Rails on Oracle&lt;/a&gt; Birds of a Feather session there and gave overview about how to contribute to ActiveRecord Oracle enhanced adapter.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;width:425px&quot; id=&quot;__ss_8004773&quot;&gt; &lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/rsim/rails-on-oracle-2011&quot; title=&quot;Rails on Oracle 2011&quot;&gt;Rails on Oracle 2011&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/8004773&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt; &lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;&lt;span class=&quot;caps&quot;&gt;TAPOST&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Then I participated in our local &lt;a href=&quot;http://www.itbaltic.com/conferences/tapost2011&quot; title=&quot;TAPOST&quot;&gt;Theory and Practice of Software Testing&lt;/a&gt; conference and there I promoted use of Ruby as test scripting language.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;width:425px&quot; id=&quot;__ss_8114164&quot;&gt; &lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/rsim/why-every-tester-should-learn-ruby&quot; title=&quot;Why Every Tester Should Learn Ruby&quot;&gt;Why Every Tester Should Learn Ruby&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/8114164&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;RailsWayCon&lt;/h3&gt;
&lt;p&gt;And lastly I participated in &lt;a href=&quot;http://euruko2011.org&quot;&gt;Euruko&lt;/a&gt; and &lt;a href=&quot;http://railswaycon.com&quot;&gt;RailsWayCon&lt;/a&gt; conferences in Berlin. In RailsWayCon my first presentation was about multidimensional data analysis with JRuby and &lt;a href=&quot;https://github.com/rsim/mondrian-olap&quot;&gt;mondrian-olap&lt;/a&gt; gem. I also published &lt;a href=&quot;https://github.com/rsim/mondrian_demo&quot;&gt;mondrian-olap demo&lt;/a&gt; project that I used during presentation.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;width:425px&quot; id=&quot;__ss_8195174&quot;&gt; &lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/rsim/railswaycon-multidimensional-data-analysis-with-jruby&quot; title=&quot;RailsWayCon: Multidimensional Data Analysis with JRuby&quot;&gt;RailsWayCon: Multidimensional Data Analysis with JRuby&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/8195174&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/div&gt;
&lt;p&gt;And second RailsWayCon presentation was about &lt;a href=&quot;http://jashkenas.github.com/coffee-script&quot;&gt;CoffeeScript&lt;/a&gt;, &lt;a href=&quot;http://documentcloud.github.com/backbone&quot;&gt;Backbone.js&lt;/a&gt; and &lt;a href=&quot;http://pivotal.github.com/jasmine&quot;&gt;Jasmine&lt;/a&gt; that I am recently using to build rich web user interfaces. This was quite successful presentation as there were many questions and also many participants were encouraged to try out CoffeeScript and Backbone.js. I also published my &lt;a href=&quot;https://github.com/rsim/backbone_coffeescript_demo&quot;&gt;demo application&lt;/a&gt; that I used for code samples during presentation.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;span style=&quot;width:425px&quot; id=&quot;__ss_8196890&quot;&gt; &lt;strong style=&quot;display:block;margin:12px 0 4px&quot;&gt;&lt;a href=&quot;http://www.slideshare.net/rsim/railslike-javascript-using-coffeescript-backbonejs-and-jasmine-8196890&quot; title=&quot;Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine&quot;&gt;Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/8196890&quot; width=&quot;425&quot; height=&quot;355&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/div&gt;
&lt;h3&gt;Next conferences&lt;/h3&gt;
&lt;p&gt;Now I will rest for some time from conferences :) But then I will attend &lt;a href=&quot;https://frozenrails.eu&quot;&gt;FrozenRails&lt;/a&gt; in Helsinki and I will present at &lt;a href=&quot;http://www.oracle.com/openworld/index.html&quot;&gt;Oracle OpenWorld&lt;/a&gt; in San Francisco. See you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Oracle enhanced adapter 1.3.2 is released</title>
   <link href="http://blog.rayapps.com/2011/01/05/oracle-enhanced-adapter-1-3-2-is-released/"/>
   <updated>2011-01-05T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2011/01/05/oracle-enhanced-adapter-1-3-2-is-released</id>
   <content type="html">&lt;p&gt;I just released &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter&lt;/a&gt; version 1.3.2 with latest bug fixes and enhancements.&lt;/p&gt;
&lt;h3&gt;Bug fixes and improvements&lt;/h3&gt;
&lt;p&gt;Main fixes and improvements are the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://localhost:4000/2010/09/09/oracle-enhanced-adapter-1-3-1-and-how-to-use-it-with-rails3/&quot;&gt;Previous version 1.3.1&lt;/a&gt; was checking if environment variable TNS_NAME is set and only then used provided &lt;code&gt;database&lt;/code&gt; connection parameter (in &lt;code&gt;database.yml&lt;/code&gt;) as &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; connection alias and otherwise defaulted to connection to &lt;code&gt;localhost&lt;/code&gt; with provided database name. This was causing issues in many setups.&lt;br /&gt;
Therefore now it is simplified that if you provide only &lt;code&gt;database&lt;/code&gt; parameter in &lt;code&gt;database.yml&lt;/code&gt; then it by default will be used as &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; connection alias or &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; connection string.&lt;/li&gt;
	&lt;li&gt;Numeric username and/or password in &lt;code&gt;database.yml&lt;/code&gt; will be automatically converted to string (previously you needed to quote them using &lt;code&gt;&quot;...&quot;&lt;/code&gt;).&lt;/li&gt;
	&lt;li&gt;Database connection pool and &lt;span class=&quot;caps&quot;&gt;JNDI&lt;/span&gt; connections are now better supported for JRuby on Tomcat and JBoss application servers.&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;NLS&lt;/span&gt; connection parameters are supported via environment variables or in &lt;code&gt;database.yml&lt;/code&gt;. For example, if you need to have &lt;code&gt;NLS_DATE_FORMAT&lt;/code&gt; in your database session to be &lt;code&gt;DD-MON-YYYY&lt;/code&gt; then either you specify &lt;code&gt;nls_date_format: DD-MON-YYYY&lt;/code&gt; in &lt;code&gt;database.yml&lt;/code&gt; for particular database connection or set &lt;code&gt;ENV['NLS_DATE_FORMAT'] = 'DD-MON-YYYY'&lt;/code&gt; in e.g. &lt;code&gt;config/initializers/oracle.rb&lt;/code&gt;. You can see the list of all &lt;span class=&quot;caps&quot;&gt;NLS&lt;/span&gt; parameters &lt;a href=&quot;https://github.com/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb#L86-107&quot;&gt;in source code&lt;/a&gt;.&lt;br /&gt;
It might be necessary to specify these &lt;span class=&quot;caps&quot;&gt;NLS&lt;/span&gt; session parameters only if you work with some existing legacy database which has, for example, some stored procedures that require particular &lt;span class=&quot;caps&quot;&gt;NLS&lt;/span&gt; settings. If this is new database just for Rails purposes then there is no need to change any settings.&lt;/li&gt;
	&lt;li&gt;If you have defined foreign key constraints then they are now correctly dumped in &lt;code&gt;db/schema.rb&lt;/code&gt; after all table definitions. Previously they were dumped after corresponding table which sometimes caused that schema could not be recreated from schema dump because it tried to load constraint which referenced table which has not yet been defined.&lt;/li&gt;
	&lt;li&gt;If you are using &lt;code&gt;NCHAR&lt;/code&gt; and &lt;code&gt;NVARCHAR2&lt;/code&gt; data types then now &lt;code&gt;NCHAR&lt;/code&gt; and &lt;code&gt;NVARCHAR2&lt;/code&gt; type values are correctly quoted with &lt;code&gt;N'...'&lt;/code&gt; in &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Upcoming changes in Rails 3.1&lt;/h3&gt;
&lt;p&gt;Meanwhile Oracle enhanced adapter is updated to pass all ActiveRecord unit tests in &lt;a href=&quot;https://github.com/rails/rails&quot;&gt;Rails development master branch&lt;/a&gt; and also updated according to &lt;a href=&quot;https://github.com/rails/arel&quot;&gt;Arel&lt;/a&gt; changes. Arel library is responsible for all &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement generation in Rails 3.0.&lt;/p&gt;
&lt;p&gt;Rails 3.0.3 is using Arel version 2.0 which was full rewrite of Arel 1.0 (that was used initial Rails 3.0 version) and as a result of this rewrite it is much faster and now Rails 3.0.3 ActiveRecord is already little bit faster than in ActiveRecord in Rails 2.3.&lt;/p&gt;
&lt;p&gt;There are several improvements in Rails master branch which are planned for Rails 3.1 version which are already supported by Oracle enhanced adapter. One improvement is that ActiveRecord will support prepared statement caching (initially for standard simple queries like &lt;code&gt;find&lt;/code&gt; by primary key) which will reduce &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement parsing time and memory usage (and probably Oracle DBAs will complain less about Rails dynamic &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; generation :)). The other improvement is that ActiveRecord will correctly load included associations with more than 1000 records (which currently fails with &lt;span class=&quot;caps&quot;&gt;ORA&lt;/span&gt;-01795 error).&lt;/p&gt;
&lt;p&gt;But I will write more about these improvements sometime later when Rails 3.1 will be released :)&lt;/p&gt;
&lt;h3&gt;Install&lt;/h3&gt;
&lt;p&gt;As always you can install Oracle enhanced adapter on any Ruby platform (Ruby 1.8.7 or Ruby 1.9.2 or JRuby 1.5) with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;If you have any questions please use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;discussion group&lt;/a&gt; or &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/issues&quot;&gt;report issues at GitHub&lt;/a&gt; or post comments here. And the best way how to contribute is to fix some issue or create some enhancement and send me pull request at &lt;a href=&quot;https://github.com/rsim/oracle-enhanced&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql-spec upgraded to use RSpec 2.0</title>
   <link href="http://blog.rayapps.com/2010/10/22/ruby-plsql-spec-upgraded-to-use-rspec-20/"/>
   <updated>2010-10-22T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2010/10/22/ruby-plsql-spec-upgraded-to-use-rspec-20</id>
   <content type="html">&lt;p&gt;Initial version of &lt;a href=&quot;http://blog.rayapps.com/2010/10/05/ruby-plsql-spec-gem-and-code-coverage-reporting/&quot;&gt;ruby-plsql-spec gem&lt;/a&gt; was using RSpec version 1.3. But recently &lt;a href=&quot;http://blog.davidchelimsky.net/2010/10/10/rspec-200-is-released/&quot;&gt;RSpec 2.0 was released&lt;/a&gt; which &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; is not compatible with previous RSpec 1.x &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and as a result &lt;code&gt;plsql-spec&lt;/code&gt; utility was failing if just RSpec was upgraded to version 2.0.&lt;/p&gt;
&lt;p&gt;Therefore I updated also ruby-plsql-spec to use latest RSpec 2.0 gem and released &lt;strong&gt;ruby-plsql-spec gem version 0.2.1&lt;/strong&gt;. You can install the latest version with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install ruby-plsql-spec&lt;/pre&gt;
&lt;h3&gt;Upgrade from previous version&lt;/h3&gt;
&lt;p&gt;If you previously already installed initial ruby-plsql-spec version 0.1.0 then you need to update your &lt;code&gt;spec/spec_helper.rb&lt;/code&gt; file to use RSpec 2.0. You can do it by running one more time&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;plsql-spec init&lt;/pre&gt;
&lt;p&gt;which will check which current files are different from the latest templates. You need to update just spec_helper.rb file. When you will be prompted to overwrite spec_helper.rb file then at first you can enter &lt;code&gt;d&lt;/code&gt; to see differences between current file and new template. If you have not changed original spec_helper.rb file then you will see just one difference&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;
- Spec::Runner.configure do |config|
+ RSpec.configure do |config|
&lt;/pre&gt;
&lt;p&gt;You can then answer &lt;code&gt;y&lt;/code&gt; and this file will be updated. When you will be prompted to overwrite other files then you can review the changes in the same way and decide if you want them to be overwritten or not (e.g. do not overwrite &lt;code&gt;database.yml&lt;/code&gt; file as it has your specific database connection settings).&lt;/p&gt;
&lt;h3&gt;&lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; output option&lt;/h3&gt;
&lt;p&gt;In addition &lt;code&gt;plsql-spec&lt;/code&gt; utility now has &lt;code&gt;--html&lt;/code&gt; option which will generate test results report as &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; report. It might be useful for usage in text editors where you can define which command line utility to run when pressing some shortcut key and then display generated &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; output report. If you will execute&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;plsql-spec run --html&lt;/pre&gt;
&lt;p&gt;then it will generate &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; report in &lt;code&gt;test-results.html&lt;/code&gt; file. You can override this file name as well using &lt;code&gt;--html output_file_name.html&lt;/code&gt; option.&lt;/p&gt;
&lt;h3&gt;Questions or suggestions&lt;/h3&gt;
&lt;p&gt;If you have any other feature suggestions or questions about ruby-plsql-spec then please post comments here or report any bugs at &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec/issues&quot;&gt;GitHub issues&lt;/a&gt; page.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql-spec gem and code coverage reporting</title>
   <link href="http://blog.rayapps.com/2010/10/05/ruby-plsql-spec-gem-and-code-coverage-reporting/"/>
   <updated>2010-10-05T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2010/10/05/ruby-plsql-spec-gem-and-code-coverage-reporting</id>
   <content type="html">&lt;p&gt;During recent Oracle OpenWorld conference I presented session &lt;a href=&quot;http://www.slideshare.net/rsim/plsql-unit-testing-can-be-fun&quot;&gt;PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing can be fun!&lt;/a&gt; where I demonstrated how to do &lt;a href=&quot;http://blog.rayapps.com/2009/11/27/oracle-plsql-unit-testing-with-ruby/&quot;&gt;PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing with Ruby&lt;/a&gt;:&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;object id=&quot;__sse5251535&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=plsqlunittestingcanbefun-100921132711-phpapp02&amp;rel=0&amp;stripped_title=plsql-unit-testing-can-be-fun&amp;userName=rsim&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed name=&quot;__sse5251535&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=plsqlunittestingcanbefun-100921132711-phpapp02&amp;rel=0&amp;stripped_title=plsql-unit-testing-can-be-fun&amp;userName=rsim&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;p&gt;Audience was quite interested and had a lot of questions and therefore it motivated me to do some more improvements to ruby-plsql-spec to make it easier for newcomers.&lt;/p&gt;
&lt;h3&gt;ruby-plsql-spec gem and plsql-spec command line utility&lt;/h3&gt;
&lt;p&gt;Initially &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec&quot;&gt;ruby-plsql-spec&lt;/a&gt; was just repository of sample tests and if you wanted to start to use it in your project you had to manually pick necessary files and copy them to your project directory.&lt;/p&gt;
&lt;p&gt;Now ruby-plsql-spec is released as a gem which includes all necessary dependencies (except ruby-oci8 which you should install if using &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; Ruby implementation) and you can install it with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install ruby-plsql-spec&lt;/pre&gt;
&lt;p&gt;See more information about installation in &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec/blob/master/README.markdown&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;&lt;/a&gt; file or see specific &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec/blob/master/INSTALL-Windows.markdown&quot;&gt;installation instructions on Windows&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When you have installed ruby-plsql-spec gem and want to start to use it in your existing project then go to your project directory and from command line execute&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;plsql-spec init&lt;/pre&gt;
&lt;p&gt;It will create &lt;code&gt;spec&lt;/code&gt; subdirectory in current directory where all initial supporting files will be created. The main configuration file which should be updated is &lt;code&gt;spec/database.yml&lt;/code&gt; where you should specify username, password and database connection string that should be used when running tests:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;default:
  username: hr
  password: hr
  database: orcl
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you specify just &lt;code&gt;database:&lt;/code&gt; name then it will be used as &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; connection string (and TNS_ADMIN environment variable should point to directory where tnsnames.ora file is located) or you can also provide &lt;code&gt;hostname:&lt;/code&gt; and if necessary also &lt;code&gt;port:&lt;/code&gt; parameters and then you can connect to database without tnsnames.ora file.&lt;/p&gt;
&lt;p&gt;Now you can start to create your tests in &lt;code&gt;spec&lt;/code&gt; directory and your tests file names should end with &lt;code&gt;_spec.rb&lt;/code&gt;. You can see some examples at &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec/tree/master/examples/spec/&quot;&gt;ruby-plsql-spec examples directory&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To validate your installation you can try to create simple dummy test in &lt;code&gt;spec/dummy_spec.rb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;spec_helper&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;test installation&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should get SYSDATE&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysdate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NULL&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And now from command line you can try to run your test with:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;plsql-spec run&lt;/pre&gt;
&lt;p&gt;If everything is fine you should see something similar like this:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;Running all specs from spec/
.

Finished in 0.033782 seconds

1 example, 0 failures&lt;/pre&gt;
&lt;h3&gt;Code coverage reporting&lt;/h3&gt;
&lt;p&gt;During my Oracle OpenWorld presentation I also showed how to get PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; code coverage report (which shows which PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; code lines were executed during tests run). It might be useful when you want to identify which existing PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; code is not yet covered by unit tests.&lt;/p&gt;
&lt;p&gt;Now code coverage reporting is even easier with new ruby-plsql-spec gem. It uses Oracle database &lt;a href=&quot;http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_profil.htm&quot;&gt;DBMS_PROFILER&lt;/a&gt; package to collect code coverage information and I took &lt;a href=&quot;http://github.com/relevance/rcov&quot;&gt;rcov&lt;/a&gt; reports &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; files to present results (so that they would be very similar to Ruby code coverage reports).&lt;/p&gt;
&lt;p&gt;To try code coverage reporting let&amp;#8217;s create simple PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; function:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_profiler&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test_profiler&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;EXCEPTION&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OTHERS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;others&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and simple test to verify code coverage reporting:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;spec_helper&amp;quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;test code coverage&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should get result&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_profiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test_profiler&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And now you can run tests with &lt;code&gt;--coverage&lt;/code&gt; option which will produce code coverage report:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;plsql-spec run --coverage&lt;/pre&gt;
&lt;p&gt;As a result code coverage reports are created in &lt;code&gt;coverage/&lt;/code&gt; subdirectory. Open &lt;code&gt;coverage/index.html&lt;/code&gt; in your browser and click on &lt;code&gt;TEST_PROFILER&lt;/code&gt; function and you should see something similar like this report:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://blog.rayapps.com/images/test_profiler.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can see that &lt;code&gt;RETURN 'test_profiler';&lt;/code&gt; line (with green background) was executed by test but &lt;code&gt;RETURN 'others';&lt;/code&gt; line (with red background) was not. Lines with light background are ignored by DBMS_PROFILER and I do not take them into account when calculating code coverage percentage (but they are taken into account when calculating total coverage percentage).&lt;/p&gt;
&lt;h3&gt;Questions or feedback&lt;/h3&gt;
&lt;p&gt;If you have any other questions about using ruby-plsql-spec for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing then please post comments here or if you find any issues when using ruby-plsql-spec then please report them at &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec/issues&quot;&gt;GitHub issues&lt;/a&gt; page.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Oracle enhanced adapter 1.3.1 and how to use it with Rails 3</title>
   <link href="http://blog.rayapps.com/2010/09/09/oracle-enhanced-adapter-1-3-1-and-how-to-use-it-with-rails3/"/>
   <updated>2010-09-09T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2010/09/09/oracle-enhanced-adapter-1-3-1-and-how-to-use-it-with-rails3</id>
   <content type="html">&lt;p&gt;Rails 3.0 was &lt;a href=&quot;http://weblog.rubyonrails.org/2010/8/29/rails-3-0-it-s-done&quot;&gt;released recently&lt;/a&gt; and therefore I am releasing new &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter&lt;/a&gt; version 1.3.1 which is tested and updated against latest Rails 3.0.0 version. You can read about &lt;a href=&quot;http://blog.rayapps.com/2010/06/21/oracle-enhanced-adapter-1-3-0-is-rails-3-compatible/&quot;&gt;main changes in oracle_enhanced adapter for Rails 3 support&lt;/a&gt; in my previous blog post. Latest version 1.3.1 mainly contains several bug fixes (which you can find in &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/blob/master/History.txt&quot;&gt;change log&lt;/a&gt; as well as in detailed commit list) as well as several new features that I will describe here.&lt;/p&gt;
&lt;h3&gt;Usage with Rails 3&lt;/h3&gt;
&lt;p&gt;I have improved a little bit configuration and loading of oracle_enhanced adapter in Rails 3 and here are the initial steps that you should do to use oracle_enhanced adapter in Rails 3 application. I assume that you are using latest Rails 3.0.0 version as well as latest Bundler 1.0.0 version.&lt;/p&gt;
&lt;p&gt;At first you need to include necessary gems in Gemfile of your application:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby-oci8&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;~&amp;gt; 2.0.4&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;activerecord-oracle_enhanced-adapter&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;~&amp;gt; 1.3.1&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;It is recommended to use &lt;code&gt;~&amp;gt; version&lt;/code&gt; (requires specified version or later minor version update where only the last digit of version has changed) or &lt;code&gt;= version&lt;/code&gt; in your Gemfile and not &lt;code&gt;&amp;gt;=&lt;/code&gt; (which might include major version changes). In this way you ensure that your application will not break when major &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; changes will happen in gem that you are using.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you want to run your application both on &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; and JRuby then you can specify&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;platforms&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ruby&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby-oci8&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;~&amp;gt; 2.0.4&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;which will load ruby-oci8 gem only when using &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8 or 1.9 and not when using JRuby.&lt;/p&gt;
&lt;p&gt;If you would like to use the latest development version of oracle_enhanced then change Gemfile to:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;activerecord-oracle_enhanced-adapter&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;~&amp;gt; 1.3.1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;git://github.com/rsim/oracle-enhanced.git&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you will use also ruby-plsql gem in your application then include as well (and specify version as needed)&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;ruby-plsql&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;~&amp;gt; 0.4.3&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After these changes in Gemfile run &lt;code&gt;bundle update&lt;/code&gt; to install necessary gems and generate corresponding Gemfile.lock.&lt;/p&gt;
&lt;p&gt;If you want to use all default oracle_enhanced settings then you need just to specify your database connection in &lt;code&gt;database.yml&lt;/code&gt;, for example, something like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;development:
  adapter: oracle_enhanced
  database: orcl
  username: user
  password: secret
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and you can start to use Rails with Oracle database. If you would like to change some oracle_enhanced adapter settings then it is recommended to create initializer file &lt;code&gt;config/initializers/oracle.rb&lt;/code&gt; where you can specify necessary defaults, for example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;on_load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:active_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_eval&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_integers_by_column_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_dates_by_column_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_booleans_from_strings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# to ensure that sequences will start from 1 and without gaps&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_sequence_start_value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;1 NOCACHE INCREMENT BY 1&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# other settings ...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It is important to use &lt;code&gt;ActiveSupport.on_load(:active_record)&lt;/code&gt; as Rails 3 does lazy loading of all components and we need to ensure that oracle_enhanced adapter defaults are set only after ActiveRecord is loaded.&lt;/p&gt;
&lt;p&gt;You can take a look at &lt;a href=&quot;http://github.com/rsim/rails3_oracle_sample&quot;&gt;sample Rails 3 application on Oracle&lt;/a&gt; to see sample configuration files that I mentioned here.&lt;/p&gt;
&lt;h3&gt;Database connection options&lt;/h3&gt;
&lt;p&gt;There are several ways how to specify database connection in &lt;code&gt;database.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;h4&gt;Using tnsnames.ora file with &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; aliases&lt;/h4&gt;
&lt;p&gt;If you are using &lt;a href=&quot;http://www.orafaq.com/wiki/Tnsnames.ora&quot;&gt;tnsnames.ora&lt;/a&gt; file with &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; names and connection descriptions then you need to set TNS_ADMIN environment variable to point to directory where tnsnames.ora file is located. If oracle_enhanced adapter will detect that &lt;span class=&quot;caps&quot;&gt;ENV&lt;/span&gt;[&amp;#8216;TNS_ADMIN&amp;#8217;] is not empty then it will try to use &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; name in :database parameter to connect to database. So in this case in &lt;code&gt;database.yml&lt;/code&gt; you need to specify:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;development:
  adapter: oracle_enhanced
  database: connection_name_from_tnsnames
  username: user
  password: secret
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Connection using tnsnames is supported both for &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; with ruby-oci8 as well as for JRuby with &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt;. Use this option if you would not like to hardcode database server address, port and database name in your application and want to specify separately in &lt;code&gt;tnsnames.ora&lt;/code&gt; file.&lt;/p&gt;
&lt;h4&gt;Using &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;port&lt;/code&gt; and &lt;code&gt;database&lt;/code&gt; option&lt;/h4&gt;
&lt;p&gt;If you do not want to create separate tnsnames.ora file and want to specify database server, port and database name directly in application, then you can specify these options separately in &lt;code&gt;database.yml&lt;/code&gt; file, for example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;development:
  adapter: oracle_enhanced
  host: localhost
  port: 1521
  database: orcl
  username: user
  password: secret
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;port&lt;/code&gt; default value is 1521 and can be omitted. It is also possible to specify host, port and database name is Oracle specific format in &lt;code&gt;database&lt;/code&gt; option:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;development:
  adapter: oracle_enhanced
  database: //localhost:1521/orcl
  username: user
  password: secret
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It is also possible to specify &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; connection description directly in &lt;code&gt;database.yml&lt;/code&gt; file (if you do not want to create separate &lt;code&gt;tnsnames.ora&lt;/code&gt; file), for example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;development:
  adapter: oracle_enhanced
  database: &amp;quot;(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=orcl)))&amp;quot;
  username: user
  password: secret
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;Using &lt;span class=&quot;caps&quot;&gt;JNDI&lt;/span&gt; connections in JRuby&lt;/h4&gt;
&lt;p&gt;If you deploy your JRuby application in Java application server that supports &lt;span class=&quot;caps&quot;&gt;JNDI&lt;/span&gt; connections then it is possible to specify also &lt;span class=&quot;caps&quot;&gt;JNDI&lt;/span&gt; connection in &lt;code&gt;database.yml&lt;/code&gt; file, for example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oracle_enhanced&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;jndi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;jdbc/jndi_connection_name&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I am not using this connection option but some oracle_enhanced users are using it.&lt;/p&gt;
&lt;h3&gt;Contributing to oracle_enhanced adapter&lt;/h3&gt;
&lt;p&gt;If you experience any issues with oracle_enhanced adapter then please report issues at &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/issues&quot;&gt;GitHub issue tracker&lt;/a&gt; or discuss them at &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;oracle_enhanced discussion group&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But even better if you want some new feature in oracle_enhanced adapter then fork &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;oracle_enhanced git repository&lt;/a&gt; and make your changes and send me pull requests for review.&lt;/p&gt;
&lt;p&gt;For all changes please add also RSpec tests as well as verify if all existing tests are passing after your changes. I added &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/blob/master/RUNNING_TESTS.rdoc&quot;&gt;description how to set up environment for running tests&lt;/a&gt; &amp;#8211; please let me know if something is missing there.&lt;/p&gt;
&lt;p&gt;Big thanks to &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/raw/master/README.rdoc&quot;&gt;all contributors&lt;/a&gt; who have submitted patches so far :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Moving blog from wordpress.com to Jekyll</title>
   <link href="http://blog.rayapps.com/2010/08/09/moving-blog-from-wordpress-com-to-jekyll/"/>
   <updated>2010-08-09T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2010/08/09/moving-blog-from-wordpress-com-to-jekyll</id>
   <content type="html">&lt;div style=&quot;float:right; margin-left:10px;&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/jekyll.png&quot; title=&quot;Jekyll&quot; alt=&quot;Jekyll&quot; /&gt;&lt;/div&gt;
&lt;h3&gt;Why to move?&lt;/h3&gt;
&lt;p&gt;This blog was hosted for several years on wordpress.com as it was the easiest way to host a blog when I started. But recently I was not very satisfied with it because of the following reasons:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;I include code snippets in my blog posts quite often and several times I had issues with code formatting on wordpress.com. I used MarsEdit to upload blog posts but when I read previous posts back then quite often my &amp;lt; and &amp;gt; symbols were replaced with &amp;amp;lt; and &amp;amp;gt;.&lt;/li&gt;
	&lt;li&gt;I would prefer to write my posts in Textile and not in plain &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; (I think it could be possible also with wordpress.com but it was not obvious to me).&lt;/li&gt;
	&lt;li&gt;I didn&amp;#8217;t quite like &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; design of my site and wanted to improve it but I prefer minimalistic &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; stylesheets and didn&amp;#8217;t want to learn how to do design &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; specific for Wordpress sites.&lt;/li&gt;
	&lt;li&gt;Wordpress site was too mainstream, I wanted something more geeky :)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When I do web app development then I use &lt;a href=&quot;http://macromates.com/&quot;&gt;TextMate&lt;/a&gt; for &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; / &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; and Ruby editing (sometime I use &lt;a href=&quot;http://macrabbit.com/cssedit/&quot;&gt;CSSEdit&lt;/a&gt; when I need to do more &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; editing), I use &lt;a href=&quot;http://redcloth.org/hobix.com/textile/&quot;&gt;Textile&lt;/a&gt; for wiki-style content editing in my apps, I use &lt;a href=&quot;http://git-scm.com/&quot;&gt;git&lt;/a&gt; for version control, I use Ruby rake for build and deployment tasks. Wouldn&amp;#8217;t it be great if I could use the same toolset for writing my blog?&lt;/p&gt;
&lt;h3&gt;What is Jekyll?&lt;/h3&gt;
&lt;p&gt;I had heard about &lt;a href=&quot;http://github.com/mojombo/jekyll&quot;&gt;Jekyll&lt;/a&gt; blogging tool several times and now I decided that it is the time to start to use it. Jekyll was exactly matching my needs:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You can write blog posts in Textile (or in Markdown)&lt;/li&gt;
	&lt;li&gt;You can design &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; templates and &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; stylesheets as you want and use &lt;a href=&quot;http://www.liquidmarkup.org/&quot;&gt;Liquid&lt;/a&gt; to embed dynamic content&lt;/li&gt;
	&lt;li&gt;You can store all blog content in git repository (or in any other version control system that you like)&lt;/li&gt;
	&lt;li&gt;And finally you use jekyll Ruby gem to generate static &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; files that can be hosted anywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So it sounds quite easy and cool therefore I started migration.&lt;/p&gt;
&lt;h3&gt;Migration&lt;/h3&gt;
&lt;h4&gt;Initial setup&lt;/h4&gt;
&lt;p&gt;I started my new blog repository using canonical &lt;a href=&quot;http://github.com/mojombo/mojombo.github.com&quot;&gt;example site from Jekyll&amp;#8217;s creator&lt;/a&gt;. You just need to remove posts from _posts directory and start to create your own.&lt;/p&gt;
&lt;h4&gt;Export from wordpress.com&lt;/h4&gt;
&lt;p&gt;At first I needed to export all my existing posts from wordpress.com. I found &lt;a href=&quot;http://gist.github.com/268428&quot;&gt;helpful script&lt;/a&gt; which processes wordpress.com export and creates Textile source files for Jekyll as well as comments import file for Disqus (more about that later). It did quite good job but I needed anyway to go manually through all posts to do the following changes:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;I needed to manually change &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; source for lists to Textile formatted lists (export file conversion script converted just headings to Textile formatting) as otherwise they were not looking good when parsed by Textile formatting.&lt;/li&gt;
	&lt;li&gt;I needed to wrap all code snippets with Jekyll code highlighting tags (which uses Pygments tool to generate &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;) &amp;#8211; as previously I had not used consistent formatting style I could not do that by global search &amp;amp; replace.&lt;/li&gt;
	&lt;li&gt;I needed to download all uploaded images from wordpress.com and put them in &lt;code&gt;images&lt;/code&gt; directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; design&lt;/h4&gt;
&lt;p&gt;As I wanted to create more simple and maintainable &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; stylesheets I didn&amp;#8217;t just copy previous &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; files but manually picked just the parts I needed. And now as I had full control over &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; I spent a lot of time improving my previous design (font sizes, margins, paddings etc.) &amp;#8211; but now at least I am more satisfied with it :)&lt;/p&gt;
&lt;h4&gt;Tags&lt;/h4&gt;
&lt;p&gt;As all final generated pages are static there is no standard way how to do typical dynamic pages like list of posts with selected tag. But the good thing is that I can create &lt;code&gt;rake&lt;/code&gt; tasks that can re-generate all dynamic pages as static pages whenever I do some changes to original posts. I found some examples that I used to create &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/Rakefile#L30-87&quot;&gt;my rake tasks for tag pages and tag cloud&lt;/a&gt; generation.&lt;/p&gt;
&lt;h4&gt;Related pages&lt;/h4&gt;
&lt;p&gt;Previously wordpress.com was showing some automatically generated related posts for each post. Initially it was not quite obvious how to do it (as &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/_layouts/post.html#L19-26&quot;&gt;site.related_posts&lt;/a&gt; was always showing the latest posts). Then I found that I need to turn on &lt;code&gt;lsi&lt;/code&gt; option and in addition install &lt;a href=&quot;http://www.gnu.org/software/gsl/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;GSL&lt;/span&gt;&lt;/a&gt; library (I installed it with &lt;a href=&quot;http://github.com/mxcl/homebrew&quot;&gt;homebrew&lt;/a&gt;) and &lt;a href=&quot;http://rb-gsl.rubyforge.org/&quot;&gt;RubyGSL&lt;/a&gt; (as otherwise related posts generation was very slow).&lt;/p&gt;
&lt;h4&gt;Comments&lt;/h4&gt;
&lt;p&gt;The next issue is that in static &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; site you cannot store comments and you need to use some hosted commenting system. The most frequently commenting system in Jekyll sites is &lt;a href=&quot;http://disqus.com&quot;&gt;Disqus&lt;/a&gt; and therefore I decided to use it as well. It took some time to understand how it works but it provides all necessary &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; snippets that you need to include in your layout templates and then it just works.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://gist.github.com/268428&quot;&gt;Previously mentioned script&lt;/a&gt; also included possibility to import my existing comments from wordpress.com into Disqus. But that was not quite as easy as I hoped:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Disqus &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; that allows to add comments to existing post that is found by &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; is not creating new discussion threads if they do not exist. Therefore I needed at first to open all existing pages to create corresponding Disqus discussion threads.&lt;/li&gt;
	&lt;li&gt;As in static &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; case I do not have any post identifiers that could be used as discussion thread identifiers I need to ensure that my new URLs of blog posts are exactly the same as the old ones (in my case I needed to &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/_config.yml#L3&quot;&gt;add / at the end of URLs&lt;/a&gt; as &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; without ending / will be considered as different &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; by Disqus).&lt;/li&gt;
	&lt;li&gt;There was issue that some comments in export file had wrong date in &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; (it was in cases when draft of post was prepared earlier than post was published) and I needed to fix that in export file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So be prepared that you will need to import and then delete imported comments several times :)&lt;/p&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; / Atom feeds&lt;/h4&gt;
&lt;p&gt;If you have existing subscribers to your &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; or Atom feed then you either need to use the same &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; for new feed as well or to redirect it to the new feed &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;. In my case I created new Feedburner feed and &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/.htaccess#L4-7&quot;&gt;redirected old feed &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; to the new one in .htaccess file&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Other &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; mappings&lt;/h4&gt;
&lt;p&gt;In my case I renamed &lt;code&gt;categories&lt;/code&gt; to &lt;code&gt;tags&lt;/code&gt; in my blog posts and URLs but as these old category URLs were indexed by Google and were showing on to Google search results I &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/.htaccess#L4-7&quot;&gt;redirected them as well in .htaccess file&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Search&lt;/h4&gt;
&lt;p&gt;If you want to allow search in your blog then the easiest way is just to add Google search box with &lt;code&gt;sitesearch&lt;/code&gt; parameter.&lt;/p&gt;
&lt;h4&gt;Analytics&lt;/h4&gt;
&lt;p&gt;Previously I used standard wordpress.com analytics pages to review statistics, now I added &lt;a href=&quot;http://www.google.com/analytics&quot;&gt;Google Analytics&lt;/a&gt; for that purpose.&lt;/p&gt;
&lt;h3&gt;Deployment&lt;/h3&gt;
&lt;p&gt;Finally after all migration tasks I was ready to deploy my blog into production. As I had account at &lt;a href=&quot;http://www.dreamhost.com/&quot;&gt;Dreamhost&lt;/a&gt; I decided that it is good enough for static &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; hosting.&lt;/p&gt;
&lt;p&gt;I created &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/Rakefile#L1-28&quot;&gt;rake tasks for deployment&lt;/a&gt; that use rsync for file transfer and now I can just do &lt;code&gt;rake deploy&lt;/code&gt; to generate the latest version of site and transfer it to hosting server.&lt;/p&gt;
&lt;p&gt;After that I needed to remap &lt;span class=&quot;caps&quot;&gt;DNS&lt;/span&gt; name of blog.rayapps.com to new location and wait for several hours until this change propogated over Internet.&lt;/p&gt;
&lt;h3&gt;Additional &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; generation speed improvements&lt;/h3&gt;
&lt;p&gt;When I was doing regular &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; re-generation using &lt;code&gt;jekyll&lt;/code&gt; I noticed that it started to get quite slow. After investigation I found out that the majority of time went on Pygments execution for code highlighting. To fix this issue I found jekyll patches that implemented Pygments results caching and I added it as &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com/blob/master/_plugins/pygments_cache_patch.rb&quot;&gt;&amp;#8216;monkey patch&amp;#8217; to my repository&lt;/a&gt; (it stores cached results in &lt;code&gt;_cache&lt;/code&gt; directory). After this patch my &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; re-generation happens instantly.&lt;/p&gt;
&lt;h3&gt;My blog repository&lt;/h3&gt;
&lt;p&gt;I published &lt;a href=&quot;http://github.com/rsim/blog.rayapps.com&quot;&gt;&amp;#8216;source code&amp;#8217; of my blog on GitHub&lt;/a&gt; so you can use it as example if I convinced you to migrate to Jekyll as well :)&lt;/p&gt;
&lt;p&gt;The whole process took several days but now I am happy with my new &amp;#8220;geek blogging platform&amp;#8221; and can recommend it to others as well.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Oracle enhanced adapter 1.3.0 is Rails 3 compatible</title>
   <link href="http://blog.rayapps.com/2010/06/21/oracle-enhanced-adapter-1-3-0-is-rails-3-compatible/"/>
   <updated>2010-06-21T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2010/06/21/oracle-enhanced-adapter-1-3-0-is-rails-3-compatible</id>
   <content type="html">&lt;p&gt;Rails 3 is in final finishing stage (currently in beta4) and therefore I released new &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter&lt;/a&gt; version 1.3.0 which I was working on during last months.&lt;/p&gt;
&lt;h3&gt;Rails 3 compatibility&lt;br /&gt;
&lt;img src=&quot;http://blog.rayapps.com/images/rails3.gif&quot; alt=&quot;rails3.gif&quot; border=&quot;0&quot; width=&quot;150&quot; height=&quot;112&quot; style=&quot;float:right;padding-left:20px;&quot; /&gt;&lt;/h3&gt;
&lt;p&gt;The major enhancement is that Oracle enhanced adapter is now compatible with Rails 3. To achieve that I also developed Oracle &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; compiler for &lt;a href=&quot;http://github.com/rails/arel&quot;&gt;Arel&lt;/a&gt; gem which is used now by ActiveRecord to generate &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements. When using Oracle enhanced adapter with Rails 3 you will notice several major changes:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Table and column names are always quoted and in uppercase to avoid the need for checking Oracle reserved words.&lt;br /&gt;
E.g. now &lt;code&gt;Post.all&lt;/code&gt; will generate query &lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;POSTS&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;POSTS&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
	&lt;li&gt;Better support for limit and offset options (when possible just &lt;span class=&quot;caps&quot;&gt;ROWNUM&lt;/span&gt; condition in &lt;span class=&quot;caps&quot;&gt;WHERE&lt;/span&gt; clause is used without using subqueries).&lt;br /&gt;
E.g. &lt;code&gt;Post.first&lt;/code&gt; (or &lt;code&gt;Post.limit(1)&lt;/code&gt;) will generate query &lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;POSTS&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;POSTS&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROWNUM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt; but &lt;code&gt;Post.limit(1).offset(1)&lt;/code&gt; will generate &lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw_sql_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rownum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw_rnum_&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;EMPLOYEES&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;&amp;quot;EMPLOYEES&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw_sql_&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rownum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw_rnum_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When using Oracle enhanced adapter with current version of Rails 3 and Arel it is necessary to turn on table and column caching option in all environments as otherwise Arel gem will cause very many &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; queries on data dictionary tables on each request. To achieve that you need to include in some initializer file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache_columns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I have published simple &lt;a href=&quot;http://github.com/rsim/rails3_oracle_sample&quot;&gt;Rails 3 demo application&lt;/a&gt; using Rails 3 and Oracle enhanced adapter. You can take a look at &lt;a href=&quot;http://github.com/rsim/rails3_oracle_sample/blob/master/Gemfile&quot;&gt;Gemfile&lt;/a&gt; and &lt;a href=&quot;http://github.com/rsim/rails3_oracle_sample/blob/master/config/initializers/oracle.rb&quot;&gt;Oracle initializer file&lt;/a&gt; to see examples how to configure Oracle enhanced adapter with Rails 3.&lt;/p&gt;
&lt;h3&gt;Rails 2.3 compatibility&lt;/h3&gt;
&lt;p&gt;Oracle enhanced adapter version 1.3.0 is still compatible with Rails 2.3 (I am testing it against Rails 2.3.5 and 2.3.8) and it is recommended to upgrade if you are on Rails 2.3 and plan to upgrade to Rails 3.0 later. But if you are still on Rails 2.2 or earlier then there might be issues with Oracle enhanced adapter 1.3.0 as I am using some Rails methods which appeared just in Rails 2.3 &amp;#8211; so in this case it might be safer to stay on previous Oracle enhanced adapter version 1.2.4 until you upgrade to latest Rails version.&lt;/p&gt;
&lt;h3&gt;Oracle &lt;span class=&quot;caps&quot;&gt;CONTEXT&lt;/span&gt; index support&lt;/h3&gt;
&lt;p&gt;Every edition of Oracle database includes &lt;a href=&quot;http://www.oracle.com/technology/products/text/index.html&quot;&gt;Oracle Text&lt;/a&gt; option for free which provides different full text indexing capabilities. Therefore in Oracle database case you don&amp;#8217;t need external full text indexing and searching engines which can simplify your application deployment architecture.&lt;/p&gt;
&lt;p&gt;The most commonly used index type is &lt;span class=&quot;caps&quot;&gt;CONTEXT&lt;/span&gt; index which can be used for efficient full text search. Most of &lt;span class=&quot;caps&quot;&gt;CONTEXT&lt;/span&gt; index creation examples show how to create simple full text index on one table and one column. But if you want to create more complex full text indexes on multiple columns or even on multiple tables and columns then you need to write your custom procedures and custom index refreshing logic.&lt;/p&gt;
&lt;p&gt;Therefore to make creation of more complex full text indexes easier I have created additional add_context_index and remove_context_index methods that can be used in migrations and which creates additional stored procedures and triggers when needed in standardized way.&lt;/p&gt;
&lt;p&gt;This is how you can create simple single column index:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add_context_index&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And you can perform search using this index with&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;word&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This is how you create index on several columns (which will generate additional stored procedure for providing &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; document with specified columns to indexer):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add_context_index&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And you can search either in all columns or specify in which column you want to search (as first argument you need to specify first column name as this is the column which is referenced during index creation):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;word&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;word within title&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;word within body&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;See Oracle Text documentation for syntax that you can use in &lt;span class=&quot;caps&quot;&gt;CONTAINS&lt;/span&gt; function in &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;WHERE&lt;/span&gt; clause.&lt;/p&gt;
&lt;p&gt;You can also specify some dummy main column name when creating multiple column index as well as specify to update index automatically after each commit (as otherwise you need to synchronize index manually or schedule periodic update):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add_context_index&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index_column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:sync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ON COMMIT&amp;#39;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;word&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Or you can specify that index should be updated when specified columns are updated (e.g. in ActiveRecord you can specify to trigger index update when created_at or updated_at columns are updated). Otherwise index is updated only when main index column is updated.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add_context_index&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index_column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:sync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ON COMMIT&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index_column_trigger_on&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:updated_at&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And you can even create index on multiple tables by providing &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; statements which should be used to fetch necessary columns from related tables:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;add_context_index&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:posts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# specify aliases always with AS keyword&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&amp;quot;SELECT comments.author AS comment_author, comments.body AS comment_body FROM comments WHERE comments.post_id = :id&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;post_and_comments_index&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:index_column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:index_column_trigger_on&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:updated_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:comments_count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:sync&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ON COMMIT&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# search in any table columns&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;word&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# search in specified column&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;aaa within title&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;bbb within comment_author&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In terms of Oracle Text performance in most cases it is good enough (typical response in not more that hundreds of milliseconds). But from my experience it is still slower compared to dedicated full text search engines like Sphinx. So in case if Oracle Text performance is not good enough (if you need all search operations return in tens of milliseconds) then you probably need to evaluate dedicated search engines like Sphinx or Lucene.&lt;/p&gt;
&lt;h3&gt;Other changes&lt;/h3&gt;
&lt;p&gt;Please see &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/blob/master/History.txt&quot;&gt;change history file&lt;/a&gt; or &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/commits/master&quot;&gt;commit list&lt;/a&gt; to see more detailed list of changes in this version.&lt;/p&gt;
&lt;h3&gt;Install&lt;/h3&gt;
&lt;p&gt;As always you can install Oracle enhanced adapter on any Ruby platform (Ruby 1.8.7 or Ruby 1.9.1/1.9.2 or JRuby) with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;If you have any questions please use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;discussion group&lt;/a&gt; or &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/issues&quot;&gt;report issues at GitHub&lt;/a&gt; or post comments here.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Please vote for my Ruby session proposals at Oracle OpenWorld</title>
   <link href="http://blog.rayapps.com/2010/06/17/please-vote-for-my-ruby-session-proposals-at-oracle-openworld/"/>
   <updated>2010-06-17T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2010/06/17/please-vote-for-my-ruby-session-proposals-at-oracle-openworld</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.oracle.com/us/openworld/index.htm&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/oow2010.png&quot; alt=&quot;oow2010.png&quot; border=&quot;0&quot; width=&quot;344&quot; height=&quot;106&quot; align=&quot;right&quot; style=&quot;padding:0 0 10px 20px;&quot;&gt;&lt;/a&gt;I am trying to tell more people at &lt;a href=&quot;http://www.oracle.com/us/openworld/index.htm&quot;&gt;Oracle OpenWorld&lt;/a&gt; about Ruby and Rails and how it can be used with Oracle database. Unfortunately my session proposals were rejected by organizers but now there is a second chance to propose sessions at &lt;a href=&quot;http://mix.oracle.com&quot;&gt;mix.oracle.com&lt;/a&gt;  and top voted sessions will be accepted for conference. But currently my proposed sessions do not have enough votes :(&lt;/p&gt;
&lt;p&gt;I would be grateful if my blog readers and Ruby on Oracle supporters would vote for my sessions &lt;a href=&quot;https://mix.oracle.com/oow10/proposals/10704-fast-web-applications-development-with-ruby-on-rails-on-oracle&quot;&gt;Fast Web Applications Development with Ruby on Rails on Oracle&lt;/a&gt; and &lt;a href=&quot;https://mix.oracle.com/oow10/proposals/10703-pl-sql-unit-testing-can-be-fun&quot;&gt;PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Unit Testing Can Be Fun!&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You need to log in to &lt;a href=&quot;http://mix.oracle.com&quot;&gt;mix.oracle.com&lt;/a&gt; with your oracle.com login (or you should create new one if you don&amp;#8217;t have it). And also you need to vote for at least one more session as well (as votes are counted if you have voted for at least 3 sessions). Voting should be done until end of this week (June 20).&lt;/p&gt;
&lt;p&gt;And if you have other oracle_enhanced or ruby-plsql users in your &lt;br /&gt;
organization then please ask their support as well :)&lt;/p&gt;
&lt;p&gt;Thanks in advance!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql 0.4.2 - better support for object types and types in packages</title>
   <link href="http://blog.rayapps.com/2010/02/26/ruby-plsql-0-4-2-better-support-for-object-types-and-types-in-packages/"/>
   <updated>2010-02-26T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2010/02/26/ruby-plsql-0-4-2-better-support-for-object-types-and-types-in-packages</id>
   <content type="html">&lt;p&gt;I just released &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql&lt;/a&gt; version 0.4.2 which mainly adds support for more PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure parameter types. See &lt;a href=&quot;http://github.com/rsim/ruby-plsql/blob/master/History.txt&quot;&gt;change history&lt;/a&gt; file for more detailed list of changes.&lt;/p&gt;
&lt;h3&gt;Object types and object methods&lt;/h3&gt;
&lt;p&gt;Now you can use ruby-plsql to construct PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; objects and call methods on these object. For example, if you have the following type defined:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OBJECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;street&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;CONSTRUCTOR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_full_address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SELF&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;RESULT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;MEMBER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;display_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_separator&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;MEMBER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PROCEDURE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set_country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_country&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;STATIC&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_full_address&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then you can construct PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; objects and call methods on them:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# call default constructor with named parameters&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;City&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# call default constructor with sequential parameters&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Street&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;City&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# call custom constructor&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Street, City, Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:p_full_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street, City, Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# returned PL/SQL object is Hash object in Ruby&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;City&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# but in addition you can call PL/SQL methods on it&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street, City, Country&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set_country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Other&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;City&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Other&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# or you can call object member methods also with explicit self parameter&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;display_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;City&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Other&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:p_separator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street, City, Country&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# or you can call static methods of type&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Street, City, Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Street&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;City&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Country&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Record types and table of record types inside packages&lt;/h3&gt;
&lt;p&gt;Now you can call Pl/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures with parameters which have record or table of record type that is defined inside PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; package. For example if you have the following package:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PACKAGE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_records&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RECORD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;hire_date&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employees&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employees2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BINARY_INTEGER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employee&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employees&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employees&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employees2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employees2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then you can call these package functions from Ruby:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;First&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2010&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# PL/SQL record corresponds to Ruby Hash&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_records&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# PL/SQL table corresponds to Ruby Array&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_records&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# PL/SQL index-by table corresponds to Ruby Hash&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_records&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you will use table types defined inside PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; packages then ruby-plsql will dynamically create session specific temporary tables which will be used to pass and get table parameter values. To ensure that these session specific temporary tables will be dropped you need to explicitly call &lt;code&gt;plsql.logoff&lt;/code&gt; to close connection. For example, if you use &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec&quot;&gt;ruby-plsql-spec&lt;/a&gt; for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing then in spec_helper.rb include&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;at_exit&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logoff&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;to ensure that connection will be closed with &lt;code&gt;plsql.logoff&lt;/code&gt; before Ruby script will exit. But in case of some script failure if this was not executed and you notice that there are temporary tables with RUBY_ prefix in your schema then you can call &lt;code&gt;plsql.connection.drop_all_ruby_temporary_tables&lt;/code&gt; to drop all temporary tables.&lt;/p&gt;
&lt;h3&gt;Establish new connection&lt;/h3&gt;
&lt;p&gt;Now there is simpler &lt;code&gt;connect!&lt;/code&gt; method how to establish new ruby-plsql connection when you need a new connection just for ruby-plsql needs. You can do it in several ways:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;database_tns_alias&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect!&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:database&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect!&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:database&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;database_tns_alias&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect!&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:password&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:database&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;database&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And the good thing is that this method will work both with &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8 or 1.9 or with JRuby &amp;#8211; you do not need to change the way how you are establishing connection to database.&lt;/p&gt;
&lt;h3&gt;Savepoints&lt;/h3&gt;
&lt;p&gt;Now there is simpler way how to define savepoints and how to rollback to savepoint:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;savepoint&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;before_something&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rollback_to&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;before_something&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Check validity of database objects&lt;/h3&gt;
&lt;p&gt;Now ruby-plsql will check if referenced database object is valid before trying to call it. And if it will not be valid then corresponding compilation error will be displayed. For example, if you have invalid database object:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_invalid_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_dummy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;l_dummy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invalid_table&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;invalid_column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_dummy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;then when trying to call it&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_invalid_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;dummy&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;you will get the following error message:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ArgumentError: Database object &amp;#39;HR.TEST_INVALID_FUNCTION&amp;#39; is not in valid status
Error on line    2:   l_dummy invalid_table.invalid_column%TYPE;
     position   11: PLS-00201: identifier &amp;#39;INVALID_TABLE.INVALID_COLUMN&amp;#39; must be declared
     position   11: PL/SQL: Item ignored
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Other improvements&lt;/h3&gt;
&lt;p&gt;See &lt;a href=&quot;http://github.com/rsim/ruby-plsql/blob/master/History.txt&quot;&gt;History.txt&lt;/a&gt; file for other new features and improvements and see RSpec tests in &lt;a href=&quot;http://github.com/rsim/ruby-plsql/tree/master/spec/plsql/&quot;&gt;spec directory&lt;/a&gt; for more usage examples.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Oracle enhanced adapter version 1.2.4</title>
   <link href="http://blog.rayapps.com/2010/02/24/activerecord-oracle-enhanced-adapter-version-1-2-4/"/>
   <updated>2010-02-24T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2010/02/24/activerecord-oracle-enhanced-adapter-version-1-2-4</id>
   <content type="html">&lt;p&gt;I have released maintenance version of ActiveRecrod &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter&lt;/a&gt; with some bug fixes and some new features. This is the last maintenance version for Rails 2, I have already done majority of work to support also Rails 3 in next adapter versions, but that deserves another post when it will be ready :).&lt;/p&gt;
&lt;p&gt;Detailed changes can be found in &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/blob/master/History.txt&quot;&gt;change history file&lt;/a&gt; and commit log, here I will point out the main changes.&lt;/p&gt;
&lt;h3&gt;Schema and structure dump&lt;/h3&gt;
&lt;p&gt;There are several improvements in schema (&lt;code&gt;rake db:schema:dump&lt;/code&gt;) and structure dump (&lt;code&gt;rake db:structure:dump&lt;/code&gt;) tasks. Now structure dump is improved to contain all schema objects in &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements format.&lt;/p&gt;
&lt;p&gt;Also &lt;code&gt;db:test:purge&lt;/code&gt; rake task (which is run before recreating test schema when running rake test or rake spec) is changed that it will delete all schema objects from test schema &amp;#8211; including also views, packages, procedures and functions which are not recreated from schema.rb. So if you need to have additional database objects in your schema besides tables, indexes, sequences and synonyms (which are dumped in schema.rb) then you need to recreate them after standard rake task &lt;code&gt;db:schema:load&lt;/code&gt; is run. Here is example how to execute any additional tasks after &lt;code&gt;db:schema:load&lt;/code&gt; (include this in some .rake file in lib/tasks directory):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:db&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:schema&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:load&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Rake&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;db:schema:create_other_objects&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;invoke&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:create_other_objects&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# include code here which creates necessary views, packages etc.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Additional options for schema definition methods&lt;/h3&gt;
&lt;p&gt;You can pass &lt;code&gt;:temporary =&amp;gt; true&lt;/code&gt; option for &lt;code&gt;create_table&lt;/code&gt; method to create temporary tables.&lt;/p&gt;
&lt;p&gt;You can use &lt;code&gt;:tablespace =&amp;gt; &quot;tablespace name&quot;&lt;/code&gt; option for &lt;code&gt;add_index&lt;/code&gt; method to create index in non-default Oracle tablespace that is specified for user (e.g. if it is requested by your &lt;span class=&quot;caps&quot;&gt;DBA&lt;/span&gt; for performance reasons). You can also define function based indexes using add_index and they will be correctly dumped in schema.rb.&lt;/p&gt;
&lt;h3&gt;Savepoints and nested ActiveRecord transactions&lt;/h3&gt;
&lt;p&gt;oracle_enhanced adapter now supports &lt;a href=&quot;http://weblog.rubyonrails.org/2009/1/16/this-week-in-edge-rails&quot;&gt;ActiveRecord nested transactions&lt;/a&gt; using database savepoints.&lt;/p&gt;
&lt;h3&gt;ruby-oci8 version&lt;/h3&gt;
&lt;p&gt;As I am using and testing oracle_enhanced adapter just with &lt;strong&gt;ruby-oci8 2.0.3&lt;/strong&gt; then I have made this as precondition (if you use &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8 or 1.9). So if you haven&amp;#8217;t yet upgraded to latest ruby-oci8 version then please do so before upgrading to oracle_enhanced 1.2.4.&lt;/p&gt;
&lt;h3&gt;&lt;span class=&quot;caps&quot;&gt;JNDI&lt;/span&gt; connection support&lt;/h3&gt;
&lt;p&gt;If you are using oracle_enhanced with JRuby then now you can also use &lt;span class=&quot;caps&quot;&gt;JNDI&lt;/span&gt; database connections &amp;#8211; please see this &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/issues#issue/6&quot;&gt;issue with comments&lt;/a&gt; to see some examples.&lt;/p&gt;
&lt;h3&gt;Install&lt;/h3&gt;
&lt;p&gt;As always you can install Oracle enhanced adapter on any Ruby platform (Ruby 1.8.6 / 1.8.7 or Ruby 1.9.1 or JRuby) with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;If you have any questions please use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;discussion group&lt;/a&gt; or post comments here.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Screencasts of Oracle PL/SQL unit testing with Ruby</title>
   <link href="http://blog.rayapps.com/2010/01/06/screencasts-of-oracle-plsql-unit-testing-with-ruby/"/>
   <updated>2010-01-06T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2010/01/06/screencasts-of-oracle-plsql-unit-testing-with-ruby</id>
   <content type="html">&lt;p&gt;In my previous post I already described how to do &lt;a href=&quot;/2009/11/27/oracle-plsql-unit-testing-with-ruby/&quot;&gt;Oracle PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing with Ruby&lt;/a&gt;. I now have named it as &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec&quot;&gt;ruby-plsql-spec&lt;/a&gt; unit testing framework. But probably you didn&amp;#8217;t want to read such long text or maybe it seemed for you too difficult to try it out therefore I prepared two screencasts to show how easy and fun it is :)&lt;/p&gt;
&lt;h3&gt;Testing simple function&lt;/h3&gt;
&lt;p&gt;The first example is based on classic &lt;a href=&quot;http://utplsql.sourceforge.net/Doc/fourstep.html#step2&quot;&gt;&lt;span class=&quot;caps&quot;&gt;BETWNSTR&lt;/span&gt; function example from utPLSQL tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;div style=&quot;text-align:left;&quot;&gt;&lt;a href=&quot;http://ruby.lv/files/betwnstr.mov&quot; title=&quot;Click to play...&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/betwnstr.png&quot; alt=&quot;betwnstr.png&quot; border=&quot;0&quot; width=&quot;400&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://ruby.lv/files/betwnstr.mov&quot;&gt;Load screencast in QuickTime format (4.7 MB).&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;Testing procedure that changes tables&lt;/h3&gt;
&lt;p&gt;Second example is based on &lt;a href=&quot;http://www.quest.com/code-tester-for-oracle/product-demo/chap02.htm&quot;&gt;Quest Code Tester for Oracle testing tables demo screencast&lt;/a&gt;. So you can see both unit testing frameworks in action and can compare which you like better :)&lt;/p&gt;
&lt;div style=&quot;text-align:left;&quot;&gt;&lt;a href=&quot;http://ruby.lv/files/rooms.mov&quot; title=&quot;Click to play...&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/rooms.png&quot; alt=&quot;rooms.png&quot; border=&quot;0&quot; width=&quot;400&quot; height=&quot;300&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://ruby.lv/files/rooms.mov&quot;&gt;Load screencast in QuickTime format (8.1 MB).&lt;/a&gt;&lt;/div&gt;
&lt;h3&gt;Test driven development&lt;/h3&gt;
&lt;p&gt;In both these screencasts I demonstrated how to do &lt;a href=&quot;http://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;test driven development&lt;/a&gt; of PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Write little test of indended functionality before writing code.&lt;/li&gt;
	&lt;li&gt;Write implementation of new functionality until this test passes and verify that all existing tests pass as well.&lt;/li&gt;
	&lt;li&gt;Refactor implementation when needed and verify that all tests still pass.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From my experience &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; style of development can improve design and testability of code and also make you think before coding what you actually want to implement. But existing visual PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; testing tools (Quest Code Tester, &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer 2.1) do not quite support &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; style of development, they expect that there is already existing code that should be tested. Therefore this is one more ruby-plsql-spec advantage if you would like to do &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; style development in PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;More information&lt;/h3&gt;
&lt;p&gt;Examples shown in screencasts are available in &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec&quot;&gt;ruby-plsql-spec&lt;/a&gt; GitHub repository. And if you want to see more examples how to use ruby-plsql library for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing then you can take a look at &lt;a href=&quot;http://github.com/rsim/ruby-plsql/blob/master/spec/plsql/procedure_spec.rb&quot;&gt;ruby-plsql own RSpec tests&lt;/a&gt; or read &lt;a href=&quot;/tags/ruby-plsql&quot;&gt;previous posts about ruby-plsql&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql 0.4.1 - support for package variables, views, dbms_output and more</title>
   <link href="http://blog.rayapps.com/2010/01/04/ruby-plsql-0-4-1-support-for-package-variables-views-dbms_output-and-more/"/>
   <updated>2010-01-04T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2010/01/04/ruby-plsql-0-4-1-support-for-package-variables-views-dbms_output-and-more</id>
   <content type="html">&lt;p&gt;Based on feedback from using &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql&lt;/a&gt; for &lt;a href=&quot;http://blog.rayapps.com/2009/11/27/oracle-plsql-unit-testing-with-ruby/&quot;&gt;PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing&lt;/a&gt; I have release new version 0.4.1 with several new features. You can read about initial versions of ruby-plsql in &lt;a href=&quot;http://blog.rayapps.com/category/plsql/&quot;&gt;previous blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Package variables&lt;/h3&gt;
&lt;p&gt;When you call methods on &lt;code&gt;plsql&lt;/code&gt; Ruby object then ruby-plsql uses &lt;code&gt;all_procedures&lt;/code&gt; and &lt;code&gt;all_arguments&lt;/code&gt; data dictionary views to search for procedures and their argument metadata to construct corresponding PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; block for execution. Unfortunately there are no corresponding data dictionary views for package variables (sometimes called &amp;#8220;global variables&amp;#8221;) that are defined in package specifications. Therefore there was no support for package variables in initial ruby-plsql versions.&lt;/p&gt;
&lt;p&gt;But as there is quite frequent need in PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; tests to set and get package variable values then I created the following solution for accessing package variables. I assume that typically package variables are defined in one line in package specifications and I scan PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; package specification source in &lt;code&gt;all_source&lt;/code&gt; data dictionary view for potential package variable definitions.&lt;/p&gt;
&lt;p&gt;As a result if you have the following example of package specification:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PACKAGE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;varchar2_variable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;number_variable&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;string_constant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONSTANT&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;constant&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;integer_constant&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONSTANT&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;then you can access these package variables in the same way as procedures:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varchar2_variable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;test&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number_variable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varchar2_variable&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;#39;test&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number_variable&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 123&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string_constant&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;#39;constant&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;integer_constant&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Other basic data types as well as &lt;code&gt;%ROWTYPE&lt;/code&gt;, &lt;code&gt;%TYPE&lt;/code&gt; and schema object types are also supported for package variables. Only custom types defined in package specification are not supported (they are not supported for procedure parameters as well). As there are no data dictionary views for types defined in package specifications I don&amp;#8217;t feel very enthusiastic about parsing package sources from all_source to get information about types defined inside packages :)&lt;/p&gt;
&lt;h3&gt;Views&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;http://blog.rayapps.com/2009/11/25/more-oracle-data-types-supported-by-ruby-plsql-gem&quot;&gt;previous post&lt;/a&gt; I described how to use ruby-plsql to perform basic table operations. Now these operations can be performed also with views:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;view_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;insert_values method&lt;/h3&gt;
&lt;p&gt;Additional &lt;code&gt;insert_values&lt;/code&gt; method is added for tables and views which can be helpful in PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; tests for test data preparation. You can specify with more compact syntax which data you would like to insert into table or view:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert_values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;First&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Second&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; INSERT INTO employees (employee_id, first_name, last_name) VALUES (1, &amp;#39;First&amp;#39;, &amp;#39;Last&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; INSERT INTO employees (employee_id, first_name, last_name) VALUES (2, &amp;#39;Second&amp;#39;, &amp;#39;Last&amp;#39;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;DBMS_OUTPUT logging&lt;/h3&gt;
&lt;p&gt;If you use &lt;code&gt;DBMS_OUTPUT.PUT_LINE&lt;/code&gt; in your PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures to log some debug messages then you can use &lt;code&gt;plsql.dbms_output_stream=&lt;/code&gt; method to set where these messages should be displayed. Use the following to display DBMS_OUTPUT messages in standard output:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbms_output_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDOUT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Or write DBMS_OUTPUT messages to file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dbms_output_stream&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;debug.log&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;&lt;span class=&quot;caps&quot;&gt;STANDARD&lt;/span&gt; package procedures&lt;/h3&gt;
&lt;p&gt;Procedures from &lt;code&gt;SYS.STANDARD&lt;/code&gt; package can be called without sys.standard prefix, e.g.:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sysdate&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;substr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;abcde&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Other improvements&lt;/h3&gt;
&lt;p&gt;See &lt;a href=&quot;http://github.com/rsim/ruby-plsql/blob/master/History.txt&quot;&gt;History.txt&lt;/a&gt; file for other new features and improvements and see RSpec tests in spec directory for more usage examples.&lt;/p&gt;
&lt;p&gt;And also this version of ruby-plsql requires ruby-oci8 gem latest version 2.0.3 (if you use &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; / standard Ruby interpreter 1.8.6, 1.8.7 or 1.9.1) so please upgrade it as well if you do not have it. But as previously you can use ruby-plsql with JRuby and Oracle &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; driver as well.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Oracle PL/SQL unit testing with Ruby</title>
   <link href="http://blog.rayapps.com/2009/11/27/oracle-plsql-unit-testing-with-ruby/"/>
   <updated>2009-11-27T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2009/11/27/oracle-plsql-unit-testing-with-ruby</id>
   <content type="html">&lt;h3&gt;Current PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing options&lt;/h3&gt;
&lt;p&gt;Unit testing and &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; (test driven development) practices are nowadays one of the key software development practices. It is especially important if you are doing agile software development in small iterations where you need to automate unit testing as much as possible, as you cannot do manual regression testing of all existing and new functionality at the end of each iteration.&lt;/p&gt;
&lt;p&gt;In some languages (like Java, Ruby, Python, C# etc.) there is quite good tools and frameworks support for unit testing and as a result there is quite high testing culture among top developers in these communities. But unfortunately in PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; community so far automated unit testing is not used very often. During recent Oracle OpenWorld conference in presentations about unit testing when it was asked who is doing automated unit testing then only few hands were raised.&lt;/p&gt;
&lt;p&gt;Why is it so? And what are current options for doing automated PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing?&lt;/p&gt;
&lt;p&gt;The first unit testing framework for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; was &lt;a href=&quot;http://utplsql.sourceforge.net/&quot;&gt;utPLSQL&lt;/a&gt; which was created by &lt;a href=&quot;http://www.toadworld.com/sf&quot;&gt;Steven Feuerstein&lt;/a&gt; and based on &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; defined by many other xUnit style frameworks (like e.g. JUnit). But the issue with this approach was that PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; syntax for tests was quite verbose and tests were not very readable (see &lt;a href=&quot;http://utplsql.cvs.sourceforge.net/viewvc/utplsql/examples/ut_betwnstr.pkb?view=markup&quot;&gt;example&lt;/a&gt;). As a result Steven stopped developing further utPLSQL and currently there are no other active maintainers of this project. There are some other alternative frameworks which tried to simplify writing tests in PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; (OUnit, pl/unit, &lt;span class=&quot;caps&quot;&gt;PLUTO&lt;/span&gt; etc.) but none of them are very actively used and maintained by PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; community.&lt;/p&gt;
&lt;p&gt;Because of the issues with utPLSQL Steven Feuerstein started development of graphical interface tool for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing which is now &lt;a href=&quot;http://unittest.inside.quest.com&quot;&gt;Quest Code Tester for Oracle&lt;/a&gt;. This tool is actively developed and maintained by Quest Software but there are several issues with it:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;It is a commercial tool and as a result it will not become widely accepted by all PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; developers. There is also a freeware edition of it but the functionality of it is &lt;a href=&quot;http://unittest.inside.quest.com/servlet/KbServlet/download/2792-102-5392/Differences%20Between%20Quest%20Code%20Tester%20for%20Oracle%20Freeware%20and%20Commercial.htm&quot;&gt;very limited&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;It is a graphical tool &amp;#8211; it can help you with quick creation of simple tests but when you will need more complex logic you might get stuck that you cannot do it (or you need to do it again in plain PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; and have the same issues as in utPLSQL).&lt;/li&gt;&lt;/li&gt;
	&lt;li&gt;It stores tests in database repository &amp;#8211; and it means that it might be hard to maintain unit tests in version control system like Subversion or Git.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And finally also Oracle started to do something in PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing area and there is unit testing support in latest &lt;a href=&quot;http://www.oracle.com/technology/products/database/sql_developer/index.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer version 2.1&lt;/a&gt; which currently still is in early adopter status. &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer has very similar approach to Quest Code Tester &amp;#8211; it is graphical tool which stores tests and test results in repository. So the benefit of &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer over Quest Code Tester is that it is free :) But compared to Quest Code Tester it still has less features (e.g. currently not all complex data types are supported) and still is not released as final version and still has bugs.&lt;/p&gt;
&lt;h3&gt;Ruby as testing tool for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;As you probably know I am quite big &lt;a href=&quot;http://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt; fan and always exploring new ways how to use Ruby to increase my productivity. And Ruby community has very high testing culture and has many good tools for testing support (I like and use &lt;a href=&quot;http://rspec.info/&quot;&gt;RSpec&lt;/a&gt; testing framework). Therefore some time ago I started to use Ruby and RSpec also for testing PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; code in our projects where we use Ruby on Rails on top of Oracle databases with existing PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; business logic.&lt;/p&gt;
&lt;p&gt;I have created &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql&lt;/a&gt; library which provides very easy &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for calling PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures from Ruby and recent ruby-plsql version &lt;a href=&quot;/2009/11/25/more-oracle-data-types-supported-by-ruby-plsql-gem/&quot;&gt;supports majority of PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; data types&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So let&amp;#8217;s start with with simple example how to use Ruby, RSpec and ruby-plsql to create PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure unit test. I will use &lt;span class=&quot;caps&quot;&gt;BETWNSTR&lt;/span&gt; procedure example from utPLSQL examples:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;betwnstr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;string_in&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;start_in&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;end_in&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PLS_INTEGER&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SUBSTR&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string_in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end_in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I took &lt;a href=&quot;http://utplsql.cvs.sourceforge.net/viewvc/utplsql/examples/ut_betwnstr_gen.pkg?view=markup&quot;&gt;example tests from utPLSQL&lt;/a&gt; and wrote them in Ruby and RSpec:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Between string&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should be correct in normal case&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;betwnstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;abcdefg&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bcde&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should be correct with zero start value&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;betwnstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;abcdefg&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;abcde&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should be correct with way big end value&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;betwnstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;abcdefg&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;efg&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should be correct with NULL string&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;betwnstr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_nil&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As you can see the tests are much shorter than in utPLSQL and are much more readable (also more readable than &lt;a href=&quot;http://utplsql.cvs.sourceforge.net/viewvc/utplsql/examples/bewtnstr.utc?view=markup&quot;&gt;utPLSQL template&lt;/a&gt; which can be used to generate utPLSQL tests). And also you can create these tests faster than using &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt; tools like Quest Code Tester or &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer.&lt;/p&gt;
&lt;h3&gt;More complex example&lt;/h3&gt;
&lt;p&gt;Second more complex example I took from &lt;a href=&quot;http://www.oracle.com/technology/obe/11gr2_db_prod/appdev/sqldev/sqldev_unit_test/sqldev_unit_test_otn.htm&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer unit testing tutorial&lt;/a&gt;. We will create tests for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure AWARD_BONUS:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;PROCEDURE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;award_bonus&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;emp_id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;commission&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;REAL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;comm_missing&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;EXCEPTION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission_pct&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employees2&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emp_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;RAISE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comm_missing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employees2&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;NVL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commission&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emp_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;award_bonus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I didn&amp;#8217;t quite like the testing approach in &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer unit testing tutorial &amp;#8211; it was assuming that there is already specific data in employees2 table and was testing procedure using specific primary key values. As a result tests are not very readable as you cannot see all input data in the test case and tests could easily broke if initial data in table are different.&lt;/p&gt;
&lt;p&gt;Therefore I created tests in Ruby using better approach that each test creates all necessary data that are needed for it and at the end of test there are no side effects which can influence other tests:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Award bonus&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CustomerFactory&lt;/span&gt;
  
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;1123&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;56&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;1123&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission_pct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should calculate base salary &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; + sales amount &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; * &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                  &lt;span class=&quot;s2&quot;&gt;&amp;quot;commission percentage &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commission_pct&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; = salary &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;:commission_pct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission_pct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;ss&quot;&gt;:salary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;award_bonus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;get_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:salary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I am generating three different tests with three different sets of input values. When you run these tests you see result:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Award bonus
- should calculate base salary 1000 + sales amount 1234.55 * commission percentage 0.1 = salary 1123.46
- should calculate base salary NULL + sales amount 1234.56 * commission percentage 0.1 = salary 123.46
- should calculate base salary 1000 + sales amount 1234.54 * commission percentage 0.1 = salary 1123.45
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In addition I am using factory pattern (create_customer method) for test data creation. When using factory pattern you create test data creation method which will create valid new record with default field values. If in your test you need some specific non-default values then you can pass just these values as parameters to factory method. Factory pattern also helps in the maintenance of tests. For example, if new mandatory columns will be added to employees table then it will be necessary to add new fields with default values in factory methods and nothing should be changed in individual tests.&lt;/p&gt;
&lt;p&gt;Here is example of employee factory implementation:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;EmployeeFactory&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Creates new employee with valid field values.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Pass in parameters only field values that you want to override.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees2_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nextval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;last@example.com&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;today&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:job_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:job_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:commission_pct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:salary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;get_employee&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;c1&quot;&gt;# Select employee by primary key&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And here is additional test for testing if procedure will raise exception if one input value is missing:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;should raise ORA-06510 exception if commission percentage is missing&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission_pct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:commission_pct&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commission_pct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:salary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;award_bonus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sales_amt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raise_error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/ORA-06510/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;How to use it&lt;/h3&gt;
&lt;p&gt;I hope that if you are looking for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing tool then you will try this out :) You can get examples from this article together with necessary setup code and installation instructions at  &lt;a href=&quot;http://github.com/rsim/ruby-plsql-spec&quot;&gt;http://github.com/rsim/ruby-plsql-spec&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have any feedback or questions or feature suggestions then please comment.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>More Oracle data types supported by ruby-plsql gem</title>
   <link href="http://blog.rayapps.com/2009/11/25/more-oracle-data-types-supported-by-ruby-plsql-gem/"/>
   <updated>2009-11-25T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2009/11/25/more-oracle-data-types-supported-by-ruby-plsql-gem</id>
   <content type="html">&lt;p&gt;I have just released &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql&lt;/a&gt; gem version 0.4.0 which provides many new features. You can read about initial versions of ruby-plsql in &lt;a href=&quot;http://blog.rayapps.com/category/plsql/&quot;&gt;previous blog posts&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Oracle complex data type support&lt;/h3&gt;
&lt;p&gt;Initial versions of ruby-plsql supported just simple Oracle types like &lt;code&gt;NUMBER&lt;/code&gt;, &lt;code&gt;VARCHAR2&lt;/code&gt;, &lt;code&gt;DATE&lt;/code&gt;, &lt;code&gt;TIMESTAMP&lt;/code&gt;, &lt;code&gt;CLOB&lt;/code&gt;, &lt;code&gt;BLOB&lt;/code&gt; as PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure parameters. Now support for many more complex data types is added. See examples below how to call PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures with these complex data types.&lt;/p&gt;
&lt;h4&gt;PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Record&lt;/h4&gt;
&lt;p&gt;Let&amp;#8217;s assume you have PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure with PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; record type parameter (which most typically will be in &lt;code&gt;table%ROWTYPE&lt;/code&gt; format):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;hire_date&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_full_name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ROWTYPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then you can create Ruby Hash with record field values (specifying field names as Symbols), e.g.:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;First&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and pass this Hash as a parameter which will be translated to PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; record parameter by ruby-plsql:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; &amp;quot;First Last&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# or&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:p_employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; &amp;quot;First Last&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In the same way you can get PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; function return values or output parameter values as Hash values.&lt;/p&gt;
&lt;h4&gt;Object type&lt;/h4&gt;
&lt;p&gt;In similar way also object type parameters can be passed as Hash values. In this case also nested objects or nested collections of objects are supported:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OBJECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;street&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_phone&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OBJECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;phone_number&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_phones&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T_PHONE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OBJECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;hire_date&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;t_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;phones&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;t_phones&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_full_name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and from Ruby side you can call this PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; function as:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;First&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:street&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Main street 1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Riga&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Latvia&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:phones&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mobile&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:phone_number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;123456&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;home&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:phone_number&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;654321&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; &amp;quot;First Last&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# or&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_full_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:p_employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; &amp;quot;First Last&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And also object type return values and output parameters will be returned as Ruby Hash values (with nested Hashes or Arrays if necessary).&lt;/p&gt;
&lt;p&gt;There is one limitation that these object types should be defined as database types and not just inside PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; package definition. Unfortunately you cannot access type definitions inside packages from &lt;span class=&quot;caps&quot;&gt;OCI&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; drivers and as a result cannot call such procedures from outside of PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;.&lt;/p&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;TABLE&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;VARRAY&lt;/span&gt; collections&lt;/h4&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;TABLE&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;VARRAY&lt;/span&gt; collection parameters can be passed as Array values:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TYPE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_numbers&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OF&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_sum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_numbers&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;l_sum&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;COUNT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;FOR&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;FIRST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;LAST&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOOP&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;l_sum&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_sum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LOOP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;ELSE&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And from Ruby side:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; 10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;CURSOR&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;You can get also cursor return values from PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_cursor&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SYS_REFCURSOR&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;l_cursor&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;SYS_REFCURSOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;OPEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_cursor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FOR&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_cursor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;can be called from Ruby in the following way:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_cursor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; first row from test_employees will be returned&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It is important to pass block parameter in this case and do something with returned cursor within this block as after ruby-plsql finishes PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure call it will close all open cursors and therefore it will not be possible to do anything with returned cursor outside this block.&lt;/p&gt;
&lt;p&gt;It is also possible to use returned cursor as input parameter for another PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_cursor_fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_cursor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SYS_REFCURSOR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ROWTYPE&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;l_record&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ROWTYPE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;FETCH&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_cursor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;which can be called from Ruby&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_cursor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_cursor_fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; first record as Hash&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: you can pass cursors as PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure input parameter just when using ruby-plsql on &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8/1.9 with ruby-oci8, unfortunately I have not found a way how to pass cursor as input parameter when using JRuby and &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt;.&lt;/p&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;BOOLEAN&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;And finally you can use also PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;BOOLEAN&lt;/span&gt; type &amp;#8211; it is quite tricky data type as it is supported just by PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; but not supported as data type in Oracle tables. But now you can also use it with ruby-plsql:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_boolean&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_boolean&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;BOOLEAN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;BOOLEAN&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_boolean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#=&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can find more PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure call usage examples in &lt;a href=&quot;http://github.com/rsim/ruby-plsql/blob/master/spec/plsql/procedure_spec.rb&quot;&gt;ruby-plsql RSpec tests&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Table and sequence operations&lt;/h3&gt;
&lt;p&gt;I have been using and promoting to others ruby-plsql as PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure unit testing tool. As current PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing tools are not so advanced and easy to use as Ruby unit testing tools then I like better to use Ruby testing tools (like RSpec) together with ruby-plsql to write short and easy to understand PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit tests.&lt;/p&gt;
&lt;p&gt;In unit tests in setup and teardown methods you typically need some easy way how to create some sample data in necessary tables as well as to validate resulting data in tables after test execution.&lt;/p&gt;
&lt;p&gt;If you are Ruby on Rails developer then you probably will use ActiveRecord (or DataMapper) for manipulation of table data. But if Ruby is used just for unit tests then probably ActiveRecord would be too complicated for this task.&lt;/p&gt;
&lt;p&gt;Therefore I added some basic table operations to ruby-plsql which might be useful e.g. in unit tests. Some syntax ideas for these table operations are coming from &lt;a href=&quot;http://github.com/jeremyevans/sequel/&quot;&gt;Sequel&lt;/a&gt; Ruby library.&lt;/p&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt;&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# insert one record&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;First&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Last&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# INSERT INTO employees VALUES (1, &amp;#39;First&amp;#39;, &amp;#39;Last&amp;#39;, ...)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# insert many records &lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employee1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employee2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# array of many Hashes&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;insert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If primary key values should be selected from sequence then you can get next sequence values with&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nextval&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# SELECT employees_seq.NEXTVAL FROM dual&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees_seq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;currval&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# SELECT employees_seq.CURRVAL FROM dual&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt;&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# select one record&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# SELECT * FROM employees&lt;/span&gt;
                      &lt;span class=&quot;c1&quot;&gt;# fetch first row =&amp;gt; {:employee_id =&amp;gt; ..., :first_name =&amp;gt; &amp;#39;...&amp;#39;, ...}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# SELECT * FROM employees WHERE employee_id = 1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;WHERE employee_id = 1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;WHERE employee_id = :employee_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# select many records&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;                       &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [{...}, {...}, ...]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:order_by&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;WHERE employee_id &amp;gt; :employee_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# count records&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;# SELECT COUNT(*) FROM employees&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;WHERE employee_id &amp;gt; :employee_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt;&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# update records&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Second&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:where&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
                      &lt;span class=&quot;c1&quot;&gt;# UPDATE employees SET first_name = &amp;#39;Second&amp;#39; WHERE employee_id = 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt;&lt;/h4&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# delete records&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;employees&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# DELETE FROM employees WHERE employee_id = 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;Other &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements&lt;/h4&gt;
&lt;p&gt;Any other &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; statement can be executed with&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;SELECT ...&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# or&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;SELECT ...&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;or any other non-&lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement can be executed with&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;...&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And also &lt;span class=&quot;caps&quot;&gt;COMMIT&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;ROLLBACK&lt;/span&gt; could be executed simply with&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commit&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rollback&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I plan to write a separate blog post about how I recommend to create PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit tests using Ruby and ruby-plsql and RSpec.&lt;/p&gt;
&lt;h3&gt;Install&lt;/h3&gt;
&lt;p&gt;As always you can install latest version of ruby-plsql with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install ruby-plsql&lt;/pre&gt;
&lt;p&gt;Latest gem version is just on &lt;a href=&quot;http://gemcutter.org/gems/ruby-plsql&quot;&gt;Gemcutter&lt;/a&gt; but now it should be available as default gem source for all Ruby installations.&lt;/p&gt;
&lt;p&gt;And as always ruby-plsql is supported both on&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Ruby 1.8.6/1.8.7 or Ruby 1.9.1 with ruby-oci8 gem version 2.0.3 or later (some specific issues with complex data types will be fixed in later versions of ruby-oci8)&lt;/li&gt;
	&lt;li&gt;JRuby 1.3/1.4 with Oracle &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; driver (testing mainly with ojdbc14.jar but also ojdbc5.jar or ojdbc6.jar should be fine)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please try it out and tell me if there are any issues with some particular data types or if there are still some unsupported PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; data types that you would like to be supported in ruby-plsql. And also I encourage you to try ruby-plsql out for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing if you had no PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit tests previously :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Notes from Oracle OpenWorld 2009</title>
   <link href="http://blog.rayapps.com/2009/10/20/notes-from-oracle-openworld-2009/"/>
   <updated>2009-10-20T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/10/20/notes-from-oracle-openworld-2009</id>
   <content type="html">&lt;h3&gt;People&lt;/h3&gt;
&lt;p&gt;Last week I participated in annual &lt;a href=&quot;http://www.oracle.com/us/openworld/018079.htm&quot;&gt;Oracle OpenWorld 2009&lt;/a&gt; conference. There is quite wide coverage of conference in various web sites and blogs therefore I will write just some personal notes that I wanted to highlight.&lt;/p&gt;
&lt;p&gt;For me the most value was meeting with different interesting people. At first thanks to &lt;a href=&quot;http://blogs.oracle.com/otn/&quot;&gt;Justin Kestelyn&lt;/a&gt; and all &lt;a href=&quot;http://www.oracle.com/technology/index.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;OTN&lt;/span&gt;&lt;/a&gt; team for Oracle community support. Oracle &lt;span class=&quot;caps&quot;&gt;ACE&lt;/span&gt; dinner, bloggers meetup, &lt;span class=&quot;caps&quot;&gt;OTN&lt;/span&gt; lounge and unconference were great places where to meet and discuss with interesting and active Oracle community members.&lt;/p&gt;
&lt;p&gt;It was nice to meet &lt;a href=&quot;http://db360.blogspot.com/&quot;&gt;Kuassi Mensah&lt;/a&gt; and &lt;a href=&quot;http://blogs.oracle.com/opal/&quot;&gt;Christopher Jones&lt;/a&gt; who are supporters of dynamic languages in Oracle and supporters of Ruby in particular. And also had interesting discussions with &lt;a href=&quot;http://twitter.com/rmanalan&quot;&gt;Rich Manalang&lt;/a&gt; &amp;#8211; Ruby guru at Oracle, who is from the &lt;a href=&quot;http://theappslab.com/&quot;&gt;AppsLab&lt;/a&gt; team.&lt;/p&gt;
&lt;p&gt;This year there were quite a few Sun people in the conference. Scott McNealy and James Gosling were doing keynotes. And I had interesting discussions with &lt;a href=&quot;http://blog.arungupta.me/&quot;&gt;Arun Gupta&lt;/a&gt; and &lt;a href=&quot;http://www.tbray.org/ongoing/&quot;&gt;Tim Bray&lt;/a&gt;. &lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt; they have very good coverage of Oracle OpenWorld in their blogs (and also have a fresh look at it as they were for the first time here).&lt;/p&gt;
&lt;p&gt;This year I did two &lt;a href=&quot;http://wiki.oracle.com/page/Oracle+OpenWorld+Unconference&quot;&gt;unconference&lt;/a&gt; sessions &amp;#8211; &lt;a href=&quot;http://www.slideshare.net/rsim/oracle-adapters-for-ruby-orms&quot;&gt;Oracle adapters for Ruby ORMs&lt;/a&gt; and &lt;a href=&quot;http://www.slideshare.net/rsim/server-installation-and-configuration-with-chef&quot;&gt;Server Installation and Configuration with Chef&lt;/a&gt;. They were not very many attendees but at least it seemed that those who attended were satisfied with content :) This year Oracle Develop track was located quite far from unconference location and probably this also was a reason why there were not very many attendees (as my sessions were quite developer oriented).&lt;/p&gt;
&lt;h3&gt;Technologies&lt;/h3&gt;
&lt;p&gt;Here is the list of Oracle products and technologies that I am interested in to spend some time investigating them:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Fustion applications.&lt;/strong&gt; I expected to hear more about next-generation of new Fusion applications but there was just short demo in the final keynote and a promise that they will be available sometime next year. &lt;a href=&quot;http://www.flickr.com/photos/oracleopenworld09/sets/72157622462805751/&quot;&gt;User interface&lt;/a&gt; of new applications seems much better than for the current Oracle applications as well as current beta-testers are telling that usability is really much better. So I am really looking for trying them out.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Application Development Framework (&lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt;).&lt;/strong&gt; I am not a big fan of &lt;a href=&quot;http://www.oracle.com/technology/products/adf/index.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt;&lt;/a&gt; drag-and-drop development style (that&amp;#8217;s why I prefer Ruby on Rails :)) but as &lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt; is the main development platform for Fusion Applications then it will be necessary to use it if we would like to extend or customize Fusion applications. But what I would be really interested in is how to integrate JRuby with &lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt; &amp;#8211; it would be nice to use &lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt; Faces UI components to get &lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt; look and feel, but to use JRuby for model &amp;amp; controller business logic development.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer unit testing.&lt;/strong&gt; It was nice to see that finally Oracle has PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit testing support in latest version of &lt;a href=&quot;http://www.oracle.com/technology/software/products/sql/index21_EA1.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer&lt;/a&gt; which hopefully will increase awareness about unit testing among PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; developers. &lt;a href=&quot;http://www.toadworld.com/sf&quot;&gt;Steven Feuerstein&lt;/a&gt; gave very good &amp;#8220;motivational&amp;#8221; talk about unit testing during converence. But I still can&amp;#8217;t decide if &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer repository based unit tests is the best way how to do them. E.g. as all unit tests are stored in database repository you cannot version control them with Subversion or Git (which is the place where we store source of all PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures).&lt;br /&gt;
Therefore I plan to make enhancements to my &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql&lt;/a&gt; gem to support more PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; data types and then it would be possible to write PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; unit tests with Ruby and RSpec which would provide more compact syntax compared to current &lt;a href=&quot;http://utplsql.sourceforge.net/&quot;&gt;utPLSQL&lt;/a&gt; framework. Need to write blog post about it :)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Oracle Coherence.&lt;/strong&gt; Recently I have heard many references to &lt;a href=&quot;http://www.oracle.com/technology/products/coherence/index.html&quot;&gt;Oracle Coherence&lt;/a&gt; in-memory data grid which is often used to achieve high-scalability of web applications. Therefore I am thinking about Ruby client for Coherence and potentially using Coherence as cache solution in Ruby on Rails applications.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Java in database.&lt;/strong&gt; Recently I did some experiments with Java stored procedures in Oracle database &amp;#8211; and the main reason is that it could provide integration of Oracle database with other systems that have Java based &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;. I already did experiments with creating Oracle client for &lt;a href=&quot;http://www.rabbitmq.com/&quot;&gt;RabbitMQ&lt;/a&gt; messaging system.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Oracle object types.&lt;/strong&gt; Many Oracle products (like Spatial Data option) are using Oracle object types for storing data. Currently these object data types are not supported by Ruby ActiveRecord and DataMapper ORMs. Need to do investigation how they could be supported and how to use Ruby e.g. for accessing spatial data in Oracle database.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Oracle Magazine&amp;#8217;s Developer of the Year&lt;/h3&gt;
&lt;p&gt;And finally during Oracle OpenWorld annual Oracle Magazine Editors&amp;#8217; Choice Awards 2009 were published. And it was pleasant surprise for me that in this year I got &lt;a href=&quot;http://www.oracle.com/technology/oramag/oracle/09-nov/o69awards.html#simanovskis&quot;&gt;Oracle Magazine&amp;#8217;s Developer of the Year&lt;/a&gt; award. Thanks to Oracle people who promoted me and thanks for congratulations that I received :) Here is my picture and profile from the latest Oracle Magazine:&lt;br /&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;a href=&quot;http://blog.rayapps.com/images/doty.png&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/doty_450.png&quot; alt=&quot;doty_450.png&quot; border=&quot;0&quot; width=&quot;450&quot; height=&quot;299&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;font size=&quot;-2&quot;&gt;Photo &amp;copy; Delmi Alvarez / Getty Images&lt;/font&gt;&lt;/div&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>New features in ActiveRecord Oracle enhanced adapter version 1.2.2</title>
   <link href="http://blog.rayapps.com/2009/09/28/new-features-in-activerecord-oracle-enhanced-adapter-version-1-2-2/"/>
   <updated>2009-09-28T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/09/28/new-features-in-activerecord-oracle-enhanced-adapter-version-1-2-2</id>
   <content type="html">&lt;p&gt;During the last months many new features have been implemented for ActiveRecord &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter&lt;/a&gt; which are now included in Oracle enhanced adapter version 1.2.2. You can find full list in &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/blob/master/History.txt&quot;&gt;change history file&lt;/a&gt;, here I will tell about the main ones.&lt;/p&gt;
&lt;h3&gt;Documentation&lt;/h3&gt;
&lt;p&gt;Now Oracle enhanced adapter has improved RDoc documentation for all public methods. So you can go to RDoc documentation of installed gem or go and &lt;a href=&quot;http://oracle-enhanced.rubyforge.org/rdoc&quot;&gt;view published documentation on-line&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Schema definition&lt;/h3&gt;
&lt;p&gt;There are many new features in schema definition methods that you can use in migration files:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;When you use &lt;code&gt;add_index&lt;/code&gt; then ActiveRecord is automatically generating index name using format index_table_name_on_column1_and_column2_&amp;#8230; which previously could cause Oracle errors as Oracle identifiers should be up to 30 characters long. Now default index names are &lt;strong&gt;automatically shortened down to 30 or less characters&lt;/strong&gt; (of course you can always use also &lt;code&gt;:name&lt;/code&gt; option to specify shortened version by yourself).&lt;/li&gt;
	&lt;li&gt;Now adapter is &lt;strong&gt;ignoring &lt;code&gt;:limit&lt;/code&gt; option for &lt;code&gt;:text&lt;/code&gt; and &lt;code&gt;:binary&lt;/code&gt; columns&lt;/strong&gt; (as in Oracle you cannot specify limit for &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; data types). Previously it could cause errors if you tried to migrate Rails application from e.g. MySQL where &lt;code&gt;:text&lt;/code&gt; and &lt;code&gt;:binary&lt;/code&gt; columns could have &lt;code&gt;:limit&lt;/code&gt; in schema definition.&lt;/li&gt;
	&lt;li&gt;If you define &lt;code&gt;:string&lt;/code&gt; &lt;strong&gt;column with&lt;/strong&gt;* &lt;code&gt;:limit&lt;/code&gt; &lt;strong&gt;option&lt;/strong&gt; then it will define &lt;code&gt;VARCHAR2&lt;/code&gt; &lt;strong&gt;column with size in characters and not in bytes&lt;/strong&gt; (this makes difference if you use &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 with language where one character might be stored as several bytes). This is expected behavior from ActiveRecord that you define maximum string size in &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 characters.&lt;/li&gt;
	&lt;li&gt;Now you can use &lt;code&gt;add_foreign_key&lt;/code&gt; and &lt;code&gt;remove_foreign_key&lt;/code&gt; to define foreign key constraints in migrations (see &lt;a href=&quot;http://oracle-enhanced.rubyforge.org/rdoc/classes/ActiveRecord/ConnectionAdapters/OracleEnhancedSchemaStatementsExt.html#M000010&quot;&gt;RDoc documentation for details&lt;/a&gt;). Syntax and some implemenatation for foreign key definition was taken from &lt;a href=&quot;http://github.com/matthuhiggins/foreigner&quot;&gt;foreigner Rails plugin&lt;/a&gt; as well as some ideas taken from &lt;a href=&quot;http://github.com/eyestreet/active_record_oracle_extensions&quot;&gt;active_record_oracle_extensions plugin&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;add_foreign_key&lt;/code&gt; definitions will be also &lt;strong&gt;extracted in schema.rb&lt;/strong&gt; by &lt;code&gt;rake db:schema:dump&lt;/code&gt; task. Therefore they will be also present in test database when you will recreate it from schema.rb file.&lt;/li&gt;
	&lt;li&gt;Foreign keys are also safe for loading of fixtures (in case you are still using them instead of factories :)). &lt;code&gt;disable_referential_integrity&lt;/code&gt; method is implemented for Oracle enhanced adapter which is called by ActiveRecord before loading fixtures and which disables all currently active foreign key constraints during loading of fixtures.&lt;/li&gt;
	&lt;li&gt;You can use &lt;code&gt;add_synonym&lt;/code&gt; and &lt;code&gt;remove_synonym&lt;/code&gt; to &lt;a href=&quot;http://oracle-enhanced.rubyforge.org/rdoc/classes/ActiveRecord/ConnectionAdapters/OracleEnhancedSchemaStatementsExt.html#M000012&quot;&gt;define database synonyms&lt;/a&gt; to other tables, views or sequences. add_synonym definitions will also be extracted in schema.rb file.&lt;/li&gt;
	&lt;li&gt;It is possible to create tables with &lt;a href=&quot;http://oracle-enhanced.rubyforge.org/rdoc/classes/ActiveRecord/ConnectionAdapters/OracleEnhancedAdapter.html#M000032&quot;&gt;primary key trigger&lt;/a&gt;. There will be no difference in terms how you would create new records in such table using ActiveRecord but in case you have also need to do direct INSERTs into the table then it will be easier as you can omit primary key from &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt; statement and primary key trigger will populate it automatically from corresponding sequence.&lt;/li&gt;
	&lt;li&gt;ActiveRecord &lt;strong&gt;schema dumper is patched&lt;/strong&gt; to work correctly when default &lt;strong&gt;table prefixes or suffixes&lt;/strong&gt; are used &amp;#8211; they are now removed from schema.rb dump to avoid duplicate prefixes and suffixes when recreating schema from schema.rb.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Legacy schema support&lt;/h3&gt;
&lt;p&gt;Some features which can support &amp;#8220;weird&amp;#8221; legacy database schemas:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If you are using ActiveRecord with legacy schema which have tables with triggers that populate primary key triggers (and not using default Rails and Oracle enhanced adapter conventions) then you can use &lt;code&gt;set_sequence_name :autogenerated&lt;/code&gt; in class definition to tell adapter to omit primary key value from INSERTs.&lt;/li&gt;
	&lt;li&gt;You can use ActiveRecord also with &lt;strong&gt;tables that you can access over database link&lt;/strong&gt;. To do that you need to define local synonym to remote table (and also remote sequence if you want to insert records as well) and then use local synonym in set_table_name in class definition. Previously adapter could not get remote table columns, now it will get table columns also over database link.&lt;br /&gt;
But still you cannot specify remote table (like &amp;#8220;table_name@db_link&amp;#8221;) directly in &lt;code&gt;set_table_name&lt;/code&gt; as table_name will be used as column prefix in generated &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements where &amp;#8220;@db_link&amp;#8221; will not be valid syntax.&lt;br /&gt;
And when you define local synonyms then please use the new &lt;code&gt;add_synonym&lt;/code&gt; feature :)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Connection options&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;cursor_sharing&lt;/code&gt; option default value is changed from &amp;#8220;similar&amp;#8221; to &amp;#8220;&lt;strong&gt;force&lt;/strong&gt;&amp;#8221; &amp;#8211; please read &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced/browse_thread/thread/90d1bfbbc02397b5&quot;&gt;explanation in discussion group post&lt;/a&gt; what it is and why the new default value is recommended choice.&lt;/li&gt;
	&lt;li&gt;When using &lt;strong&gt;JRuby&lt;/strong&gt; and &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; you can set TNS_ADMIN environment variable to tnsnames.ora directory and then use &lt;strong&gt;&lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; database alias&lt;/strong&gt; in database.yml file (specify just database: option and remove host: option). This might be useful for more complex &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; connection definitions, e.g. connection to load balanced Oracle &lt;span class=&quot;caps&quot;&gt;RAC&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;Adapter will not raise error if it cannot locate &lt;strong&gt;ojdbc14.jar&lt;/strong&gt;* file. So either put it in $JRUBY_HOME/lib or ensure that it will be loaded by application server. Would love to hear feedback from people who are using this adapter with JRuby to find out if this behaves well now :)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Logging&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;Now you can get &lt;strong&gt;PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; debugging&lt;/strong&gt; information into your ActiveRecord log file. Use &lt;code&gt;dbms_output.put_line&lt;/code&gt; in your PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures and functions (that are called from ActiveRecord models) and in your ActiveRecord model use &lt;code&gt;connection.enable_dbms_output&lt;/code&gt; and &lt;code&gt;connection.disable_dbms_output&lt;/code&gt; around your database calls to get dbms_output logging information into ActiveRecord log file. But please use it just in development environment with debug log level as in production it would add too much overhead for each database call. And this feature also requires that you install ruby-plsql gem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you see this probably is the largest &amp;#8220;point&amp;#8221; release that I have had :) Thanks also to other contributors which patches were included in this release.&lt;/p&gt;
&lt;p&gt;As always you can install Oracle enhanced adapter on any Ruby platform (Ruby 1.8.6 / 1.8.7 or Ruby 1.9.1 or JRuby) with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;If you have any questions please use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;discussion group&lt;/a&gt; or post comments here.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to install Oracle Database 10g on Mac OS X Snow Leopard</title>
   <link href="http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard/"/>
   <updated>2009-09-14T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://blog.rayapps.com/images/sl_oracle.jpg&quot; alt=&quot;sl_oracle.jpg&quot; border=&quot;0&quot; width=&quot;250&quot; height=&quot;133&quot; align=&quot;right&quot;&gt;Oracle Database 10g is not yet officially supported on new Mac OS X 10.6 Snow Leopard but thanks to comments at my &lt;a href=&quot;http://blog.rayapps.com/2009/04/12/how-to-install-oracle-database-10g-on-mac-os-x-intel/&quot;&gt;previous tutorial&lt;/a&gt; I managed to do Oracle 10g installation on fresh Mac OS X Snow Leopard.&lt;/p&gt;
&lt;p&gt;If you have upgraded from Leopard with Oracle 10g installation to Snow Leopard then most probably Oracle 10g should work fine and you should not do anything. These instructions are just for fresh installation of Snow Leopard.&lt;/p&gt;
&lt;p&gt;And also please take in mind that Oracle 10g on Snow Leopard is not supported yet by Oracle and therefore please do not run critical production applications on it :)&lt;/p&gt;
&lt;p&gt;So here are my updated Oracle 10g installation instructions for Snow Leopard.&lt;/p&gt;
&lt;h3&gt;Initial preparation&lt;/h3&gt;
&lt;p&gt;At first you need Xcode tools installed on your Mac OS X.&lt;/p&gt;
&lt;p&gt;Then you need to create oracle user as well as increase default kernel parameters. Open Terminal and switch to root user:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo -i&lt;/pre&gt;
&lt;p&gt;Create oinstall group and oracle user (I used group and user number 600 to ensure that they do not collide with existing groups and users):&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;dscl . -create /groups/oinstall
dscl . -append /groups/oinstall gid 600
dscl . -append /groups/oinstall passwd &quot;*&quot;
dscl . -create /users/oracle
dscl . -append /users/oracle uid 600
dscl . -append /users/oracle gid 600
dscl . -append /users/oracle shell /bin/bash
dscl . -append /users/oracle home /Users/oracle
dscl . -append /users/oracle realname &quot;Oracle software owner&quot;
mkdir /Users/oracle
chown oracle:oinstall /Users/oracle&lt;/pre&gt;
&lt;p&gt;Change password for oracle user:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;passwd oracle&lt;/pre&gt;
&lt;p&gt;Change default kernel parameters:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi /etc/sysctl.conf&lt;/pre&gt;
&lt;p&gt;and enter values recommended by Oracle:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;kern.sysv.semmsl=87381
kern.sysv.semmns=87381
kern.sysv.semmni=87381
kern.sysv.semmnu=87381
kern.sysv.semume=10
kern.sysv.shmall=2097152
kern.sysv.shmmax=2197815296
kern.sysv.shmmni=4096
kern.maxfiles=65536
kern.maxfilesperproc=65536
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65000
kern.corefile=core
kern.maxproc=2068
kern.maxprocperuid=2068
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Oracle DB installation scripts have reference to Java version 1.4.2 which is not present on Snow Leopard. The easiest way to fix it is to create symbolic link to newer version of Java:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo ln -s /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0 /System/Library/Frameworks/JavaVM.framework/Versions/1.4.2&lt;/pre&gt;
&lt;p&gt;After this reboot your computer so that these new kernel parameters would be taken into effect.&lt;/p&gt;
&lt;p&gt;After reboot you need to log in as new &amp;#8220;Oracle software owner&amp;#8221; user (as now Snow Leopard has stricter control for access to X11 display and therefore I couldn&amp;#8217;t manage to start Oracle installation just from terminal).&lt;/p&gt;
&lt;p&gt;Open Terminal application and set shell settings in .bash_profile&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi .bash_profile&lt;/pre&gt;
&lt;p&gt;and enter&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DISPLAY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;:0.0
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ORACLE_BASE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$HOME&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;umask &lt;/span&gt;022
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Hn 65536
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Sn 65536
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As you see I prefer to install all Oracle related files under home directory of oracle user therefore I am setting ORACLE_BASE to home directory. And also include ulimit settings &amp;#8211; I forgot to do this initially and got strange &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; service errors because of that.&lt;/p&gt;
&lt;p&gt;Now execute this script so that these settings are applied to current shell:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;. ./.bash_profile&lt;/pre&gt;
&lt;p&gt;Now download &lt;a href=&quot;http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10204macsoft_x86-64.html&quot;&gt;db.zip installation archive&lt;/a&gt; and place it somewhere and unzip it:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;mkdir Install
cd Install
# download db.zip to this directory
unzip db.zip
cd db/Disk1&lt;/pre&gt;
&lt;p&gt;Now you are ready to start installation. In Snow Leopard you need to pass -J-d32 option to installation script to force to run Java in 32-bit mode as some native libraries are 32-bit:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;./runInstaller -J-d32&lt;/pre&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;In installation wizard I selected the following options:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Standard Edition &amp;#8211; as I don&amp;#8217;t need additional features of Enterprise Edition&lt;/li&gt;
	&lt;li&gt;Install Software Only &amp;#8211; we will need to do some fixes before database creation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the middle of installation you will get error message &amp;#8220;Error in invoking target &amp;#8216;all_no_orcl ipc_g ihsodbc32&amp;#8217; &amp;#8230;&amp;#8221; (message truncated). Please do not press anything and switch to Terminal application.&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;cd ~/oracle/product/10.2.0/db_1/rdbms/lib
vi ins_rdbms.mk&lt;/pre&gt;
&lt;p&gt;and in this file you need to search for line containing &lt;code&gt;HSODBC_LINKLINE&lt;/code&gt; (in vi enter &lt;code&gt;/HSODBC_LINKLINE&lt;/code&gt;) and comment out this line with putting @# @ in front of it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;#	$(HSODBC_LINKLINE)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and save changed file.&lt;/p&gt;
&lt;p&gt;In this way we disable failing compilation of library which is anyway not needed for our Oracle DB installation.&lt;/p&gt;
&lt;p&gt;After that you can switch back to Oracle installation application and press Retry.&lt;/p&gt;
&lt;p&gt;At the end of installation you will be instructed to run one shell script from root. To do that open new tab in Terminal and execute (substitute &amp;#8220;username&amp;#8221; with your login name):&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;su - username
sudo /Users/oracle/oracle/product/10.2.0/db_1/root.sh&lt;/pre&gt;
&lt;p&gt;Hopefully installation will complete successfully.&lt;/p&gt;
&lt;h3&gt;Creation of database&lt;/h3&gt;
&lt;p&gt;Switch back to Terminal tab with oracle user and add the following lines to .bash_profile of oracle user:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ORACLE_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/oracle/oracle/product/10.2.0/db_1
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ORACLE_HOME&lt;/span&gt;/lib
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ORACLE_SID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;orcl
&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$ORACLE_HOME&lt;/span&gt;/bin
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and execute it&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;. ~/.bash_profile&lt;/pre&gt;
&lt;p&gt;Now you need to modify &lt;code&gt;$ORACLE_HOME/jdk/bin/java&lt;/code&gt; script and change &lt;code&gt;...java -Xbootclasspath...&lt;/code&gt; to &lt;code&gt;...java -d32 -Xbootclasspath...&lt;/code&gt;. This is necessary to force netca and dbca utilities to run in 32-bit mode.&lt;/p&gt;
&lt;p&gt;Now you need to do the major installation hack :) Unfortunately the main oracle executable binary when compiled under Snow Leopard is giving core dumps when starting Oracle database and currently the only way how I managed to fix it is to replace this executable file with the one which was compiled previously under Leopard. So you need to download it in trust me that it is correct :)&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;cd $ORACLE_HOME/bin
curl -O http://rayapps.com/downloads/oracle_se.zip
unzip oracle_se.zip
chmod ug+s oracle
rm oracle_se.zip&lt;/pre&gt;
&lt;p&gt;(If you installed Oracle Enterprise Edition then please substitute &lt;code&gt;oracle_se.zip&lt;/code&gt; with &lt;code&gt;oracle_ee.zip&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;Now you can run Network Configuration Assistant&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;netca&lt;/pre&gt;
&lt;p&gt;and select all default options to create listener and wait until you get confirmation message that listener is configured and started.&lt;/p&gt;
&lt;p&gt;After that you can run Database Configuration Assistant&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;dbca&lt;/pre&gt;
&lt;p&gt;and select&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Create a Database&lt;/li&gt;
	&lt;li&gt;General Purpose&lt;/li&gt;
	&lt;li&gt;Specify orcl as Global Database Name and &lt;span class=&quot;caps&quot;&gt;SID&lt;/span&gt; (or set it to something different if you need)&lt;/li&gt;
	&lt;li&gt;Specify password for &lt;span class=&quot;caps&quot;&gt;SYS&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;SYSTEM&lt;/span&gt; users&lt;/li&gt;
	&lt;li&gt;I selected also Sample Schemas&lt;/li&gt;
	&lt;li&gt;and in Character Sets I selected Use Unicode (AL32UTF8)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of installation I tried to use Password Management to unlock additional schemas but it didn&amp;#8217;t work &amp;#8211; so you need to unlock other sample schemas if needed using sqlplus.&lt;/p&gt;
&lt;p&gt;At the end of installation verify if you can connect to newly created database&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sqlplus system@orcl&lt;/pre&gt;
&lt;p&gt;I hope that my fixes will help you as well and you will be able to connect to database.&lt;/p&gt;
&lt;p&gt;If you want to unlock other sample users then do it from sqlplus, e.g.:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;alter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;account&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unlock&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;identified&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Further instructions are the same as for Leopard and there are no more changes.&lt;/p&gt;
&lt;h3&gt;Change listener to listen on localhost&lt;/h3&gt;
&lt;p&gt;As I need this Oracle database just as local development database on my computer then I want to change the listener so that it would listen just on localhost port 1521:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi $ORACLE_HOME/network/admin/listener.ora&lt;/pre&gt;
&lt;p&gt;and change it to:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /Users/oracle/oracle/product/10.2.0/db_1)
      (PROGRAM = extproc)
    )
    (SID_DESC =
      (SID_NAME = orcl)
      (ORACLE_HOME = /Users/oracle/oracle/product/10.2.0/db_1)
    )
  )
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC0))
    )
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then also change &lt;span class=&quot;caps&quot;&gt;ORCL&lt;/span&gt; alias definition in &lt;code&gt;$ORACLE_HOME/network/admin/tnsnames.ora&lt;/code&gt; to:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;ORCL =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl)
    )
  )
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After this change restart listener and try to connect with sqlplus to verify that these changes are successful.&lt;/p&gt;
&lt;h3&gt;Automatic startup of Oracle database&lt;/h3&gt;
&lt;p&gt;If you want that Oracle database is started automatically when your computer is booted then you need to create the following startup script. Start terminal and switch to root.&lt;/p&gt;
&lt;p&gt;At first edit &lt;code&gt;/etc/oratab&lt;/code&gt; and change N to Y at the end of line for &lt;span class=&quot;caps&quot;&gt;ORCL&lt;/span&gt; database &amp;#8211; this will be used by &lt;code&gt;dbstart&lt;/code&gt; utility to find which databases should be started automatically.&lt;/p&gt;
&lt;p&gt;Then create startup script for Oracle database:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;mkdir /Library/StartupItems/Oracle
cd /Library/StartupItems/Oracle
vi Oracle&lt;/pre&gt;
&lt;p&gt;and enter the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Suppress the annoying &amp;quot;$1: unbound variable&amp;quot; error when no option&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# was given&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -z &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; ; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Usage: $0 [start|stop|restart] &amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# source the common startup script&lt;/span&gt;
. /etc/rc.common

&lt;span class=&quot;c&quot;&gt;# Change the value of ORACLE_HOME to specify the correct Oracle home&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# directory for the installation&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ORACLE_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/oracle/oracle/product/10.2.0/db_1
&lt;span class=&quot;nv&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ORACLE_HOME&lt;/span&gt;/lib
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;ORACLE_HOME DYLD_LIBRARY_PATH

&lt;span class=&quot;c&quot;&gt;# change the value of ORACLE to the login name of the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# oracle owner at your site&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ORACLE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;oracle

&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$ORACLE_HOME&lt;/span&gt;/bin

&lt;span class=&quot;c&quot;&gt;# Set shell limits for the Oracle Database&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Hu 2068
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Su 2068
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Hn 65536
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Sn 65536

StartService&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  ConsoleMessage &lt;span class=&quot;s2&quot;&gt;&amp;quot;Starting Oracle Databases&amp;quot;&lt;/span&gt;
  su &lt;span class=&quot;nv&quot;&gt;$ORACLE&lt;/span&gt; -c &lt;span class=&quot;s2&quot;&gt;&amp;quot;$ORACLE_HOME/bin/dbstart $ORACLE_HOME&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

StopService&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  ConsoleMessage &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stopping Oracle Databases&amp;quot;&lt;/span&gt;
  su &lt;span class=&quot;nv&quot;&gt;$ORACLE&lt;/span&gt; -c &lt;span class=&quot;s2&quot;&gt;&amp;quot;$ORACLE_HOME/bin/dbshut $ORACLE_HOME&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

RestartService&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  StopService
  StartService
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

RunService &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and then make this script executable&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;chmod a+x Oracle&lt;/pre&gt;
&lt;p&gt;and in addition create properties file:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi StartupParameters.plist&lt;/pre&gt;
&lt;p&gt;with the following contents:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;{
  Description     = &amp;quot;Oracle Database Startup&amp;quot;;
  Provides        = (&amp;quot;Oracle Database&amp;quot;);
  Requires        = (&amp;quot;Disks&amp;quot;);
  OrderPreference = &amp;quot;None&amp;quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now you can verify that these scripts are working. Open new terminal and try&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo /Library/StartupItems/Oracle/Oracle stop&lt;/pre&gt;
&lt;p&gt;to stop the database and&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo /Library/StartupItems/Oracle/Oracle start&lt;/pre&gt;
&lt;p&gt;to start again the database. And later you can reboot your computer also to verify that Oracle database will be started automatically.&lt;/p&gt;
&lt;h3&gt;Hide oracle user from login window&lt;/h3&gt;
&lt;p&gt;After computer reboot you probably noticed that now you got oracle user in initial login window. To get rid of it execute this from terminal:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo defaults write /Library/Preferences/com.apple.loginwindow HiddenUsersList -array-add oracle&lt;/pre&gt;
&lt;h3&gt;What next?&lt;/h3&gt;
&lt;p&gt;Now when you have Oracle database installed you would need some development tools that you could use to access the database. Here are some links:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.oracle.com/technology/products/database/sql_developer/index.html&quot;&gt;Oracle &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer&lt;/a&gt; &amp;#8211; free Oracle &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt; tool that supports Mac OS X as well&lt;/li&gt;
	&lt;li&gt;If you would like to use Ruby and Ruby on Rails then check out my tutorial &lt;a href=&quot;http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/&quot;&gt;how to setup Ruby and Oracle client on Snow Leopard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please comment if you find any issues with Oracle Database 10g installation on Snow Leopard using this tutorial.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to setup Ruby and Oracle Instant Client on Snow Leopard</title>
   <link href="http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/"/>
   <updated>2009-09-06T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard</id>
   <content type="html">&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;Mac OS X Snow Leopard is out and many Rubyists are rushing to upgrade to it. The main difference for Ruby after upgrading to Snow Leopard is that Ruby installation has been changed from 32-bit to 64-bit program and version has changed from 1.8.6 to 1.8.7. And it means that all Ruby gems with C extensions should be reinstalled and recompiled using 64-bit external libraries.&lt;/p&gt;
&lt;p&gt;After upgrading to Snow Leopard the first thing to do is to follow &lt;a href=&quot;http://weblog.rubyonrails.org/2009/8/30/upgrading-to-snow-leopard&quot;&gt;instructions on official Ruby on Rails blog&lt;/a&gt;. After that follow instructions below.&lt;/p&gt;
&lt;h3&gt;Installing 64-bit Oracle Instant Client for Intel Mac&lt;/h3&gt;
&lt;p&gt;Download &lt;a href=&quot;http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/intel_macsoft.html&quot;&gt;Oracle Instant Client 64-bit version&lt;/a&gt;. Download &amp;#8220;Instant Client Package &amp;#8211; Basic&amp;#8221;, &amp;#8220;Instant Client Package &amp;#8211; &lt;span class=&quot;caps&quot;&gt;SDK&lt;/span&gt;&amp;#8221; and &amp;#8220;Instant Client Package &amp;#8211; SQL*Plus&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Unzip downloaded archives and move it where you would like to have it &amp;#8211; I am keeping it in &lt;code&gt;/usr/local/oracle/instantclient_10_2&lt;/code&gt; (if you have previous 32-bit Oracle Instant Client in this directory then delete it beforehand). Then go to this directory and make symbolic links for dynamic libraries&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo ln -s libclntsh.dylib.10.1 libclntsh.dylib
sudo ln -s libocci.dylib.10.1 libocci.dylib&lt;/pre&gt;
&lt;p&gt;Then I recommend to create and place somewhere your &lt;code&gt;tnsnames.ora&lt;/code&gt; file where you will keep your database connections definitions &amp;#8211; I place this file in directory &lt;code&gt;/usr/local/oracle/network/admin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then finally you need to set up necessary environment variables &amp;#8211; I place the following definitions in my &lt;code&gt;.bash_profile&lt;/code&gt; script:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/instantclient_10_2&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SQLPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/instantclient_10_2&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TNS_ADMIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/network/admin&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;NLS_LANG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;AMERICAN_AMERICA.UTF8&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$DYLD_LIBRARY_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Use your path to Oracle Instant Client if it differs from &lt;code&gt;/usr/local/oracle/instantclient_10_2&lt;/code&gt;. And as you see I also define &lt;code&gt;NLS_LANG&lt;/code&gt; environment variable &amp;#8211; this is necessary if your database is not in UTF8 encoding but in Ruby you want to get &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 encoded strings from the database. Specifying this NLS_LANG environment variable you will force that Oracle Instant Client will do character set translation.&lt;/p&gt;
&lt;p&gt;After these steps relaunch Terminal application (so that new environment variables are set), specify database connection in &lt;code&gt;tnsnames.ora&lt;/code&gt; file and try if you can access your database with &lt;code&gt;sqlplus&lt;/code&gt; from command line.&lt;/p&gt;
&lt;h3&gt;Install ruby-oci8 gem&lt;/h3&gt;
&lt;p&gt;The latest versions of ruby-oci8 are available as Ruby gems and therefore I recommend to install it as a gem and not to compile and install as library (as I have recommended previously in my blog).&lt;/p&gt;
&lt;p&gt;If you previously installed ruby-oci8 as a library then I recommend to delete it from Ruby installation. Go to &lt;code&gt;/usr/lib/ruby/site_ruby/1.8&lt;/code&gt; directory and remove &lt;code&gt;oci8.rb&lt;/code&gt; file as well as remove &lt;code&gt;oci8lib.bundle&lt;/code&gt; compiled library from either &lt;code&gt;universal-darwin9.0&lt;/code&gt; or &lt;code&gt;universal-darwin10.0&lt;/code&gt; subdirectory.&lt;/p&gt;
&lt;p&gt;Now install ruby-oci8 with the following command:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo env DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH ARCHFLAGS=&quot;-arch x86_64&quot; gem install ruby-oci8&lt;/pre&gt;
&lt;p&gt;It is important to pass &lt;code&gt;DYLD_LIBRARY_PATH&lt;/code&gt; environment variable to sudo (as otherwise ruby-oci8 gem installation will not find Oracle Instant Client) as well as specify &lt;code&gt;ARCHFLAGS&lt;/code&gt; to compile C extension just for 64-bit platform as otherwise it will try to compile both for 32-bit and 64-bit platform.&lt;/p&gt;
&lt;p&gt;Now try&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;ruby -rubygems -e &quot;require 'oci8'; OCI8.new('scott','tiger','orcl').exec('select * from dual') do |r| puts r.join(','); end&quot;&lt;/pre&gt;
&lt;p&gt;or similar (replacing username, password or database alias) to verify that you can access Oracle database from ruby.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it! Please write in comments if something is not working according to these instructions.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Initial version of DataMapper Oracle adapter</title>
   <link href="http://blog.rayapps.com/2009/07/21/initial-version-of-datamapper-oracle-adapter/"/>
   <updated>2009-07-21T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/07/21/initial-version-of-datamapper-oracle-adapter</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://blog.rayapps.com/images/datamapper.jpg&quot; alt=&quot;datamapper.jpg&quot; border=&quot;0&quot; width=&quot;347&quot; height=&quot;91&quot; align=&quot;right&quot; style=&quot;padding:0 4px 4px 8px;&quot; /&gt;&lt;h3&gt;What is DataMapper?&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.datamapper.org&quot;&gt;DataMapper&lt;/a&gt; is Ruby Object/Relational Mapper that is similar to ActiveRecord (component of &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt;) but still it handles several things differently than ActiveRecord.&lt;/p&gt;
&lt;p&gt;I got interested in DataMapper because I liked better some of its design decisions when compared with ActiveRecord. And in particular DataMapper architecture can suite better if you need to work with legacy Oracle database schemas &amp;#8211; that is the area where I use Ruby on Rails a lot and for these purposes I also created &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Oracle enhanced adapter for ActiveRecord&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But as there were no Oracle adapter available for DataMapper I needed to create one :) I started to work on Oracle adapter for DataMapper after the RailsConf and now it is passing all DataMapper tests on all Ruby platforms &amp;#8211; &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8, Ruby 1.9 and JRuby 1.3.&lt;/p&gt;
&lt;h3&gt;Why DataMapper for Oracle database?&lt;/h3&gt;
&lt;p&gt;If you would like to learn main differences between DataMapper and ActiveRecord then please start with &lt;a href=&quot;http://www.datamapper.org/doku.php?id=getting_started_with_datamapper&quot;&gt;this overview&lt;/a&gt; and &lt;a href=&quot;http://www.datamapper.org/doku.php?id=why_datamapper&quot;&gt;this summary of benefits&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here I will mention specific benefits if you would like to use DataMapper with Oracle database.&lt;/p&gt;
&lt;h4&gt;Model properties&lt;/h4&gt;
&lt;p&gt;In DataMapper you always specify in model class definition what Ruby &amp;#8220;type&amp;#8221; you would like to use for each model attribute (or property as called in DataMapper):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Resource&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:post_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;Date&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:created_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DateTime&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:updated_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The main benefit for that is that you can explicitly define when to use Ruby Time, Date or DateTime class which is stored as &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; (or sometimes as &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt;) in Oracle database. In addition you can define your own custom DataMapper types and define how to serialize them into database.&lt;/p&gt;
&lt;h4&gt;Composite primary keys&lt;/h4&gt;
&lt;p&gt;DataMapper core library supports composite primary keys for models. If you use ActiveRecord then there is an option to use additional composite_primary_keys gem but it regularly breaks with latest ActiveRecord versions and quite often it also might break in some edge cases. In DataMapper composite primary keys are defined quite simple:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;City&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Resource&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;Legacy schemas&lt;/h4&gt;
&lt;p&gt;DataMapper is quite useful when you want to put Ruby models on top of existing Oracle schemas. It is possible to provide different database field name for property or provide custom sequence name for primary keys:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Resource&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sequence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post_s&amp;quot;&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can also define one model that can be persisted in two different repositories (e.g. databases or schemas) and use different naming conventions in each repository:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Resource&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post_id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sequence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;post_s&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As a result DataMapper can be used also for data migration between different databases.&lt;/p&gt;
&lt;h4&gt;Bind variables&lt;/h4&gt;
&lt;p&gt;ActiveRecord always generates &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements for execution as one single string. Therefore Oracle enhanced adapter always initializes Oracle session with setting cursor_sharing=&amp;#8216;similar&amp;#8217;. It instructs Oracle always to take all literals (constants) from &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement and replace them with bind variables. It reduces the number of unique &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements generated but also it is some overhead for Oracle optimizer.&lt;/p&gt;
&lt;p&gt;DataMapper always passes all statement parameters separately to corresponding database adapter and therefore it is possible for Oracle adapter to pass all parameters as bind variables to Oracle.&lt;/p&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; values inserting and selecting&lt;/h4&gt;
&lt;p&gt;As for ActiveRecord all inserted values should be passed as literals in &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt; statement it was not possible to insert large &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; values directly in &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt; statement. Therefore ActiveRecord Oracle enhanced adapter did separate call-backs for inserting any &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; data after &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt; of other data. In DataMapper it is possible to insert all data at once as &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; data are passed as bind variables.&lt;/p&gt;
&lt;p&gt;DataMapper also handles better lazy loading of large columns. So if you define property as Text then by default it will not be selected from database &amp;#8211; it will be selected separately only when you use it. Typically it could reduce amount of data that needs to be sent from database to application as Text properties are quite often not needed in e.g. all web pages.&lt;/p&gt;
&lt;h4&gt;Wny not DataMapper?&lt;/h4&gt;
&lt;p&gt;If you are fine with ActiveRecord default conventions and you don&amp;#8217;t have any issues that I listed previously then probably ActiveRecord is good enough for you and you shouldn&amp;#8217;t change to DataMapper. There are of course much more Rails plugins that work with ActiveRecord but not yet with DataMapper. And DataMapper is still much less used and therefore there might some edge cases where it is not tested and you will need to find the issue causes by yourself.&lt;/p&gt;
&lt;p&gt;But if you like to try new things then please try it out &amp;#8211; and also DataMapper community is quite friendly and helpful and will help to solve any issues :)&lt;/p&gt;
&lt;h3&gt;Installation of DataMapper Oracle adapter&lt;/h3&gt;
&lt;p&gt;So if you have decided to try to use DataMapper with Oracle database then follow the instructions how to install it.&lt;/p&gt;
&lt;p&gt;Oracle support is done for current development version 0.10.0 of DataMapper &amp;#8211; therefore you will need to install the latest versions from GitHub (they are still not published as gems on RubyForge).&lt;/p&gt;
&lt;p&gt;DataMapper with Oracle adapter can be used both on &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8.6 (I am not testing it on 1.8.7) and Ruby 1.9.1 as well as on JRuby 1.3. And currently installation is tested on Mac OS X and Linux &amp;#8211; if there is anyone interested in Windows support then please let me know.&lt;/p&gt;
&lt;h4&gt;&lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8.6 or Ruby 1.9.1&lt;/h4&gt;
&lt;p&gt;At first you need to have the same preconditions as for ActiveRecord:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Oracle Instant Cient&lt;/li&gt;
	&lt;li&gt;ruby-oci8 gem, version 2.0.2 or later&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are using Mac then you can use &lt;a href=&quot;/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/&quot;&gt;these instructions&lt;/a&gt; for installation.&lt;/p&gt;
&lt;p&gt;Now at first it is necessary to install DataObjects Oracle driver &amp;#8211; DataObjects library is unified interface to relational databases (like SQLite, MySQL, PostgreSQL, Oracle) that DataMapper uses to access these databases.&lt;/p&gt;
&lt;p&gt;At first validate that you have the latest version of rubygems installed and install necessary additional gems:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem update --system
gem install addressable -v 2.0&lt;/pre&gt;
&lt;p&gt;As I mentioned currently you need to install the latest version from GitHub (at first create and go to directory where you would like to store DataMapper sources):&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;git clone git://github.com/datamapper/extlib.git
cd extlib
git checkout -b next --track origin/next
rake install
cd ..
git clone git://github.com/datamapper/do.git
cd do
git checkout -b next --track origin/next
cd data_objects
rake install
cd ../do_oracle
rake compile
rake install
cd ../..&lt;/pre&gt;
&lt;p&gt;Now if DataObjects installation was successful you can install DataMapper. &lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt;: Oracle adapter is now in &amp;#8220;next&amp;#8221; branch of DataMapper so now you need to install it form there:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;git clone git://github.com/datamapper/dm-core.git
cd dm-core
git checkout -b next --track origin/next
rake install&lt;/pre&gt;
&lt;p&gt;Now start irb and test if you can connect to Oracle database (change database name, username and password according to your setup):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;rubygems&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;dm-core&amp;quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setup&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;oracle://hr:hr@xe&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and try some basic DataMapper operations (I assume that you don&amp;#8217;t have posts table in this schema):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Post&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Resource&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;     &lt;span class=&quot;no&quot;&gt;Serial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sequence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;posts_seq&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;property&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;DataMapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto_migrate!&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Title&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auto_migrate_down!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h4&gt;JRuby&lt;/h4&gt;
&lt;p&gt;At first I assume that you have already installed JRuby latest version (1.3.1 at the moment).&lt;/p&gt;
&lt;p&gt;Then you need to place Oracle &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; driver ojdbc14.jar file in JRUBY_HOME/lib directory (other option is just to put somewhere in &lt;span class=&quot;caps&quot;&gt;PATH&lt;/span&gt;).&lt;/p&gt;
&lt;p&gt;All other installation should be done in the same way &amp;#8211; just use &amp;#8220;jruby -S gem&amp;#8221; instead of &amp;#8220;gem&amp;#8221; and &amp;#8220;jruby -S rake&amp;#8221; instead of &amp;#8220;rake&amp;#8221; and it should install necessary gems for JRuby.&lt;/p&gt;
&lt;p&gt;In addition before installing do_oracle gem you need to install do_jdbc gem (which contains general &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; driver functionality):&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;# after installation of data_objects gem
cd ../do_jdbc
jruby -S rake compile
jruby -S rake install
# continue with do_oracle installation&lt;/pre&gt;
&lt;h4&gt;Other DataMapper gems&lt;/h4&gt;
&lt;p&gt;DataMapper is much more componentized than ActiveRecord. Here I described how to install just the main dm-core gem. You can see the list of &lt;a href=&quot;http://www.datamapper.org/doku.php?id=gem_maintainers&quot;&gt;other gems in DataMapper web site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To install additional DataMapper gems you need to&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;git clone git://github.com/datamapper/dm-more.git
cd dm-more
git checkout -b next --track origin/next
cd dm-some-other-gem
rake install&lt;/pre&gt;
&lt;h3&gt;Questions?&lt;/h3&gt;
&lt;p&gt;This was my first attempt to describe how to start to use DataMapper with Oracle. If you have any questions or something is not working for you then please write comments and I will try to answer and fix any issues in these instructions.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql new version - Ruby 1.9.1 support and more</title>
   <link href="http://blog.rayapps.com/2009/04/21/ruby-plsql-new-version-ruby-191-support-and-more/"/>
   <updated>2009-04-21T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/04/21/ruby-plsql-new-version-ruby-191-support-and-more</id>
   <content type="html">&lt;p&gt;I have released &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql gem&lt;/a&gt; (Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for Oracle PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure calls) new version 0.3.0 which includes several new features.&lt;/p&gt;
&lt;h3&gt;Ruby 1.9.1&lt;/h3&gt;
&lt;p&gt;Probably the most important is support for Ruby 1.9.1 &amp;#8211; now you can use both &lt;a href=&quot;http://blog.rayapps.com/2009/03/23/activerecord-oracle-enhanced-adapter-also-on-jruby-and-ruby-19/&quot;&gt;Oracle enhanced adapter&lt;/a&gt; and ruby-plsql gem on all three major Ruby plaforms:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8.6 with ruby-oci8 1.0.x library or gem&lt;/li&gt;
	&lt;li&gt;Ruby/&lt;span class=&quot;caps&quot;&gt;YARV&lt;/span&gt; 1.9.1 with ruby-oci8 2.0 library or gem (currently just trunk version of ruby-oci8 2.0 contains the last bug fixes for Ruby 1.9.1)&lt;/li&gt;
	&lt;li&gt;JRuby (so far tested with 1.1.6) with &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; Oracle driver&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ActiveRecord connection&lt;/h3&gt;
&lt;p&gt;In addition usage of ruby-plsql gem in Ruby on Rails project is simplified. Now you can include in environment.rb or some initializer file just:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;activerecord_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and you don&amp;#8217;t need to specify plsql.connection anymore &amp;#8211; it will always use current ActiveRecord connection. This is also useful when ActiveRecord reestablishes connection to database as you don&amp;#8217;t need to reestablish plsql connection in this case.&lt;/p&gt;
&lt;p&gt;In addition if you use several different connections to Oracle database then you can assign to &lt;code&gt;plsql.activerecord_class&lt;/code&gt; also different class that inherits from &lt;code&gt;ActiveRecord::Base&lt;/code&gt; and has connection to different database.&lt;/p&gt;
&lt;h3&gt;Database time zone&lt;/h3&gt;
&lt;p&gt;Also you can also specify in which timezone &lt;code&gt;DATE&lt;/code&gt; values are stored in database:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_timezone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;default_timezone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:utc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This will affect how &lt;code&gt;DATE&lt;/code&gt; values (without timezone) will be converted to &lt;code&gt;Time&lt;/code&gt; or &lt;code&gt;DateTime&lt;/code&gt; values (with timezone), default selection is &lt;code&gt;:local&lt;/code&gt; timezone. If you have set &lt;code&gt;plsql.activerecord_class&lt;/code&gt; then the value will be taken from &lt;code&gt;ActiveRecord::Base.default_timezone&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; support&lt;/h3&gt;
&lt;p&gt;You can now use &lt;code&gt;BLOB&lt;/code&gt; data type for input and output parameters and function return values.&lt;br /&gt;
I remind you that also &lt;code&gt;NUMBER&lt;/code&gt;, &lt;code&gt;VARCHAR2&lt;/code&gt;, &lt;code&gt;DATE&lt;/code&gt;, &lt;code&gt;TIMESTAMP&lt;/code&gt; and &lt;code&gt;CLOB&lt;/code&gt; data types are supported,&lt;/p&gt;
&lt;h3&gt;Synonym support&lt;/h3&gt;
&lt;p&gt;Now you can also use private and public database synonyms to functions or procedures or packages.&lt;br /&gt;
E.g. if &lt;code&gt;ORA_LOGIN_USER&lt;/code&gt; is public database synonym to &lt;code&gt;SYS.LOGIN_USER&lt;/code&gt; function then instead of&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;login_user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;you can use&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ora_login_user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;To install the gem as always do&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install ruby-plsql&lt;/pre&gt;
&lt;p&gt;or call the correct gem command version for JRuby or Ruby 1.9.1.&lt;/p&gt;
&lt;p&gt;Source code of ruby-plsql is located at &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;GitHub&lt;/a&gt; where you can find usage examples in RSpec tests.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to install Oracle Database 10g on Mac OS X Intel</title>
   <link href="http://blog.rayapps.com/2009/04/12/how-to-install-oracle-database-10g-on-mac-os-x-intel/"/>
   <updated>2009-04-12T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2009/04/12/how-to-install-oracle-database-10g-on-mac-os-x-intel</id>
   <content type="html">&lt;blockquote class=&quot;warning&quot;&gt;
&lt;p class=&quot;warning&quot;&gt;&lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt;: &lt;a href=&quot;http://blog.rayapps.com/2009/09/14/how-to-install-oracle-database-10g-on-mac-os-x-snow-leopard/&quot;&gt;Created instructions how to install Oracle 10g on Mac OS X Snow Leopard&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Couple days ago Oracle developers on Mac OS X received Easter present &amp;#8211; finally &lt;a href=&quot;http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10204macsoft_x86-64.html&quot;&gt;Oracle Database 10g was released for Mac OS X 10.5 Intel platform&lt;/a&gt;. This download includes installation guide for Mac OS X but as any Oracle installation guide it is quite long and contains a lot of unnecessary information for first time install as well as does not contain some necessary information.&lt;/p&gt;
&lt;p&gt;Therefore I am posting here my shorter tutorial how to install it. And this tutorial is targeted to developers who want to install local Oracle database for development needs on their MacBook, iMac or Mac Pro.&lt;/p&gt;
&lt;h3&gt;Initial preparation&lt;/h3&gt;
&lt;p&gt;If you are a developer then I suppose you already have Xcode tools installed which are required also for Oracle installation. And I tried these steps on Mac OS X latest version 10.5.6.&lt;/p&gt;
&lt;p&gt;Then you need to create oracle user as well as increase default kernel parameters. Open Terminal and switch to root user:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo -i&lt;/pre&gt;
&lt;p&gt;Create oinstall group and oracle user (I used group and user number 600 to ensure that they do not collide with existing groups and users):&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;dscl . -create /groups/oinstall
dscl . -append /groups/oinstall gid 600
dscl . -append /groups/oinstall passwd &quot;*&quot;
dscl . -create /users/oracle
dscl . -append /users/oracle uid 600
dscl . -append /users/oracle gid 600
dscl . -append /users/oracle shell /bin/bash
dscl . -append /users/oracle home /Users/oracle
dscl . -append /users/oracle realname &quot;Oracle software owner&quot;
mkdir /Users/oracle
chown oracle:oinstall /Users/oracle&lt;/pre&gt;
&lt;p&gt;Change password for oracle user:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;passwd oracle&lt;/pre&gt;
&lt;p&gt;Change default kernel parameters:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi /etc/sysctl.conf&lt;/pre&gt;
&lt;p&gt;and enter values recommended by Oracle:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;kern.sysv.semmsl=87381
kern.sysv.semmns=87381
kern.sysv.semmni=87381
kern.sysv.semmnu=87381
kern.sysv.semume=10
kern.sysv.shmall=2097152
kern.sysv.shmmax=2197815296
kern.sysv.shmmni=4096
kern.maxfiles=65536
kern.maxfilesperproc=65536
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65000
kern.corefile=core
kern.maxproc=2068
kern.maxprocperuid=2068&lt;/pre&gt;
&lt;p&gt;After this reboot your computer so that these new kernel parameters would be taken into effect. After reboot open again Terminal and now login as oracle user:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;su - oracle&lt;/pre&gt;
&lt;p&gt;Set shell settings in .bash_profile&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi .bash_profile&lt;/pre&gt;
&lt;p&gt;and enter&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;export DISPLAY=:0.0
export ORACLE_BASE=$HOME
umask 022
ulimit -Hn 65536
ulimit -Sn 65536&lt;/pre&gt;
&lt;p&gt;As you see I prefer to install all Oracle related files under home directory of oracle user therefore I am setting ORACLE_BASE to home directory. And also include ulimit settings &amp;#8211; I forgot to do this initially and got strange &lt;span class=&quot;caps&quot;&gt;TNS&lt;/span&gt; service errors because of that.&lt;/p&gt;
&lt;p&gt;Now execute this script so that these settings are applied to current shell:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;. ./.bash_profile&lt;/pre&gt;
&lt;p&gt;Now download &lt;a href=&quot;http://www.oracle.com/technology/software/products/database/oracle10g/htdocs/10204macsoft_x86-64.html&quot;&gt;db.zip installation archive&lt;/a&gt; and place it somewhere and unzip it:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;mkdir Install
cd Install
# download db.zip to this directory
unzip db.zip
cd db/Disk1&lt;/pre&gt;
&lt;p&gt;Now you are ready to start installation:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;./runInstaller&lt;/pre&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;In installation wizard I selected the following options:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Advanced Installation &amp;#8211; so that I can change some default options&lt;/li&gt;
	&lt;li&gt;Standard Edition &amp;#8211; as I don&amp;#8217;t need additional features of Enterprise Edition&lt;/li&gt;
	&lt;li&gt;Create Database / General Purpose&lt;/li&gt;
	&lt;li&gt;Global database name: orcl, &lt;span class=&quot;caps&quot;&gt;SID&lt;/span&gt;: orcl&lt;/li&gt;
	&lt;li&gt;Character set: &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 AL32UTF8&lt;/li&gt;
	&lt;li&gt;Create database with sample schemas&lt;/li&gt;
	&lt;li&gt;Selected &amp;#8220;Use the same password for all the accounts&amp;#8221; &amp;#8211; do not specify default &amp;#8220;manager&amp;#8221; password as it will not be allowed :)&lt;/li&gt;
	&lt;li&gt;Password Management &amp;#8211; selected this to unlock necessary sample accounts (e.g. HR schema account that I use as default test schema)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of installation you will be instructed to run one shell script from root.&lt;br /&gt;
Hopefully installation will complete successfully.&lt;/p&gt;
&lt;h3&gt;Additional oracle user settings&lt;/h3&gt;
&lt;p&gt;If you will use oracle user later then add the following lines to .bash_profile of oracle user:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;export ORACLE_HOME=/Users/oracle/oracle/product/10.2.0/db_1
export DYLD_LIBRARY_PATH=$ORACLE_HOME/lib
export ORACLE_SID=ORCL
PATH=$PATH:$ORACLE_HOME/bin&lt;/pre&gt;
&lt;p&gt;After this relogin as oracle user and verify listener status:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;lsnrctl status&lt;/pre&gt;
&lt;p&gt;and if it is down then start it with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;lsnrctl start&lt;/pre&gt;
&lt;p&gt;and verify if you can connect to Oracle database with sample user (that I unlocked during installation)&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sqlplus hr/hr@orcl&lt;/pre&gt;
&lt;p&gt;If it fails then do some investigation :)&lt;/p&gt;
&lt;h3&gt;Change listener to listen on localhost&lt;/h3&gt;
&lt;p&gt;As I need this Oracle database just as local development database on my computer then I want to change the listener so that it would listen just on localhost port 1521:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi $ORACLE_HOME/network/admin/listener.ora&lt;/pre&gt;
&lt;p&gt;and change the contents of the file to:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /Users/oracle/oracle/product/10.2.0/db_1)
      (PROGRAM = extproc)
    )
    (SID_DESC =
      (SID_NAME = orcl)
      (ORACLE_HOME = /Users/oracle/oracle/product/10.2.0/db_1)
    )
  )
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
      (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    )
  )&lt;/pre&gt;
&lt;p&gt;Then also change &lt;span class=&quot;caps&quot;&gt;ORCL&lt;/span&gt; alias definition in $ORACLE_HOME/network/admin/tnsnames.ora to:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;ORCL =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = orcl)
    )
  )&lt;/pre&gt;
&lt;p&gt;After this change restart listener and try to connect with sqlplus to verify that these changes are successful.&lt;/p&gt;
&lt;h3&gt;Automatic startup of Oracle database&lt;/h3&gt;
&lt;p&gt;If you want that Oracle database is started automatically when your computer is booted then you need to create the following startup script. Start terminal and switch to root.&lt;/p&gt;
&lt;p&gt;At first edit /etc/oratab and change N to Y at the end of line for &lt;span class=&quot;caps&quot;&gt;ORCL&lt;/span&gt; database &amp;#8211; this will be used by dbstart utility to find which databases should be started automatically.&lt;/p&gt;
&lt;p&gt;Then create startup script for Oracle database:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;mkdir /Library/StartupItems/Oracle
cd /Library/StartupItems/Oracle
vi Oracle&lt;/pre&gt;
&lt;p&gt;and enter the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Suppress the annoying &amp;quot;$1: unbound variable&amp;quot; error when no option&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# was given&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -z &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; ; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Usage: $0 [start|stop|restart] &amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;1
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# source the common startup script&lt;/span&gt;
. /etc/rc.common

&lt;span class=&quot;c&quot;&gt;# Change the value of ORACLE_HOME to specify the correct Oracle home&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# directory for the installation&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ORACLE_HOME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/oracle/oracle/product/10.2.0/db_1
&lt;span class=&quot;nv&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$ORACLE_HOME&lt;/span&gt;/lib
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;ORACLE_HOME DYLD_LIBRARY_PATH

&lt;span class=&quot;c&quot;&gt;# change the value of ORACLE to the login name of the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# oracle owner at your site&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;ORACLE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;oracle

&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$ORACLE_HOME&lt;/span&gt;/bin

&lt;span class=&quot;c&quot;&gt;# Set shell limits for the Oracle Database&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Hu 2068
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Su 2068
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Hn 65536
&lt;span class=&quot;nb&quot;&gt;ulimit&lt;/span&gt; -Sn 65536

StartService&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  ConsoleMessage &lt;span class=&quot;s2&quot;&gt;&amp;quot;Starting Oracle Databases&amp;quot;&lt;/span&gt;
  su &lt;span class=&quot;nv&quot;&gt;$ORACLE&lt;/span&gt; -c &lt;span class=&quot;s2&quot;&gt;&amp;quot;$ORACLE_HOME/bin/dbstart $ORACLE_HOME&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

StopService&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  ConsoleMessage &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stopping Oracle Databases&amp;quot;&lt;/span&gt;
  su &lt;span class=&quot;nv&quot;&gt;$ORACLE&lt;/span&gt; -c &lt;span class=&quot;s2&quot;&gt;&amp;quot;$ORACLE_HOME/bin/dbshut $ORACLE_HOME&amp;quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

RestartService&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  StopService
  StartService
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

RunService &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and then make this script executable&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;chmod a+x Oracle&lt;/pre&gt;
&lt;p&gt;and in addition create properties file:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;vi StartupParameters.plist&lt;/pre&gt;
&lt;p&gt;with the following contents:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;{
  Description     = &quot;Oracle Database Startup&quot;;
  Provides        = (&quot;Oracle Database&quot;);
  Requires        = (&quot;Disks&quot;);
  OrderPreference = &quot;None&quot;;
}&lt;/pre&gt;
&lt;p&gt;Now you can verify that these scripts are working. Open new terminal and try&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo /Library/StartupItems/Oracle/Oracle stop&lt;/pre&gt;
&lt;p&gt;to stop the database and&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo /Library/StartupItems/Oracle/Oracle start&lt;/pre&gt;
&lt;p&gt;to start again the database. And later you can reboot your computer also to verify that Oracle database will be started automatically.&lt;/p&gt;
&lt;h3&gt;Hide oracle user from login window&lt;/h3&gt;
&lt;p&gt;After computer reboot you probably noticed that now you got oracle user in initial login window. To get rid of it execute this from terminal:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo defaults write /Library/Preferences/com.apple.loginwindow HiddenUsersList -array-add oracle&lt;/pre&gt;
&lt;h3&gt;What next?&lt;/h3&gt;
&lt;p&gt;Now when you have Oracle database installed you would need some development tools that you could use to access the database. Here are some links:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.oracle.com/technology/products/database/sql_developer/index.html&quot;&gt;Oracle &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; Developer&lt;/a&gt; &amp;#8211; free Oracle &lt;span class=&quot;caps&quot;&gt;GUI&lt;/span&gt; tool that supports Mac OS X as well&lt;/li&gt;
	&lt;li&gt;If you would like to use Ruby and Ruby on Rails then check out my tutorial &lt;a href=&quot;http://blog.rayapps.com/2008/04/24/how-to-setup-ruby-and-new-oracle-instant-client-on-leopard/&quot;&gt;how to setup Ruby and Oracle client&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;If you would like to use &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; then &lt;a href=&quot;http://www.oracle.com/technology/pub/articles/bibbs-php-leopard.html&quot;&gt;you can check out this tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Please comment if you find any issues with Oracle Database 10g installation using this tutorial.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Oracle enhanced adapter also on JRuby and Ruby 1.9</title>
   <link href="http://blog.rayapps.com/2009/03/23/activerecord-oracle-enhanced-adapter-also-on-jruby-and-ruby-19/"/>
   <updated>2009-03-23T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2009/03/23/activerecord-oracle-enhanced-adapter-also-on-jruby-and-ruby-19</id>
   <content type="html">&lt;p&gt;So far if you wanted to use Ruby on Rails on Oracle database you needed to use different adapters depending on the Ruby platform that you wanted to use. If you used original &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; (Matz Ruby interpreter) 1.8.6 then hopefully you were using Oracle enhanced adapter. But if you wanted to use JRuby then you needed to use &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; adapter that is maintained by JRuby team (and which sometimes might work differently than Oracle enhanced adapter). And if you wanted to use new Ruby 1.9.1 then you were out of luck as no adapter supported it.&lt;/p&gt;
&lt;p&gt;Therefore I wanted to announce great news that &lt;strong&gt;ActiveRecord Oracle enhanced adapter 1.2.0 is released&lt;/strong&gt; and it supports &lt;strong&gt;all three major Ruby platforms!&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Use Oracle enhanced adapter on &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; 1.8.6 with ruby-oci8 1.0.x library or gem&lt;/li&gt;
	&lt;li&gt;Use Oracle enhanced adapter on JRuby (so far tested with 1.1.6) with &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; Oracle driver&lt;/li&gt;
	&lt;li&gt;Use Oracle enhanced adapter on Ruby/&lt;span class=&quot;caps&quot;&gt;YARV&lt;/span&gt; 1.9.1 with ruby-oci8 2.0 library or gem&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This provides you with much more flexibility to develop on one Ruby platform but deploy on another and on all three platforms you can use &lt;a href=&quot;http://wiki.github.com/rsim/oracle-enhanced/usage&quot;&gt;the same additional functionality&lt;/a&gt; that Oracle enhanced adapter provides on top of standard ActiveRecord functionality.&lt;/p&gt;
&lt;p&gt;And during testing of Oracle enhanced adapter on all platforms additional milestone was achieved &amp;#8211; &lt;strong&gt;Oracle enhanced adapter passes 100% ActiveRecord unit tests!&lt;/strong&gt; But to be honest I need to tell that I needed to patch quite many unit tests for Oracle specifics as not all &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; that runs on MySQL is also valid on Oracle. I published my patched branch of ActiveRecord unit tests at my &lt;a href=&quot;http://github.com/rsim/rails/tree/oracle_enhanced&quot;&gt;GitHub fork of Rails&lt;/a&gt; &amp;#8211; you can clone the repository and verify by yourself.&lt;/p&gt;
&lt;p&gt;So please try out new version of Oracle enhanced adapter on any Ruby platform:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;gem install activerecord-oracle_enahnced-adapter&lt;/pre&gt;
&lt;p&gt;If you have any questions please use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;discussion group&lt;/a&gt; or post comments here. In nearest future I will also add more instructions how to install Oracle enhanced adapter on JRuby and Ruby 1.9.1 at &lt;a href=&quot;http://wiki.github.com/rsim/oracle-enhanced&quot;&gt;GitHub wiki page&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>More information sources on ActiveRecord Oracle enhanced adapter</title>
   <link href="http://blog.rayapps.com/2009/01/03/more-information-sources-on-activerecord-oracle-enhanced-adapter/"/>
   <updated>2009-01-03T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2009/01/03/more-information-sources-on-activerecord-oracle-enhanced-adapter</id>
   <content type="html">&lt;p&gt;I&amp;#8217;m glad to see that there are many users of &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;ActiveRecord Oracle enhanced adapter&lt;/a&gt; and therefore comments in this blog is not anymore the best way how to communicate with Oracle enhanced adapter users. Therefore I created several other information exchange places which I hope will be more effective.&lt;/p&gt;
&lt;p&gt;The latest addition is &lt;a href=&quot;http://github.com/rsim/oracle-enhanced/wikis&quot;&gt;wiki pages on GitHub&lt;/a&gt; where I put usage description and examples as well as some troubleshooting hints that previously were scattered in &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; file and different blog posts. This is the first place where to look for information about Oracle enhanced adapter. And if you are GitHub user then you can correct mistakes or add additional content also by yourself.&lt;/p&gt;
&lt;p&gt;If you have some question or you would like to discuss some feature then you can use &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced&quot;&gt;Google discussion group&lt;/a&gt;. I will use this discussion group also for new release announcements as well so subscribe to it if you would like to get Oracle enhanced adapter news.&lt;/p&gt;
&lt;p&gt;If you would like to report some bug or new feature (and patch would be greatly appreciated) then please use &lt;a href=&quot;http://rsim.lighthouseapp.com/projects/11468-oracle-enhanced&quot;&gt;Lighthouse issue tracker&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And source code of Oracle enhanced adapter is still located in &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;Github repository&lt;/a&gt;. If you are GitHub user then you can watch it or even fork it and experiment with some new features.&lt;/p&gt;
&lt;p&gt;And &lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt; I just released &lt;a href=&quot;http://groups.google.com/group/oracle-enhanced/browse_thread/thread/874e196fb3d76e89&quot;&gt;Oracle enhanced adapter version 1.1.9&lt;/a&gt; with some new features and it has been also tested with latest Rails 2.2 release.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>NTLM Windows domain authentication for Rails application</title>
   <link href="http://blog.rayapps.com/2008/12/02/ntlm-windows-domain-authentication-for-rails-application/"/>
   <updated>2008-12-02T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2008/12/02/ntlm-windows-domain-authentication-for-rails-application</id>
   <content type="html">&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;http://blog.rayapps.com/images/railspluswindows.png&quot; border=&quot;0&quot; alt=&quot;RailsPlusWindows.png&quot; width=&quot;239&quot; height=&quot;96&quot; align=&quot;right&quot; /&gt;In one &amp;#8220;enterprise&amp;#8221; Ruby on Rails project we had an idea to integrate Windows domain user authentication with Rails application — as majority of users were using Windows and Internet Explorer and always were logged in Windows domain then it would be very good if they could log in automatically to the new Rails application without entering their username and password.&lt;/p&gt;
&lt;p&gt;Windows is using &lt;a href=&quot;http://en.wikipedia.org/wiki/NTLM&quot;&gt;&lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; protocol&lt;/a&gt; to provide such functionality — basically it uses additional &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; headers to negotiate authentication information between web server and browser. It is tightly integrated into Microsoft Internet Information Server and if you live in pure Windows world then implementation of &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication is just a checkbox in &lt;span class=&quot;caps&quot;&gt;IIS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;But if you are using Ruby on Rails with Apache web server in front of it and running everything on Linux or other Unix then this is not so simple. Therefore I wanted to share my solution how I solved this problem.&lt;/p&gt;
&lt;h3&gt;mod_ntlm Apache module installation&lt;/h3&gt;
&lt;p&gt;The first step is that we need &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; protocol support for Apache web server so that it could handle Windows domain user authentication with web browser.&lt;/p&gt;
&lt;p&gt;The first thing I found was &lt;a href=&quot;http://modntlm.sourceforge.net/&quot;&gt;mod_ntlm&lt;/a&gt;, but unfortunately this project is inactive for many years and do not have support for Apache 2.2 that I am using.&lt;/p&gt;
&lt;p&gt;The other option I found was &lt;a href=&quot;http://adldap.sourceforge.net/wiki/doku.php?id=mod_auth_ntlm_winbind&quot;&gt;mod_auth_ntlm_winbind&lt;/a&gt; from Samba project but this solution requires Samba&amp;#8217;s winbind daemon on the same server which makes the whole configuration more complex and therefore I was not eager to do that.&lt;/p&gt;
&lt;p&gt;Then finally I found that someone has &lt;a href=&quot;http://mywheel.net/blog/index.php/mod_ntlm2-on-apache-22x/&quot;&gt;patched mod_ntlm to work with Apache 2.2&lt;/a&gt; and this looked promising. I took this version of mod_ntlm but in addition I needed to make some additional patches to it and as a result I published &lt;a href=&quot;http://github.com/rsim/mod_ntlm&quot;&gt;my final mod_ntlm version in my GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you would like to &lt;strong&gt;install mod_ntlm module on Linux&lt;/strong&gt; then at first ensure that you have Apache 2.2 installed together with Apache development utilities (check that you have either apxs or apxs2 utility in your path). Then from the source directory of &lt;code&gt;mod_ntlm&lt;/code&gt; (that you downloaded from my GitHub repository) do:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;apxs -i -a -c mod_ntlm.c&lt;/pre&gt;
&lt;p&gt;If everything goes well then it should install &lt;code&gt;mod_ntlm.so&lt;/code&gt; module in the directory where all other Apache modules is installed. It also tries to add module load directive in Apache configuration file &lt;code&gt;httpd.conf&lt;/code&gt; but please check by yourself that you have&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;nb&quot;&gt;LoadModule&lt;/span&gt; ntlm_module ...directory.path.../mod_ntlm.so
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;line in your configuration file and directory path is the same as for other Apache modules. Try to restart Apache server to see if the module will be successfully loaded.&lt;/p&gt;
&lt;p&gt;I also managed to &lt;strong&gt;install mod_ntlm on my Mac OS X Leopard&lt;/strong&gt; so that I could later test &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication locally. Installation on Mac OS X was a little bit more tricky as I needed to compile 64-bit architecture module to be able to load it with preinstalled Apache:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo ln -s /usr/include/malloc/malloc.h /usr/include/malloc.h
sudo ln -s /usr/include/sys/statvfs.h /usr/include/sys/vfs.h
apxs -c -o mod_ntlm.so -Wc,&quot;-shared -arch i386 -arch x86_64&quot; -Wl,&quot;-arch i386 -arch x86_64&quot; mod_ntlm.c
sudo apxs -i -a -n 'ntlm' mod_ntlm.so&lt;/pre&gt;
&lt;p&gt;After this check &lt;code&gt;/etc/apache2/httpd.conf&lt;/code&gt; file that it includes:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;nb&quot;&gt;LoadModule&lt;/span&gt; ntlm_module        libexec/apache2/mod_ntlm.so
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and try to restart Apache with&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo apachectl -k restart&lt;/pre&gt;
&lt;h3&gt;mod_ntlm Apache module configuration&lt;/h3&gt;
&lt;p&gt;The next thing is that you need to configure &lt;code&gt;mod_ntlm&lt;/code&gt;. Put these configuration directories in the same place where you have your virtual host configuration directives related to your Rails application. Let&amp;#8217;s assume that we have domain &amp;#8220;domain.com&amp;#8221; with domain controllers &amp;#8220;dc01.domain.com&amp;#8221; and &amp;#8220;dc02.domain.com&amp;#8221;. And let&amp;#8217;s use /winlogin as a &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; which will be used for Windows domain authentication.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;nb&quot;&gt;RewriteEngine&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;On&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;Location&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/winlogin&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;AuthName&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;My Application&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;AuthType&lt;/span&gt; NTLM
  &lt;span class=&quot;nb&quot;&gt;NTLMAuth&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;on&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;NTLMAuthoritative&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;on&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;NTLMDomain&lt;/span&gt; domain.com
  &lt;span class=&quot;nb&quot;&gt;NTLMServer&lt;/span&gt; dc01.domain.com
  &lt;span class=&quot;nb&quot;&gt;NTLMBackup&lt;/span&gt; dc02.domain.com
  &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; valid-user
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;mod_ntlm&lt;/code&gt; will set &lt;code&gt;REMOTE_USER&lt;/code&gt; environment variable with authenticated Windows username. If we are using Mongrel servers cluster behind Apache web server then we need to add the following configuration lines to put &lt;code&gt;REMOTE_USER&lt;/code&gt; in &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; header X-Forwarded-User of forwarded request to Mongrel cluster.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;nb&quot;&gt;RewriteCond&lt;/span&gt; %{LA-U:REMOTE_USER} (.+)
&lt;span class=&quot;nb&quot;&gt;RewriteRule&lt;/span&gt; . - [E=RU:%1]
&lt;span class=&quot;nb&quot;&gt;RequestHeader&lt;/span&gt; add X-Forwarded-User %{RU}e
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Please remember to put all previous configuration lines before any other &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; rewriting directives. In my case I have the following configuration lines which will forward all non-static requests to my Mongrel servers cluster (which in my case have HAproxy on port 3000 before them):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Redirect all non-static requests to haproxy&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;RewriteCond&lt;/span&gt; %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
&lt;span class=&quot;nb&quot;&gt;RewriteRule&lt;/span&gt; ^/(.*)$ http://127.0.0.1:3000%{REQUEST_URI} [L,P,QSA]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Rails sessions controller&lt;/h3&gt;
&lt;p&gt;Now the final part is to handle authenticated Windows users in Rails sessions controller. Here are examples how I am doing this.&lt;/p&gt;
&lt;p&gt;routes.rb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;winlogin&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;winlogin&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;sessions&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;create_from_windows_login&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;sessions_controller.rb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_from_windows_login&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;login&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;forwarded_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Browser did not provide Windows domain user name&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authenticated_by_windows_domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# user has access rights to system&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;User has no access rights to application&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;logged_in?&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# store that next time automatic login should be made&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:windows_domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;true&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:expires&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;month&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Because of IE NTLM strange behavior need to give 401 response with Javascript redirect&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@redirect_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect_back_or_default_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;root_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:layout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;redirect&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;new&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;forwarded_user&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_forwarded_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;X-Forwarded-User&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x_forwarded_user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;(null)&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;User.authenticated_by_windows_domain&lt;/code&gt; is model method that either find existing or creates new user based on authenticated Windows username in parameter and checks that user has access rights. Private method forwarded_user extracts Windows username from &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; header — in my case it always was formatted as &amp;#8220;(null),username&amp;#8221; therefore I needed to remove unnecessary &amp;#8220;(null)&amp;#8221; from it.&lt;/p&gt;
&lt;p&gt;In addition I am storing browser cookie that user used Windows domain authentication — it means that next time we can forward this user directly to &lt;code&gt;/winlogin&lt;/code&gt; instead of showing login page if user has this cookie. We cannot forward all users to &lt;code&gt;/winlogin&lt;/code&gt; as then for all users browser will prompt for Windows username and password (and probably we are also using other authentication methods).&lt;/p&gt;
&lt;p&gt;The last thing is that we need to do a little hack as a workaround for strange Internet Explorer behavior. If Internet Explorer has authenticated with some web server using &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; protocol then IE will  think that this web server will require &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication for all &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; requests. And therefore it does &amp;#8220;performance optimization&amp;#8221; when doing &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; requests to this web server — the first &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; request from browser will have no &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; data in it, just header with &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication message. In Rails application case we do not need these &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentications for all &lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt; requests as we are maintaining Rails session to identify logged in users. Therefore we are making this trick that after successful authentication we return &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; 401 code which makes IE think that it is not authenticated anymore with this web server. But together with &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; 401 code we return &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; page which forces client side redirect to home page either using JavaScript or&lt;/p&gt;
&lt;p&gt;create_from_windows_login.html.erb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;erb&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:head&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  &amp;lt;script language=&amp;quot;javascript&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    &amp;lt;!--&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;      location.replace(&amp;quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@redirect_to&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&amp;quot;);&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    //--&amp;gt;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  &amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  &amp;lt;noscript&amp;gt;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;    &amp;lt;meta http-equiv=&amp;quot;Refresh&amp;quot; content=&amp;quot;0; URL=&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@redirect_to&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&amp;quot; /&amp;gt;&lt;/span&gt;
&lt;span class=&quot;x&quot;&gt;  &amp;lt;/noscript&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Redirecting...&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@redirect_to&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;content_for :head&lt;/code&gt; is used to specify which additional content should be put in &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; part of layout.&lt;/p&gt;
&lt;p&gt;As a result you now have basic Windows domain &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication working. Please let me know in comments if you have any issues with this solution or if you have other suggestions how to use Windows domain &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication in Rails applications.&lt;/p&gt;
&lt;h3&gt;Additional hints&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication can be used also in Firefox. Enter &lt;code&gt;about:config&lt;/code&gt; in location field and then search for &lt;code&gt;network.automatic-ntlm-auth.trusted-uris&lt;/code&gt;. There you can enter servers for which you would like to use automatic &lt;span class=&quot;caps&quot;&gt;NTLM&lt;/span&gt; authentication.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>OpenWorld unconference presentation about Rails on Oracle</title>
   <link href="http://blog.rayapps.com/2008/09/26/openworld-unconference-presentation-about-rails-on-oracle/"/>
   <updated>2008-09-26T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/09/26/openworld-unconference-presentation-about-rails-on-oracle</id>
   <content type="html">&lt;p&gt;On last day of Oracle OpenWorld I did my &lt;a href=&quot;http://wiki.oracle.com/page/Oracle+OpenWorld+Unconference&quot;&gt;unconference&lt;/a&gt; presentation &amp;#8211; Using Ruby on Rails with legacy Oracle databases.&lt;/p&gt;
&lt;p&gt;As I did not know if anyone will come to listen to it I was glad that six people attended (including &lt;a href=&quot;http://db360.blogspot.com/&quot;&gt;Kuassi Mensah&lt;/a&gt; from Oracle who is helping to promote Ruby support inside Oracle). And on the previous day I also managed to show parts of my presentation to Rich and Anthony from &lt;a href=&quot;http://theappslab.com/&quot;&gt;Oracle AppsLab&lt;/a&gt; team.&lt;/p&gt;
&lt;p&gt;I published my slides on Slideshare:&lt;br /&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;object id=&quot;__sse619018&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=using-rails-with-legacy-oracle-db-1222386749548113-9&amp;stripped_title=using-ruby-on-rails-with-legacy-oracle-databases-presentation&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;/&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;/&gt;&lt;embed name=&quot;__sse619018&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=using-rails-with-legacy-oracle-db-1222386749548113-9&amp;stripped_title=using-ruby-on-rails-with-legacy-oracle-databases-presentation&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;And I published &lt;a href=&quot;http://github.com/rsim/legacy_oracle_sample&quot;&gt;my demo project&lt;/a&gt; on GitHub:&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/hr-schema-demo.png&quot; border=&quot;0&quot; alt=&quot;hr_schema_demo.png&quot; width=&quot;640&quot; height=&quot;231&quot; /&gt;&lt;/div&gt;
&lt;p&gt;Thanks to all Oracle people who recognize my work on Ruby and Oracle integration and I hope that our common activities will increase number of Ruby and Rails projects on Oracle :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Some positive drag-and-drop experience</title>
   <link href="http://blog.rayapps.com/2008/09/24/some-positive-drag-and-drop-experience/"/>
   <updated>2008-09-24T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/09/24/some-positive-drag-and-drop-experience</id>
   <content type="html">&lt;p&gt;In the &lt;a href=&quot;/2008/09/22/coding-or-drag-and-droping/&quot;&gt;previous post&lt;/a&gt; I wrote that I didn&amp;#8217;t quite like drag-and-drop development style in JDeveloper that I experienced during Oracle OpenWorld hands-on session.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/oracle-bi.png&quot; alt=&quot;oracle_bi.png&quot; border=&quot;0&quot; width=&quot;640&quot; height=&quot;279&quot; /&gt;&lt;/div&gt;
&lt;p&gt;Today I was in &lt;a href=&quot;http://www.oracle.com/technology/products/bi/enterprise-edition.html&quot;&gt;Oracle BI Answers &amp;amp; Dashboard&lt;/a&gt; hands-on session and during this session I was also drag-and-dropping to create reports, charts and business intelligence dashboards. But in this case I liked it as it seemed natural way how to create such reports.&lt;/p&gt;
&lt;p&gt;The main difference why I liked it was that I got immediate feedback how the end report will look like &amp;#8211; after each change I could immediately see and test real report with real data. And such immediate feedback is key prerequisite for interactive analytical reporting development.&lt;/p&gt;
&lt;p&gt;In JDeveloper case I needed to compile and build everything and restart local application server after each change to see real results from any change &amp;#8211; and it took at least 10 seconds for just sample &amp;#8220;hello world&amp;#8221; application. I assume that this lag will be even longer in larger real projects. Probably it is not so long time but when you compare it to 1 second feedback time then anything larger seems long.&lt;/p&gt;
&lt;p&gt;I also visited Oracle demo grounds where I discussed my concerns regarding JDeveloper drag-and-drop development style. At the end we reached common understanding that JDeveloper and &lt;span class=&quot;caps&quot;&gt;ADF&lt;/span&gt; framework is really good for former Oracle Forms developers who do not want to learn &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; and Javascript and auto-generated applications could be quite OK for internal enterprise applications. But if you want to build advanced web applications you still need to learn and be expert in these web technologies (&lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; and Javascript).&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Coding or drag-and-dropping?</title>
   <link href="http://blog.rayapps.com/2008/09/22/coding-or-drag-and-droping/"/>
   <updated>2008-09-22T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/09/22/coding-or-drag-and-droping</id>
   <content type="html">&lt;p&gt;Today was my first day at Oracle OpenWorld and here are my first impressions from the sessions I attended.&lt;/p&gt;
&lt;p&gt;The first one was &lt;em&gt;Building Web 2.0 Social Applications in Ruby on Rails with &lt;span class=&quot;caps&quot;&gt;BEA&lt;/span&gt; AquaLogic Interaction&lt;/em&gt; by &lt;a href=&quot;http://blog.thebdgway.com/&quot;&gt;Chris Bucchere&lt;/a&gt; where he explained how they built social application for &lt;span class=&quot;caps&quot;&gt;BEA&lt;/span&gt; conference participants. And it was interesting to see also some code examples from this application that he presented.&lt;/p&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/drag-and-drop.gif&quot; alt=&quot;drag_and_drop.gif&quot; border=&quot;0&quot; width=&quot;320&quot; height=&quot;186&quot; /&gt;&lt;/div&gt;
&lt;p&gt;And then after that I participated in three Oracle Develop hands-on sessions about &lt;a href=&quot;http://www.oracle.com/technologies/soa/soa-suite.html&quot;&gt;Oracle &lt;span class=&quot;caps&quot;&gt;SOA&lt;/span&gt; suite&lt;/a&gt; and &lt;a href=&quot;http://www.oracle.com/technology/products/webcenter/index.html&quot;&gt;WebCenter&lt;/a&gt;. I signed up for these sessions because I thought that they will be more technical and code-intensive compared to other sessions.&lt;/p&gt;
&lt;p&gt;As a result I spent three hours in Oracle JDeveloper but all I was doing was dragging-and-dropping and filling some pop-up dialog boxes. I did not write single line of Java code during these workshops. And as a result I had just vague idea why all the dragged components worked together.&lt;/p&gt;
&lt;p&gt;Having experience of coding in Ruby and trying to create small and beautiful code this drag-and-drop development did not feel quite natural for me. And I am afraid that this drag-and-drop development approach will create bunch of developers who will not be able to create real code anymore.&lt;/p&gt;
&lt;p&gt;The other consequences of this drag-and-drop style coding is that it is hard to version control the resulting generated code and it is also much harder to unit test such generated code. Probably this is the reason why I could not find any OpenWorld session about unit testing and test-driven development.&lt;/p&gt;
&lt;p&gt;Am I missing some hidden beauty of drag-and-drop development? Or am I spoiled with beauty of Ruby?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Oracle enhanced adapter presentation at RejectConf in Berlin</title>
   <link href="http://blog.rayapps.com/2008/09/06/oracle-enhanced-adapter-presentation-at-rejectconf-in-berlin/"/>
   <updated>2008-09-06T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/09/06/oracle-enhanced-adapter-presentation-at-rejectconf-in-berlin</id>
   <content type="html">&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/rejectconf08.jpg&quot; alt=&quot;rejectconf08.jpg&quot; border=&quot;0&quot; width=&quot;400&quot; height=&quot;315&quot; /&gt;&lt;/div&gt;
&lt;p&gt;I just returned from &lt;a href=&quot;http://en.oreilly.com/railseurope2008/public/content/home&quot;&gt;RailsConf Europe&lt;/a&gt; in Berlin and attended a lot of good Ruby and Rails related sessions.&lt;/p&gt;
&lt;p&gt;I also tried to submit there my session proposal about using Rails with Oracle but as there were too many good proposals and as my topic was with too narrow topic then it was not accepted. Therefore I used opportunity to give 5 minutes presentation about Oracle enhanced adapter in &lt;a href=&quot;http://www.rug-b.com/trac/wiki/RejectConf&quot;&gt;RejectConf&lt;/a&gt; where anybody could present anything.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/files/rejectconf-oracle-enhaced-adapter.pdf&quot; title=&quot;rejectconf_oracle_enhaced_adapter.pdf&quot;&gt;Here are my slides&lt;/a&gt; that I used in this presentation. And at least one participant was interested in this topics as he uses Rails and Oracle and did not know about my adapter.&lt;/p&gt;
&lt;p&gt;My next public appearance is planned at &lt;a href=&quot;http://wiki.oracle.com/page/Oracle+OpenWorld+Unconference&quot;&gt;Oracle OpenWorld unconference&lt;/a&gt; where I have recerved time slot on Thursday, September 25th at 10am. Please come there if you are attending Oracle OpenWorld and are interested in how to use Ruby on Rails with your legacy Oracle databases.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Latest additions to Oracle enhanced adapter</title>
   <link href="http://blog.rayapps.com/2008/07/27/latest-additions-to-oracle-enhanced-adapter/"/>
   <updated>2008-07-27T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/07/27/latest-additions-to-oracle-enhanced-adapter</id>
   <content type="html">&lt;p&gt;Short information about latest enhancements in ActiveRecord Oracle enhanced adapter:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Oracle enhanced adapter is now compatible with &lt;a href=&quot;http://compositekeys.rubyforge.org/&quot;&gt;composite_primary_keys gem&lt;/a&gt; which is quite useful if you are working with legacy databases.&lt;/li&gt;
	&lt;li&gt;Adapter now is also working correctly with Rails 2.1 partial_updates enabled. Previously I mentioned that you needed to disable partial_updates when using &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt;/&lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; columns. Now the issue is found and fixed and partial_updates are working with &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt;/&lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; columns.&lt;/li&gt;
	&lt;li&gt;Support for other date and time formats when assigning string to :date or :datetime column. For example, if you would like to assign strings with format dd.mm.yyyy to date and datetime columns then add the following configuration options:&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string_to_date_format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;%d.%m.%Y&amp;quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string_to_time_format&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;%d.%m.%Y %H:%M:%S&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get the new release of Oracle enhanced adapter do as always:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install activerecord-oracle_enhanced-adapter
&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Screencast of Oracle E-Business Suite setup management tool</title>
   <link href="http://blog.rayapps.com/2008/07/25/screencast-of-oracle-e-business-suite-setup-management-tool/"/>
   <updated>2008-07-25T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/07/25/screencast-of-oracle-e-business-suite-setup-management-tool</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;http://blog.rayapps.com/images/urra.png&quot; alt=&quot;URRA.png&quot; border=&quot;0&quot; width=&quot;260&quot; height=&quot;156&quot; align=&quot;right&quot; /&gt;&lt;b&gt;Warning:&lt;/b&gt; this post will be unrelatead to Ruby :)&lt;/p&gt;
&lt;p&gt;For many years our company is using &lt;a href=&quot;http://www.it-alise.com/en/solutions/urra&quot;&gt;tool for Oracle E-Business Suite setup management&lt;/a&gt; that we initially built for our own purposes but now also we are offering to other Oracle partners and customers.&lt;/p&gt;
&lt;p&gt;As I was bored to do demonstrations of it over and over again I finally decided to create a &lt;a href=&quot;http://www.it-alise.com/files/URRA_demo.mov&quot;&gt;screencast of this tool&lt;/a&gt; (it&amp;#8217;s 22 MB large). And I think that my first experiment in screencasting is not too bad :)&lt;/p&gt;
&lt;p&gt;Previously screencasting was quite hard stuff as there was not so many good tools for that. In this case I used &lt;a href=&quot;http://www.varasoftware.com/products/screenflow/&quot;&gt;ScreenFlow&lt;/a&gt; tool which was released this year (and is available just on Mac OS X Leopard) and I have to say that it is much more better and easier compared to any other tools that I have seen earlier. So I am strongly recommending it to others who are interested in screencasting.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Custom ActiveRecord create, add and delete methods for legacy databases</title>
   <link href="http://blog.rayapps.com/2008/07/10/custom-activerecord-create-add-and-delete-methods-for-legacy-databases/"/>
   <updated>2008-07-10T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/07/10/custom-activerecord-create-add-and-delete-methods-for-legacy-databases</id>
   <content type="html">&lt;p&gt;In some Ruby on Rails projects I am putting ActiveRecord interface on top of existing legacy databases. It is quite easy to specify legacy table names and primary keys in ActiveRecord models so that ActiveRecord would generate correct &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; statements to read data from legacy databases.&lt;/p&gt;
&lt;p&gt;But it is more difficult to insert, update and delete in legacy databases using ActiveRecord. When using Oracle legacy databases then quite often they have exposed PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; APIs for writing to tables and you are typically not allowed to directly modify tables with &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt;, &lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;DELETE&lt;/span&gt; statements.&lt;/p&gt;
&lt;p&gt;Therefore I created support for custom create, update and delete methods in the &lt;a href=&quot;http://rubyforge.org/frs/?group_id=6212&amp;release_id=23785&quot;&gt;version 1.1.3 of ActiveRecord Oracle enhanced adapter&lt;/a&gt; which uses also my &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;ruby-plsql gem&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s look at the following example. Assume that we have the following table:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;employee_id&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;hire_date&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;version&lt;/span&gt;       &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;create_time&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;update_time&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And we have the following PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; package that should be used to write to this table:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PACKAGE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_employees_pkg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;PROCEDURE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_first_name&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_last_name&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_hire_date&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_salary&lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_employee_id&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;OUT&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;PROCEDURE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_employee_id&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_first_name&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_last_name&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_hire_date&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;DATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_salary&lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;PROCEDURE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delete_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;p_employee_id&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then we define ActiveRecord model in the following way:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TestEmployee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set_primary_key&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:employee_id&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# should return ID of new record&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set_create_method&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_employees_pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hire_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_salary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:p_employee_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# return value is ignored&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set_update_method&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_employees_pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hire_date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_salary&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;salary&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# return value is ignored&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;set_delete_method&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_employees_pkg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete_employee&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;:p_employee_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And as a result we can use this model in the same way as other ActiveRecord models:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;vi&quot;&gt;@employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TestEmployee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;First&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:last_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Last&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;today&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reload&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Second&amp;quot;&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save!&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@employee&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And all writing to the database will be done using defined &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; procedures.&lt;/p&gt;
&lt;p&gt;Currently this functionality is embedded into Oracle enhanced adapter but if somebody needs it also for other databases this functionality could easily be extraced from the adapter.&lt;/p&gt;
&lt;p&gt;To get the new release of Oracle enhanced adapter just do:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;Source code of Oracle enhanced adapter is located at &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;GitHub&lt;/a&gt; and you can submit bug reports and enhancement requests in &lt;a href=&quot;http://rsim.lighthouseapp.com/projects/11468-oracle-enhanced/tickets&quot;&gt;Lighthouse&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Vote for my session proposal at Oracle OpenWorld</title>
   <link href="http://blog.rayapps.com/2008/07/08/vote-for-my-session-proposal-at-oracle-openworld/"/>
   <updated>2008-07-08T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/07/08/vote-for-my-session-proposal-at-oracle-openworld</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://mix.oracle.com/ideas/27038-using-ruby-on-rails-with-oracle-e-business-suite&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/oow.png&quot; alt=&quot;oow.png&quot; border=&quot;0&quot; width=&quot;107&quot; height=&quot;114&quot; align=&quot;right&quot; /&gt;&lt;/a&gt;If you still have not voted for my session proposal &lt;a href=&quot;https://mix.oracle.com/ideas/27038-using-ruby-on-rails-with-oracle-e-business-suite&quot;&gt;&amp;#8220;Using Ruby on Rails with Oracle E-Business Suite&amp;#8221;&lt;/a&gt; then please do so :) Voting deadline is near &amp;#8211; July 13th.&lt;/p&gt;
&lt;p&gt;In any case I am going to be at &lt;a href=&quot;http://www.oracle.com/openworld/2008/index.html&quot;&gt;Oracle OpenWorld conference&lt;/a&gt; in San Francisco in September. So if some of my blog readers will also be there and would like to have some chat with me about Oracle and Ruby then please let me know.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Oracle enhanced adapter version 1.1.1 released</title>
   <link href="http://blog.rayapps.com/2008/06/28/activerecord-oracle-enhanced-adapter-version-111-released/"/>
   <updated>2008-06-28T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/06/28/activerecord-oracle-enhanced-adapter-version-111-released</id>
   <content type="html">&lt;p&gt;I just released &lt;a href=&quot;http://rubyforge.org/frs/?group_id=6212&amp;release_id=23422&quot;&gt;new version&lt;/a&gt; of &lt;a href=&quot;http://blog.rayapps.com/2008/05/13/activerecord-oracle-enhanced-adapter/&quot;&gt;ActiveRecord Oracle enhanced adapter&lt;/a&gt; which includes several new enhancements which could be useful if you use ActiveRecord with legacy Oracle databases:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Added ignore_table_columns option for class definitions&lt;br /&gt;
You can specify which table (or view) columns should be ignored by ActiveRecord &amp;#8211; these could be either columns which you do not need in Rails application or which have currently unsupported data types. For example:&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Employee&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ignore_table_columns&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:phone_number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:hire_date&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
	&lt;li&gt;Added support for &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt; columns&lt;br /&gt;
You can create tables with :timestamp data type which will create &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt; columns and you can access values from &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt; columns. Unfortunately due to current ruby-oci8 limitations when you will retrieve &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt; values it will be without fractional seconds (but if you pass Time value with fractional seconds then it will be stored in database).&lt;/li&gt;
	&lt;li&gt;NLS_DATE_FORMAT and NLS_TIMESTAMP_FORMAT independent &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt; columns support&lt;br /&gt;
By default Oracle adapter (and enhanced adapter as well) changes NLS_DATE_FORMAT and NLS_TIMESTAMP_FORMAT to &amp;#8216;DD-&lt;span class=&quot;caps&quot;&gt;MON&lt;/span&gt;-&lt;span class=&quot;caps&quot;&gt;YYYY&lt;/span&gt; HH24:MI:SS&amp;#8217;. But if you are working with some legacy database which requires different &lt;span class=&quot;caps&quot;&gt;NLS&lt;/span&gt; date settings then now you can change these settings to different ones. You can put in some initialization file some other &lt;span class=&quot;caps&quot;&gt;NLS&lt;/span&gt; settings, e.g.:&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%q{alter session set nls_date_format = &amp;#39;DD-MON-YYYY HH24:MI:SS&amp;#39;}&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%q{alter session set nls_timestamp_format = &amp;#39;DD-MON-YYYY HH24:MI:SS&amp;#39;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;br /&gt;
and ActiveRecord will continue to work correctly with date values.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also one Rails 2.1 related issue was solved. Previously Oracle enhanced adapter always added after_save callback to ActiveRecord session store which stores &lt;span class=&quot;caps&quot;&gt;BLOB&lt;/span&gt; data in the database (as in Rails 2.0 there was issue that this callback was not added). Now in Rails 2.1 this callback is added by ActiveRecord therefore Oracle enhanced adapter checks if this callback is already added or not. So now this should work correctly both in Rails 2.0 and Rails 2.1.&lt;/p&gt;
&lt;p&gt;Also I have noticed that in some Rails 2.1 applications Oracle adapter is failing on ActiveRecord session store updates when partial updates are enabled. If you also have such issue then put this into your initialization file which will work as workaround until I will find what is causing this problem:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecordStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;partial_updates&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To get the new release just do:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;Source code of Oracle enhanced adapter is located at &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;GitHub&lt;/a&gt;. And you can submit bug reports and enhancement requests in &lt;a href=&quot;http://rsim.lighthouseapp.com/projects/11468-oracle-enhanced/tickets&quot;&gt;Lighthouse&lt;/a&gt;. There you can see also some identified enhancements &amp;#8211; please add comments to them if you also would like to have them. Then it will be easier for me to select what to include in next version of adapter.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql gem now supports JRuby and Oracle JDBC driver</title>
   <link href="http://blog.rayapps.com/2008/06/26/ruby-plsql-gem-now-supports-jruby-and-oracle-jdbc-driver/"/>
   <updated>2008-06-26T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/06/26/ruby-plsql-gem-now-supports-jruby-and-oracle-jdbc-driver</id>
   <content type="html">&lt;p&gt;Some time ago I created &lt;a href=&quot;/2008/03/15/ruby-plsql-gem-simple-ruby-api-for-plsql-procedures/&quot;&gt;ruby-plsql gem&lt;/a&gt; which provides simple Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for Oracle PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; stored procedures.&lt;/p&gt;
&lt;p&gt;Initially this gem supported just &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; with ruby-oci8 library which provides connectivity to Oracle database as this was my main development and production environment for Ruby &amp;amp; Oracle applications. But as &lt;a href=&quot;http://jruby.codehaus.org/&quot;&gt;JRuby&lt;/a&gt; is fast growing alternative Ruby deployment platform and as it can be integrated into Oracle Fusion middleware platform (e.g. &lt;a href=&quot;https://mix.oracle.com/&quot;&gt;Oracle Mix&lt;/a&gt; is running on JRuby on Oracle Fusion middleware) then I planned to support JRuby as well.&lt;/p&gt;
&lt;p&gt;I started to work on JRuby support during &lt;a href=&quot;http://headius.blogspot.com/2008/05/jruby-pre-railsconf-hackfest-on.html&quot;&gt;RailsConf JRuby hackfest&lt;/a&gt; and initially this did not seem very hard task for me. But as I did not know &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; very well it took me much more time than initially planned. And unfortunately &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; is also much less powerful compared to ruby-oci8 library for construction of dynamic PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; calls. In addition I needed to strugle with Ruby and &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; data type mappings which differs from Ruby and ruby-oci8 data type mappings.&lt;/p&gt;
&lt;p&gt;But finally I have completed JRuby support and released &lt;a href=&quot;http://rubyforge.org/frs/?group_id=5816&amp;release_id=23386&quot;&gt;ruby-plsql gem version 0.2.0&lt;/a&gt;. And good news are that from usage perspective ruby-plsql behaves identically on &lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt; and JRuby &amp;#8211; at least my RSpec tests are telling so.&lt;/p&gt;
&lt;p&gt;To install this gem on JRuby execute&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo jruby -S gem install ruby-plsql&lt;/pre&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo jgem install ruby-plsql&lt;/pre&gt;
&lt;p&gt;depending on how you have installed JRuby on your computer.&lt;/p&gt;
&lt;p&gt;Source code of ruby-plsql is located on &lt;a href=&quot;http://github.com/rsim/ruby-plsql&quot;&gt;GitHub&lt;/a&gt; where you can find usage examples in RSpec tests.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Using mod_rails with Rails applications on Oracle</title>
   <link href="http://blog.rayapps.com/2008/05/21/using-mod_rails-with-rails-applications-on-oracle/"/>
   <updated>2008-05-21T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/05/21/using-mod_rails-with-rails-applications-on-oracle</id>
   <content type="html">&lt;p&gt;As many others I also got interested in new &lt;a href=&quot;http://modrails.com/&quot;&gt;mod_rails&lt;/a&gt; deployment solution for Rails applications. And when I read &lt;a href=&quot;http://nubyonrails.com/articles/ask-your-doctor-about-mod_rails&quot;&gt;how to use it for development environment needs&lt;/a&gt; I decided to try it out.&lt;/p&gt;
&lt;p&gt;As you probably know I am using Mac for development and using Oracle database for many Rails applications. So if you do it as well then at first you need to &lt;a href=&quot;http://blog.rayapps.com/2008/04/24/how-to-setup-ruby-and-new-oracle-instant-client-on-leopard/&quot;&gt;setup Ruby and Oracle on your Mac&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After that I installed and did setup of mod_rails according to &lt;a href=&quot;http://www.fngtps.com/2008/04/using-passenger-on-osx-for-rails-development&quot;&gt;these instructions&lt;/a&gt; and &lt;a href=&quot;http://nubyonrails.com/articles/ask-your-doctor-about-mod_rails&quot;&gt;these additional notes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;One additional thing that I had to do was to change the user which will be used to run Apache httpd server as otherwise default www user did not see my Rails applications directories. You should do it in /etc/apache2/httpd.conf:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;nb&quot;&gt;User&lt;/span&gt; yourusername
&lt;span class=&quot;nb&quot;&gt;Group&lt;/span&gt; yourusername
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And then I started to fight with the issue that ruby which was started from mod_rails could not load ruby-oci8 library as it could not find Oracle Instant Client shared library. And the reason for that was that mod_rails launched ruby with very minimal list of environment variables. E.g. as DYLD_LIBRARY_PATH environment variable was not specified then ruby-oci8 could not find Oracle Instant Client libraries.&lt;/p&gt;
&lt;p&gt;The issue is that there is no documented way how to pass necessary environment variables to mod_rails. Unfortunately mod_rails is ignoring SetEnv settings from Apache httpd.conf file. Therefore I needed to find some workaround for the issue and finally I did the following solution.&lt;/p&gt;
&lt;p&gt;I created executable script file /usr/local/bin/ruby_with_env:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/instantclient_10_2:$DYLD_LIBRARY_PATH&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SQLPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$DYLD_LIBRARY_PATH&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TNS_ADMIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/network/admin&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;NLS_LANG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;AMERICAN_AMERICA.UTF8&amp;quot;&lt;/span&gt;
/usr/bin/ruby &lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and then in Apache httpd.conf file I changed RailsRuby line to&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;apache&quot;&gt;&lt;span class=&quot;nb&quot;&gt;RailsRuby&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;/usr/local/bin/ruby_with_env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;As a result in this way I was able to specify necessary environment variables before Ruby and Rails was started and after this change ruby-oci8 libraries were successfully loaded.&lt;/p&gt;
&lt;p&gt;You can use this solution also on Linux hosts where you will deploy Rails applications in production.&lt;/p&gt;
&lt;p&gt;Currently I still have issue with mod_rails that it fails to execute RMagick library methods (which is compiled with ImageMagick). I get strange errors in Apache error_log:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.
[error] [client ::1] Premature end of script headers:
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When I was running the same application with Mongrel then everything was running correctly. If anyone has any ideas what could be the reason please write some comment.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Oracle enhanced adapter</title>
   <link href="http://blog.rayapps.com/2008/05/13/activerecord-oracle-enhanced-adapter/"/>
   <updated>2008-05-13T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/05/13/activerecord-oracle-enhanced-adapter</id>
   <content type="html">&lt;p&gt;In all Ruby on Rails on Oracle projects where I am using original ActiveRecord Oracle adapter I always create some &amp;#8220;monkey patches&amp;#8221; of Oracle adapter to support my needs. I have written about several of these patches in this blog (see &lt;a href=&quot;/2008/01/26/make-rails-database-migrations-faster-on-oracle/&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;/2008/01/08/fix-for-rails-20-on-oracle-with-database-session-store/&quot;&gt;2&lt;/a&gt;, &lt;a href=&quot;/2007/11/16/some-issues-with-oracle-views-as-activerecord-source/&quot;&gt;3&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;As such monkey patches are not easily maintainable and reusable between projects I decided to fork existing Oracle adapter and create my own ActiveRecord Oracle &amp;#8220;enhanced&amp;#8221; adapter where I will add all my enhancements.&lt;/p&gt;
&lt;p&gt;Today I released first version (1.1.0) of Oracle enhanced adapter on &lt;a href=&quot;http://rubyforge.org/projects/oracle-enhanced/&quot;&gt;RubyForge&lt;/a&gt; as well as source code is available at &lt;a href=&quot;http://github.com/rsim/oracle-enhanced&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To install Oracle enhanced adapter execute (should be available soon):&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install activerecord-oracle_enhanced-adapter&lt;/pre&gt;
&lt;p&gt;To use it you need to use &amp;#8220;oracle_enhanced&amp;#8221; as the adapter name in database.yml configuration file instead of &amp;#8220;oracle&amp;#8221;. In addition I recommend to create config/initializers/oracle_enhanced.rb file where to put any adapter configuration options that you can see below.&lt;/p&gt;
&lt;p&gt;Initial version contains the following enhancements:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Improved perfomance of schema dump methods when used on large data dictionaries&lt;/li&gt;
	&lt;li&gt;Added &lt;span class=&quot;caps&quot;&gt;LOB&lt;/span&gt; writing callback for sessions stored in database (see &lt;a href=&quot;http://blog.rayapps.com/2008/01/08/fix-for-rails-20-on-oracle-with-database-session-store/&quot;&gt;previous post&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;Added emulate_dates_by_column_name option&lt;br /&gt;
Set the option below and as a result columns with &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; in their name will be emulated as Date (and not as Time which is default for &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; columns in database)&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_dates_by_column_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
	&lt;li&gt;Added emulate_integers_by_column_name option&lt;br /&gt;
Set the option below and as a result number columns with ID at the end of column always will be emulated as Fixnum (useful if in legacy database column type is specified just as &lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt; without precision information which by default is mapped to BigDecimal Ruby type)&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_integers_by_column_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
	&lt;li&gt;Added emulate_booleans_from_strings option&lt;br /&gt;
Set the option below and as a result &lt;acronym title=&quot;1&quot;&gt;&lt;span class=&quot;caps&quot;&gt;CHAR&lt;/span&gt;&lt;/acronym&gt;, &lt;acronym title=&quot;1&quot;&gt;&lt;span class=&quot;caps&quot;&gt;VARCHAR2&lt;/span&gt;&lt;/acronym&gt; columns or VARCHAR2 columns with &lt;span class=&quot;caps&quot;&gt;FLAG&lt;/span&gt; or YN at the end of their name will be emulated as booleans (and &amp;#8220;Y&amp;#8221; and &amp;#8220;N&amp;#8221; will be used to store true and false values). This is useful for legacy databases where Rails default convention of &lt;acronym title=&quot;1&quot;&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt;&lt;/acronym&gt; for boolean values cannot be used (e.g. if you are using Oracle E-Business Suite where booleans are stored as &amp;#8220;Y&amp;#8221; and &amp;#8220;N&amp;#8221;).&lt;br /&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ConnectionAdapters&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OracleEnhancedAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_booleans_from_strings&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need to override how date, integer or boolean columns are identified then you can redefine class methods is_date_column?, is_integer_column? and is_boolean_column? definitions in OracleEnhancedAdapter class.&lt;/p&gt;
&lt;p&gt;Please comment if you find these enhancements useful in your projects and also what other Oracle adapter enhancements you need in your Ruby on Rails on Oracle projects.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Session proposal for OOW - Using Ruby on Rails with Oracle E-Business Suite</title>
   <link href="http://blog.rayapps.com/2008/05/04/session-proposal-for-oow-using-ruby-on-rails-with-oracle-e-business-suite/"/>
   <updated>2008-05-04T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/05/04/session-proposal-for-oow-using-ruby-on-rails-with-oracle-e-business-suite</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://mix.oracle.com/ideas/27038-using-ruby-on-rails-with-oracle-e-business-suite&quot;&gt;&lt;img src=&quot;http://blog.rayapps.com/images/oow-submit-session.png&quot; alt=&quot;OOW_submit_session.png&quot; border=&quot;0&quot; width=&quot;317&quot; height=&quot;179&quot; align=&quot;right&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;https://mix.oracle.com/&quot;&gt;mix.oracle.com&lt;/a&gt; team created opportunity to &lt;a href=&quot;http://oracleappslab.com/2008/05/02/suggest-a-session-topic-for-openworld/&quot;&gt;suggest and vote for sessions&lt;/a&gt; at Oracle OpenWorld conference. Therefore I will also try this opportunity and will suggest topic which is covered by many posts in this blog &amp;#8211; I proposed session &lt;a href=&quot;https://mix.oracle.com/ideas/27038-using-ruby-on-rails-with-oracle-e-business-suite&quot;&gt;Using Ruby on Rails with Oracle E-Business Suite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So if you would like me to present this topic in &lt;a href=&quot;http://www.oracle.com/openworld/2008/index.html&quot;&gt;Oracle OpenWorld conference&lt;/a&gt; then please &lt;a href=&quot;https://mix.oracle.com/ideas/27038-using-ruby-on-rails-with-oracle-e-business-suite&quot;&gt;go to mix.oracle.com and vote for it&lt;/a&gt;!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to setup Ruby and new Oracle Instant Client on Leopard</title>
   <link href="http://blog.rayapps.com/2008/04/24/how-to-setup-ruby-and-new-oracle-instant-client-on-leopard/"/>
   <updated>2008-04-24T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/04/24/how-to-setup-ruby-and-new-oracle-instant-client-on-leopard</id>
   <content type="html">&lt;blockquote class=&quot;warning&quot;&gt;
&lt;p class=&quot;warning&quot;&gt;&lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt;: &lt;a href=&quot;http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/&quot;&gt;New version of instructions for Snow Leopard is available here.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;We waited for it long, long time and finally it has arrived &amp;#8211; &lt;a href=&quot;http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/intel_macsoft.html&quot;&gt;Oracle Instant Client for Intel Mac&lt;/a&gt;. I was lucky to test beta version of the client already for the last couple of weeks and so far everything was working OK. Therefore as the final version is now available to everybody I am here rewriting &lt;a href=&quot;http://blog.rayapps.com/2007/08/27/how-to-setup-ruby-and-oracle-client-on-intel-mac/&quot;&gt;my previous instructions&lt;/a&gt; on how to get Ruby working with Oracle on Mac.&lt;/p&gt;
&lt;h3&gt;Installing Oracle Instant Client for Intel Mac&lt;/h3&gt;
&lt;p&gt;At first you need to &lt;a href=&quot;http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/intel_macsoft.html&quot;&gt;download Oracle Instant Client for Intel Mac&lt;/a&gt;. Download &amp;#8220;Instant Client Package &amp;#8211; Basic&amp;#8221; and &amp;#8220;Instant Client Package &amp;#8211; &lt;span class=&quot;caps&quot;&gt;SDK&lt;/span&gt;&amp;#8221; and also I suggest &amp;#8220;Instant Client Package &amp;#8211; SQL*Plus&amp;#8221; if you would like to have command line sqlplus utility.&lt;/p&gt;
&lt;p&gt;Unzip downloaded archives and move it where you would like to have it &amp;#8211; I am keeping it in /usr/local/oracle/instantclient_10_2. Then go to this directory and make symbolic links for dynamic libraries&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo ln -s libclntsh.dylib.10.1 libclntsh.dylib
sudo ln -s libocci.dylib.10.1 libocci.dylib&lt;/pre&gt;
&lt;p&gt;Then I recommend to create and place somewhere your tnsnames.ora file where you will keep your database connections definitions &amp;#8211; I place this file in directory /usr/local/oracle/network/admin.&lt;/p&gt;
&lt;p&gt;Then finally you need to set up necessary environment variables &amp;#8211; I place the following definitions in my .bash_profile script:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DYLD_LIBRARY_PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/instantclient_10_2&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SQLPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/instantclient_10_2&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TNS_ADMIN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/usr/local/oracle/network/admin&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;NLS_LANG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;AMERICAN_AMERICA.UTF8&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;:&lt;span class=&quot;nv&quot;&gt;$DYLD_LIBRARY_PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Use your path to Oracle Instant Client if it differc from /usr/local/oracle/instantclient_10_2. And as you see I also define NLS_LANG environment variable &amp;#8211; this is necessary if your database is not in UTF8 encoding but in Ruby you want to get &lt;span class=&quot;caps&quot;&gt;UTF&lt;/span&gt;-8 encoded strings from the database. Specifying this NLS_LANG environment variable you will force that Oracle Instant Client will do character set translation.&lt;/p&gt;
&lt;p&gt;After these steps relaunch Terminal application (so that new environment variables are set), specify database connection in tnsnames.ora file and try if you can access your database with sqlplus from command line.&lt;/p&gt;
&lt;h3&gt;Ruby installation&lt;/h3&gt;
&lt;p&gt;If you are using Leopard then I assume that you are using preinstalled Ruby which is the simplest option. I tried to compile Ruby from sources on Mac OS X Leopard but when I compared performance then original Ruby was a little bit faster on some benchmarks and therefore I sticked with original one.&lt;/p&gt;
&lt;h3&gt;Compile and install ruby-oci8&lt;/h3&gt;
&lt;p&gt;Download the latest version of &lt;a href=&quot;http://rubyforge.org/projects/ruby-oci8/&quot;&gt;ruby-oci8&lt;/a&gt; (version 1.0.0 at time of writing this post).&lt;/p&gt;
&lt;p&gt;As Oracle Instant Client is available just for Intel i386 architecture you need to change in file /usr/lib/ruby/1.8/universal-darwin9.0/rbconfig.rb line 17 to:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-arch i386&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then go to directory where you extracted ruby-oci8 source and execute ruby-oci8 standard installation sequence:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;ruby setup.rb config
make
sudo make install&lt;/pre&gt;
&lt;p&gt;After that you can change back file /usr/lib/ruby/1.8/universal-darwin9.0/rbconfig.rb line 17 to:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;-arch ppc -arch i386&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now try&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;ruby -r oci8 -e &quot;OCI8.new('scott', 'tiger','orcl').exec('select * from emp') do |r| puts r.join(','); end&quot;&lt;/pre&gt;
&lt;p&gt;or similar to verify that you can access Oracle database from ruby.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s it! Please write in comments if something is not working according to these instructions.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Video from Euruko 2008</title>
   <link href="http://blog.rayapps.com/2008/04/05/video-from-euruko-2008/"/>
   <updated>2008-04-05T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/04/05/video-from-euruko-2008</id>
   <content type="html">&lt;p&gt;I made &lt;a href=&quot;http://ruby.lv/files/Euruko_2008.m4v&quot;&gt;short video from Euruko 2008 conference&lt;/a&gt; where you can see Matz, Koichi, JRuby guys, DrNic ar me as well :)&lt;/p&gt;
&lt;p&gt;&lt;object width=&quot;400&quot; height=&quot;330&quot; type=&quot;application/x-shockwave-flash&quot; data=&quot;http://video.google.com/googleplayer.swf?docId=-1237678620877495277&quot;&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;never&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://video.google.com/googleplayer.swf?docId=-1237678620877495277&quot;&gt;&lt;param name=&quot;quality&quot; value=&quot;best&quot;&gt;&lt;param name=&quot;bgcolor&quot; value=&quot;#ffffff&quot;&gt;&lt;param name=&quot;scale&quot; value=&quot;noScale&quot;&gt;&lt;param name=&quot;wmode&quot; value=&quot;opaque&quot;&gt;&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;I posted my presentation slides in my &lt;a href=&quot;/2008/04/03/my-presentation-on-using-ruby-with-oracle-at-euruko-conference/&quot;&gt;previous post&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>My presentation on using Ruby with Oracle at Euruko conference</title>
   <link href="http://blog.rayapps.com/2008/04/03/my-presentation-on-using-ruby-with-oracle-at-euruko-conference/"/>
   <updated>2008-04-03T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2008/04/03/my-presentation-on-using-ruby-with-oracle-at-euruko-conference</id>
   <content type="html">&lt;p&gt;I gave short presentation about &amp;#8220;Using Ruby with Oracle&amp;#8221; at European Ruby conference &lt;a href=&quot;http://www.euruko2008.org/&quot;&gt;Euruko 2008&lt;/a&gt;. You can &lt;a href=&quot;http://www.euruko2008.org/system/assets/documents/0000/0009/simanovskis-using-ruby-with-oracle-euruko2008.pdf&quot;&gt;download presentation slides at their site&lt;/a&gt;. My collegue took a video of my presentation so probably after some time I will post it as well :)&lt;/p&gt;
&lt;p&gt;Either because of this presentation or maybe just because more people are interested in Ruby on Oracle the number of visits to this blog is fast growing during the last days. Which makes me more motivated to do more investigations in Ruby and Oracle area.&lt;/p&gt;
&lt;p&gt;One area of further research could be standardization of different ActiveRecord Oracle adapter patches &amp;#8211; otherwise now I have different patches in each project and this becomes quite hard to manage.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby-plsql gem: simple Ruby API for PL/SQL procedures</title>
   <link href="http://blog.rayapps.com/2008/03/15/ruby-plsql-gem-simple-ruby-api-for-plsql-procedures/"/>
   <updated>2008-03-15T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2008/03/15/ruby-plsql-gem-simple-ruby-api-for-plsql-procedures</id>
   <content type="html">&lt;p&gt;In several projects I have used Ruby and Rails to access legacy Oracle databases which have both tables with data as well as PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; packages with lot of existing business logic. Sometimes it is easier just to redo business logic in Ruby but sometimes you need to reuse existing PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; packages and procedures.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s use this simple PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; function as an example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;OR&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;REPLACE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FUNCTION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_uppercase&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p_string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VARCHAR2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;IS&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;BEGIN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;RETURN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;UPPER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;END&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test_uppercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you are using ruby-oci8 library to connect to Oracle then you can call this PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedure from Ruby in the following way (more details can be found in &lt;a href=&quot;http://ruby-oci8.rubyforge.org/en/api.html&quot;&gt;ruby-oci8 documentation&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OCI8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hr&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hr&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;xe&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EOS&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;BEGIN&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;  :return := test_uppercase(:p_string);&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;END;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;EOS&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;:p_string&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;xxx&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bind_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;:return&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;:return&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This does not look like Ruby-style as it is too long and complex code which just calls one simple PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; function :(&lt;/p&gt;
&lt;p&gt;Wouldn&amp;#8217;t it be much nicer if you could get the same result with the following code?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OCI8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hr&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;hr&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;xe&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_uppercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This idea served as inspiration to create ruby-plsql gem which would provide such nice Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; to access existing PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures and functions. Here are other examples how you can use it.&lt;/p&gt;
&lt;p&gt;Call procedure with named parameters:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_uppercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:p_string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Call procedure with specified schema:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_uppercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Call procedure from specified package in specified schema:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_package&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_uppercase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;xxx&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Call procedure with output arguments:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;plsql&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test_copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;abc&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# returns output arguments { :p_to =&amp;gt; &amp;quot;abc&amp;quot;, :p_to_double =&amp;gt; &amp;quot;abcabc&amp;quot; }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To install this gem execute&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install ruby-plsql&lt;/pre&gt;
&lt;p&gt;As I mentioned before it also requires ruby-oci8 library to access Oracle. I have plans to create JRuby / &lt;span class=&quot;caps&quot;&gt;JDBC&lt;/span&gt; support in the future versions of this gem.&lt;/p&gt;
&lt;p&gt;Current limitation is that this &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; support just &lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt;, VARCHAR2, &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;TIMESTAMP&lt;/span&gt; types for PL/&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; procedures which are dynamically mapped to Ruby Fixnum/Bignum/Float, String, DateTime and Time types.&lt;/p&gt;
&lt;p&gt;If you find this gem interesting then please let me know in comments what additional features you would like to have for it.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>How to log DB statistics at info log level in Rails 2.0</title>
   <link href="http://blog.rayapps.com/2008/02/23/how-to-log-db-statistics-at-info-log-level-in-rails-20/"/>
   <updated>2008-02-23T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2008/02/23/how-to-log-db-statistics-at-info-log-level-in-rails-20</id>
   <content type="html">&lt;p&gt;When I switched some my applications to Rails 2.0 I noticed that I do not see anymore DB execution time statistics in my production log file (which I set at info level). Now I saw zero database processing time for all my requests, e.g.:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Completed in 0.22203 (4 reqs/sec) | Rendering: 0.13277 (59%) | DB: 0.00000 (0%)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When investigating why is it so I found the following small changeset that is done in Rails 2.0 &amp;#8211; &lt;a href=&quot;http://dev.rubyonrails.org/changeset/8162&quot;&gt;http://dev.rubyonrails.org/changeset/8162&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Rails 1.2 at debug level you got both &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; and database processing time in log file and at info level you got just database processing time. In Rails 2.0 at debug level you get the same in log file but at info level you do not get database processing time.&lt;/p&gt;
&lt;p&gt;So if you are like me and want to analyze your production log file with tools like &lt;a href=&quot;http://nubyonrails.com/articles/a-hodel-3000-compliant-logger-for-the-rest-of-us&quot;&gt;pl_analyze&lt;/a&gt; then you can monkey patch ActiveRecord to get back the previous behaviour as in Rails 1.2:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveRecord&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ConnectionAdapters&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AbstractAdapter&lt;/span&gt;
      &lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# RSI: changed to get DB statistics in log file at info level&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# if @logger and @logger.debug?&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@logger&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;INFO&lt;/span&gt; 
              &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Benchmark&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;realtime&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@runtime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;log_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;log_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# Log message and raise exception.&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# Set last_verification to 0, so that connection gets verified&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# upon reentering the request loop&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@last_verification&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;log_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;StatementInvalid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And now you will get database processing statistics back in log file at info level:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text&quot;&gt;Completed in 0.21853 (4 reqs/sec) | Rendering: 0.10835 (49%) | DB: 0.09657 (44%)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Make Rails database migrations faster on Oracle</title>
   <link href="http://blog.rayapps.com/2008/01/26/make-rails-database-migrations-faster-on-oracle/"/>
   <updated>2008-01-26T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2008/01/26/make-rails-database-migrations-faster-on-oracle</id>
   <content type="html">&lt;p&gt;When using Ruby on Rails on Oracle I noticed that my database migration tasks are much slower than on MySQL.&lt;/p&gt;
&lt;p&gt;I just found the cause for that &amp;#8211; rake db:schema:dump task was taking very long time on my Oracle databases (and this task is executed at the end of rake db:migrate). As a result of this task Oracle Rails adapter is executing&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LOWER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;table_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_tables&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;statement. If your database contains a lot of other schemas with a lot of tables (as in my case I deploy Rails user schema in Oracle E-Business Suite database) then this statement is quite slow (it took more than 10 seconds in my case).&lt;/p&gt;
&lt;p&gt;As all Rails tables are located in Rails user schema then you can get the same result with&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sql&quot;&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LOWER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;table_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all_tables&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;owner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SYS_CONTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;userenv&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;session_user&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;which now executes much faster than original statement.&lt;/p&gt;
&lt;p&gt;So you can make the following patch for Oracle Rails adapter to make this change&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveRecord&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ConnectionAdapters&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OracleAdapter&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tables&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;select_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;select lower(table_name) from all_tables where owner = sys_context(&amp;#39;userenv&amp;#39;,&amp;#39;session_user&amp;#39;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tabs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;tabs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;and include it in environment.rb file or in some separate patch file which you load at Rails startup.&lt;/p&gt;
&lt;p&gt;P.S. I have published &lt;a href=&quot;http://svn.rayapps.com/lib/oracle_adapter_20_patch.rb&quot;&gt;all my patches for Oracle Rails 2.0 adapter&lt;/a&gt;. You can download this file, place it in Rails application lib directory and then just include&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;oracle_adapter_20_patch&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;in your environment.rb file. Look at comments in this file to find out what each patch is doing.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Fix for Rails 2.0 on Oracle with database session store</title>
   <link href="http://blog.rayapps.com/2008/01/08/fix-for-rails-20-on-oracle-with-database-session-store/"/>
   <updated>2008-01-08T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2008/01/08/fix-for-rails-20-on-oracle-with-database-session-store</id>
   <content type="html">&lt;p&gt;As I started to explore Rails 2.0 I tried to migrate one application to Rails 2.0 which is using Oracle as a database. Here are some initial tips for Rails 2.0 on Oracle that I found out.&lt;/p&gt;
&lt;p&gt;Oracle adapter is no more included in Rails 2.0 so you need to install it separately. It is also not yet placed on gems.rubyforge.org therefore you need to install it with:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;sudo gem install activerecord-oracle-adapter --source http://gems.rubyonrails.org&lt;/pre&gt;
&lt;p&gt;The next issue that you will get is error message &amp;#8220;select_rows is an abstract method&amp;#8221;. You can find more information about it in &lt;a href=&quot;http://dev.rubyonrails.org/ticket/10415&quot;&gt;this ticket&lt;/a&gt;. As suggested I fixed this issue with the following Oracle adapter patch that I call from anvironment.rb file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveRecord&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ConnectionAdapters&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OracleAdapter&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;select_rows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And then I faced very strange behaviour that my Rails application was not working with database session store &amp;#8211; no session data was saved. When I changed session store to cookies then everything worked fine.&lt;/p&gt;
&lt;p&gt;When I continued investigation I found out that the issue was that for each new session new row was created in &amp;#8220;sessions&amp;#8221; table but no session data was saved in &amp;#8220;data&amp;#8221; column. As &amp;#8220;data&amp;#8221; column is text field which translates to &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; data type in Oracle then it is not changed in Oracle adapter by &lt;span class=&quot;caps&quot;&gt;INSERT&lt;/span&gt; or &lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt; statements but with special &amp;#8220;write_lobs&amp;#8221; after_save callback (this is done so because in Oracle there is limitation that literal constants in &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statements cannot exceed 4000 characters and therefore such hack with after_save callback is necessary). And then I found that class &lt;span class=&quot;caps&quot;&gt;CGI&lt;/span&gt;::Session::ActiveRecordStore::Session (which is responsible for database session store) does not have this write_lobs after_save filter. Why so?&lt;/p&gt;
&lt;p&gt;As I understand now in Rails 2.0 ActiveRecord class definition sequence has changed &amp;#8211; now at first &lt;span class=&quot;caps&quot;&gt;CGI&lt;/span&gt;::Session::ActiveRecordStore::Session class is defined which inherits from ActiveRecord::Base and only afterwards OracleAdapter is loaded which adds write_lobs callback to ActiveRecord::Base but at this point it is not adding this callback to already defined Session class. As in Rails 1.2 OracleAdapter was loaded together with ActiveRecord and before Session class definition then there was no such issue.&lt;/p&gt;
&lt;p&gt;So currently I solved this issue with simple patch in environment.rb file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CGI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecordStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Session&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;after_save&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:write_lobs&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Of course it would be nicer to force that OracleAdapter is loaded before &lt;span class=&quot;caps&quot;&gt;CGI&lt;/span&gt;::Session::ActiveRecordStore::Session definition (when ActionPack is loaded). If somebody knows how to do that please write a comment :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Some issues with Oracle views as ActiveRecord source</title>
   <link href="http://blog.rayapps.com/2007/11/16/some-issues-with-oracle-views-as-activerecord-source/"/>
   <updated>2007-11-16T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2007/11/16/some-issues-with-oracle-views-as-activerecord-source</id>
   <content type="html">&lt;p&gt;I am using Ruby on Rails to publish data from existing &amp;#8220;legacy&amp;#8221; application on Oracle database which already have existing complex data model. I am defining additional database views on existing legacy data to which I  grant select rights to  Rails schema. And I am using Rails conventions when defining these views &amp;#8211; view names as pluralized / underscored version of Rails model name, ID column as primary key and %_ID columns as foreign keys.&lt;/p&gt;
&lt;p&gt;Typically this works quite well and I can use Rails find methods to automatically generate &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; SELECTs from these views. But for some legacy data I got the problem with Oracle number type mapping to Ruby integer type.&lt;/p&gt;
&lt;p&gt;Rails standard convention for database &lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt; type mapping is the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt; with specified scale and without precision (e.g. &lt;acronym title=&quot;15&quot;&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt;&lt;/acronym&gt;) is mapped to :integer&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt; with specified scale and with precision (e.g. &lt;acronym title=&quot;15,2&quot;&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt;&lt;/acronym&gt;) is mapped to :decimal&lt;/li&gt;
	&lt;li&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt; without scale and precision (just &lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt;) is mapped to :decimal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If primary keys and foreign keys in legacy tables are defined as e.g. &lt;acronym title=&quot;15&quot;&gt;&lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt;&lt;/acronym&gt; then everything is OK and they will be mapped to :integer in Rails. But if primary keys or foreign keys in legacy tables are defined as &lt;span class=&quot;caps&quot;&gt;NUMBER&lt;/span&gt; then they will be mappec to :decimal in Rails.&lt;/p&gt;
&lt;p&gt;And what happens if e.g. primary key is mapped to :decimal in Rails? Then, for example, you get that customer.id is equal to &amp;#8220;123.0&amp;#8221; and you get ugly URLs like &amp;#8220;/customers/123.0&amp;#8221;.&lt;/p&gt;
&lt;p&gt;One workaround is to use customer.id.to_i everywhere but it is quite annoying. Therefore I created patch for Oracle adapter (this is tested with Rails 1.2.3) which always sets data type as :integer for all primary keys (column name ID) and foreign keys (column name like %_ID). This includes also date columns patch that &lt;a href=&quot;http://blog.rayapps.com/2007/08/27/how-to-explicitly-set-oracle-date-column-as-ruby-date-attribute/&quot;&gt;I wrote about previously&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveRecord::ConnectionAdapters&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OracleColumn&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simplified_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:boolean&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OracleAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_booleans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;NUMBER(1)&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RSI: treat columns which end with &amp;#39;date&amp;#39; as ruby date columns&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /date$/i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:date&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RSI: removed &amp;#39;date&amp;#39; from regex&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /time/i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:datetime&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RSI: treat id columns (primary key) as integer&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /^id$/i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:integer&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RSI: treat _id columns (foreign key) as integer&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /_id$/i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:integer&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# RSI: patch to change selected results NUMBER to integer for primary and foreign keys&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OracleAdapter&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;cols&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_col_names&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oracle_downcase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fetch&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;cols&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OCI8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOB&lt;/span&gt;
              &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Writable Large Object&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OraDate&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hour&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;minute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;second&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_date&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_time&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;raw_rnum_&amp;#39;&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# RSI: patch - convert to integer if column is ID or ends with _ID&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^id$/i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/_id$/i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;col&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;rows&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;ensure&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cursor&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I have not yet verified this with Rails 2.0. And probably I will collect all my Oracle adapter patches and will release it as plugin.  Is anybody interested in this?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Oracle E-Business Suite Authentication in Ruby</title>
   <link href="http://blog.rayapps.com/2007/10/30/oracle-e-business-suite-authentication-in-ruby/"/>
   <updated>2007-10-30T00:00:00+02:00</updated>
   <id>http://blog.rayapps.com/2007/10/30/oracle-e-business-suite-authentication-in-ruby</id>
   <content type="html">&lt;p&gt;I was developing Ruby on Rails application that access data from existing Oracle E-Business Suite application and I wanted to add to this application possibility for users to authenticate themselves by their existing Oracle E-Business Suite user names and passwords.&lt;/p&gt;
&lt;p&gt;Oracle is not publicly providing algorythms which are used for user passwords encryption (which are stored in FND_USER table) and therefore some googling was necessary. I was lucky to find &lt;a href=&quot;http://www.milci.com/eappsjira&quot;&gt;Jira eBusiness Suite Authenticator&lt;/a&gt; with full source code in Java which also included all Oracle E-Business Suite password encryption / decryption functions. Actually it seems that the &amp;gt;1000 lines source code is decompiled from Oracle Java classes as there are no comments and variable names don&amp;#8217;t tell anything.&lt;/p&gt;
&lt;p&gt;But as I did not have any better source material I started Ruby rewrite of this code and happily managed to finish it in couple of days. As a result I created &lt;a href=&quot;http://svn.rayapps.com/plugins/oracle_ebs_authentication/&quot;&gt;Oracle &lt;span class=&quot;caps&quot;&gt;EBS&lt;/span&gt; Authentication&lt;/a&gt; plugin and you can find out in &lt;a href=&quot;http://svn.rayapps.com/plugins/oracle_ebs_authentication/README&quot;&gt;&lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;&lt;/a&gt; file how to install it.&lt;/p&gt;
&lt;p&gt;Usage of this plugin is quite simple &amp;#8211; here is an example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;database_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_database&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;authenticator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OracleEbsAuthentication&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Authenticator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;database_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authenticator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;validate_user_password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# user authenticated&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;authenticator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_reponsibilities&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;System Administrator&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# user has System Administrator role&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# authentication failed&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;BTW&lt;/span&gt; Oracle &lt;span class=&quot;caps&quot;&gt;EBS&lt;/span&gt; password encryption approach &lt;a href=&quot;http://www.integrigy.com/security-resources/advisories/Integrigy_Encrypted_Password_Disclosure.pdf&quot;&gt;has quite a lot of weaknesses&lt;/a&gt;. So if you provide SQL*Net access to your Oracle &lt;span class=&quot;caps&quot;&gt;EBS&lt;/span&gt; database then anyone with valid Oracle &lt;span class=&quot;caps&quot;&gt;EBS&lt;/span&gt; user name and password can decrypt &lt;span class=&quot;caps&quot;&gt;APPS&lt;/span&gt; database user password and also can decrypt passwords of all other users. You can have a deeper look in plugin source code to understand how it can be done :)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails patch for Oracle CLOB defaults</title>
   <link href="http://blog.rayapps.com/2007/08/30/rails-patch-for-oracle-clob-defaults/"/>
   <updated>2007-08-30T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2007/08/30/rails-patch-for-oracle-clob-defaults</id>
   <content type="html">&lt;p&gt;If you are using Rails 1.2.3 with Oracle database then you might find that text attributes (which map to Oracle &lt;span class=&quot;caps&quot;&gt;CLOB&lt;/span&gt; data type) get invalid default values &amp;#8211; e.g. you might find that when you create new record it will get &amp;#8220;empty_clob()&amp;#8221; as default text attribute value.&lt;/p&gt;
&lt;p&gt;I found out that this issue is corrected in current edge Rails. As I still primarily use Rails 1.2.3 I created the following patch according to the changes that are done in edge Rails. You can put it in environment.rb file or better put into a separate file and require it in environment.rb file.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# RSI: text defaults handling from http://dev.rubyonrails.org/ticket/7344 &amp;amp; http://dev.rubyonrails.org/changeset/6090&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveRecord::ConnectionAdapters&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OracleAdapter&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#:nodoc:&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# RSI: patched&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:binary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%Q{empty_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;downcase&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;blob&amp;#39;&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;()}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;columns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#:nodoc:&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;table_cols&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SQL&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;        select column_name as name, data_type as sql_type, data_default, nullable,&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;               decode(data_type, &amp;#39;NUMBER&amp;#39;, data_precision,&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;                                 &amp;#39;FLOAT&amp;#39;, data_precision,&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;                                 &amp;#39;VARCHAR2&amp;#39;, data_length,&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;                                  null) as limit,&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;               decode(data_type, &amp;#39;NUMBER&amp;#39;, data_scale, null) as scale&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;          from all_tab_columns&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;         where owner      = &amp;#39;#{owner}&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;           and table_name = &amp;#39;#{table_name}&amp;#39;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;         order by column_id&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;      SQL&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;select_all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;table_cols&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;limit&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;scale&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sql_type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;limit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;,&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# clean up odd default spacing from Oracle&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;data_default&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;data_default&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^(.*?)\s*$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;\1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;data_default&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^&amp;#39;(.*)&amp;#39;$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;\1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# RSI: patched&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;data_default&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;data_default&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/^(null|empty_[bc]lob\(\))$/i&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;OracleColumn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oracle_downcase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;data_default&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;sql_type&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;nullable&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Y&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# RSI: added&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add_column_options!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#:nodoc: &lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# handle case of defaults for CLOB columns, which would otherwise get &amp;quot;quoted&amp;quot; incorrectly &lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options_include_default?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;column&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;column&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;sql&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot; DEFAULT &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;quote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;  
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; 
      &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>How to setup Ruby and Oracle client on Intel Mac</title>
   <link href="http://blog.rayapps.com/2007/08/27/how-to-setup-ruby-and-oracle-client-on-intel-mac/"/>
   <updated>2007-08-27T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2007/08/27/how-to-setup-ruby-and-oracle-client-on-intel-mac</id>
   <content type="html">&lt;blockquote class=&quot;warning&quot;&gt;
&lt;p class=&quot;warning&quot;&gt;&lt;span class=&quot;caps&quot;&gt;UPDATE&lt;/span&gt;: &lt;a href=&quot;http://blog.rayapps.com/2008/04/24/how-to-setup-ruby-and-new-oracle-instant-client-on-leopard/&quot;&gt;New version of this instruction for Intel Macs with Leopard is available here.&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://blog.rayapps.com/2009/09/06/how-to-setup-ruby-and-oracle-instant-client-on-snow-leopard/&quot;&gt;New version of instructions for Snow Leopard is available here.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;I have been using Oracle technologies for many years but just some time ago discovered Ruby and Rails. As I had ideas how to make Ruby on Rails frontends for existing Oracle based systems I started to explore how to use Ruby on Rails together with Oracle databases.&lt;/p&gt;
&lt;p&gt;Just recently I switched from PC notebook to MacBook Pro and unfortunately found out that &lt;a href=&quot;http://forums.oracle.com/forums/thread.jspa?threadID=481059&quot;&gt;Oracle Instant Client is not yet released for Intel Macs&lt;/a&gt;. As there is no promise when it will be released and as I could not wait for that I decided to make old &lt;a href=&quot;http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/macsoft.html&quot;&gt;PowerPC version of Oracle Instant Client&lt;/a&gt; to run on Intel Mac.  As I didn&amp;#8217;t find any good description how to do that I decided to write description of it by myself &amp;#8211; hopefully it will help others.&lt;br /&gt;
h3. Universal or &amp;#8220;fat&amp;#8221; binary Ruby&lt;/p&gt;
&lt;p&gt;The first thing is that you need to get &amp;#8220;universal&amp;#8221; or &amp;#8220;fat&amp;#8221; binary installation of Ruby &amp;#8211; it means that it contains both Intel and PowerPC (&lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt;) binary code. You will need &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; version of Ruby when you will work with Oracle and you will need Intel version of Ruby when you will do other things. &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; code is running in emulation mode on Intel processors and therfore is slower as well as there are some compatibility issues with some other libraries (I will mention later what issues I found out).&lt;/p&gt;
&lt;p&gt;It is possible to get and install precompiled Ruby either from &lt;a href=&quot;http://www.macports.org/&quot;&gt;MacPorts&lt;/a&gt; or using &lt;a href=&quot;http://rubyosx.rubyforge.org/&quot;&gt;Ruby One-Click Installer&lt;/a&gt;. But I prefer to compile Ruby from source code as it gives me more control what is installed and where. I used &lt;a href=&quot;http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx&quot;&gt;Hivelogic guide&lt;/a&gt; to compile Ruby from source code.&lt;/p&gt;
&lt;p&gt;Here are my additional notes what I changed to Hivelogic guide to make &amp;#8220;fat&amp;#8221; binaries.&lt;/p&gt;
&lt;h3&gt;Installing &amp;#8220;readline&amp;#8221;&lt;/h3&gt;
&lt;p&gt;At first you need to install &amp;#8220;readline&amp;#8221; shared libraries. At first I tried to make them from &amp;#8220;readline&amp;#8221; library source code but I always got just Intel binaries. Therefore I found and downloaded &amp;#8220;readline&amp;#8221; library &lt;a href=&quot;http://downloads.sourceforge.net/rudix/readline-5.2-8universal.dmg?modtime=1185921225&amp;big_mirror=0&quot;&gt;installer package&lt;/a&gt; with universal binaries and installed it. If you previously installed Intel binary of &amp;#8220;readline&amp;#8221; library then it is better to restart Mac to ensure that new dynamic library will be loaded.&lt;/p&gt;
&lt;h3&gt;Compiling Ruby&lt;/h3&gt;
&lt;p&gt;Next you need to download and extract Ruby 1.8.6 source code.&lt;/p&gt;
&lt;p&gt;Before running &amp;#8220;configure&amp;#8221; command I made the following change in &amp;#8220;configure&amp;#8221; file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Choose a default set of architectures based upon platform.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$target_os&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;darwin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;TARGET_ARCHS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;*ppc i386*&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can specify this also on command line but this change ensures that you will not forget it :) Then you need to run &amp;#8220;configure&amp;#8221; script with additional parameter at the end:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local \
--enable-shared --enable-fat-binary&lt;/pre&gt;
&lt;p&gt;After running &amp;#8220;make&amp;#8221; hopefully you will get everything compiled and you should get &amp;#8220;fat&amp;#8221; ruby binary. You can verify it with the following command and should see the following result:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;$ file ruby
ruby: Mach-O universal binary with 2 architectures
ruby (for architecture ppc):    Mach-O executable ppc
ruby (for architecture i386):   Mach-O executable i386&lt;/pre&gt;
&lt;p&gt;If you do not see that ruby binary contains both ppc and i386 executables then something went wrong. If it is OK then you can do &amp;#8220;sudo make install&amp;#8221; to install binaries in target directories.&lt;/p&gt;
&lt;h3&gt;Make &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; and &amp;#8220;fat&amp;#8221; versions of Ruby&lt;/h3&gt;
&lt;p&gt;As you will need to be able to force to run &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; version of Ruby later then we need to extract &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; executable in a separate file and store original &amp;#8220;fat&amp;#8221; binary in another file:&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;ditto -arch ppc /usr/local/bin/ruby /usr/local/bin/ruby_ppc
mv /usr/local/bin/ruby /usr/local/bin/ruby_fat&lt;/pre&gt;
&lt;p&gt;Then I recommend to create simple scripts that will help you to switch between &amp;#8220;fat&amp;#8221; and &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; versions of Ruby:&lt;/p&gt;
&lt;p&gt;ppc_ruby.sh:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;sh&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/bash&lt;/span&gt;
sudo ln -fs /usr/local/bin/ruby_ppc /usr/local/bin/ruby
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;fat_ruby.sh:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /usr/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby_fat&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /usr/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;So when you need to have &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; version of Ruby then run &amp;#8220;ppc_ruby.sh&amp;#8221; script and when you need &amp;#8220;fat&amp;#8221; version (which will actually run Intel binary) then run &amp;#8220;fat_ruby.sh&amp;#8221; script.&lt;/p&gt;
&lt;h3&gt;Install Oracle Instant Client for &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Install Oracle Instant Client according to the &lt;a href=&quot;http://creativi.st/blog/articles/2005/06/25/rails-oracle-client-on-mac-os-x&quot;&gt;following description&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Compile and install ruby-oci8&lt;/h3&gt;
&lt;p&gt;I used the &lt;a href=&quot;http://blog.sven-tissot.de/files/ror_and_oracle.html&quot;&gt;following description&lt;/a&gt; as a basis but some additional changes were needed for ruby-oci8-1.0.0-rc3 compilation.&lt;/p&gt;
&lt;p&gt;Open ruby-oci8 &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; file and find section &amp;#8220;=== Intel Mac&amp;#8221;  where are described what to do to compile ruby-oci8 on Intel Mac.&lt;/p&gt;
&lt;p&gt;Before running any ruby scripts you need to run ppc_ruby.sh script to switch to &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; binary.&lt;/p&gt;
&lt;p&gt;If you compiled &amp;#8220;fat&amp;#8221; Ruby from source code then you need to modify file /usr/local/lib/ruby/1.8/fat-darwin8.10.1/rbconfig.rb according to &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; file (make backup of file before modifications). If you installed Ruby from binary distribution then find where is located your rbconfig.rb file.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;find lines with &lt;span class=&quot;caps&quot;&gt;CONFIG&lt;/span&gt;[&amp;#8220;&lt;span class=&quot;caps&quot;&gt;CFLAGS&lt;/span&gt;&amp;#8221;] and &lt;span class=&quot;caps&quot;&gt;CONFIG&lt;/span&gt;[&amp;#8220;&lt;span class=&quot;caps&quot;&gt;LDFLAGS&lt;/span&gt;&amp;#8221;] and &lt;span class=&quot;caps&quot;&gt;CONFIG&lt;/span&gt;[&amp;#8220;ARCH_FLAG&amp;#8221;]&lt;/li&gt;
	&lt;li&gt;remove &amp;#8220;-arch i386&amp;#8221; if present (was not present in my case)&lt;/li&gt;
	&lt;li&gt;and add &amp;#8220;-arch ppc&amp;#8221; to all of these lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make and install ruby-oci8 and if it finishes successfully then restore rbconfig.rb file from backup.&lt;/p&gt;
&lt;p&gt;Try&lt;/p&gt;
&lt;pre class=&quot;terminal&quot;&gt;ruby -r oci8 -e &quot;OCI8.new('scott', 'tiger','orcl').exec('select * from emp') do |r| puts r.join(','); end&quot;&lt;/pre&gt;
&lt;p&gt;or similar to verify that you can access Oracle database from ruby.&lt;/p&gt;
&lt;p&gt;Congratulations! You have managed to connect to Oracle DB from Ruby on Intel Mac! If you got some issues at some point then please write it in comments and I will try to help with that.&lt;/p&gt;
&lt;h3&gt;Post installation notes&lt;/h3&gt;
&lt;p&gt;If you previously installed (or if you will install in future) any Ruby gems with native extensions (e.g. Mongrel or MySQL C &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;) then you need to reinstall these gems with &amp;#8220;fat&amp;#8221; Ruby (i.e. running &amp;#8220;fat_ruby.sh&amp;#8221; script and then &amp;#8220;sudo gem install&amp;#8221;). It will ensure that all gems will also have &amp;#8220;fat&amp;#8221; native extensions so that you can run them both in &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; Ruby and Intel Ruby.&lt;/p&gt;
&lt;h3&gt;Known issues with &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; Ruby&lt;/h3&gt;
&lt;p&gt;So far I have got the following issues with running &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; version of Ruby:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Capistrano is failing to make &lt;span class=&quot;caps&quot;&gt;SSH&lt;/span&gt; connection when running in &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; Ruby (I was testing with new Capistrano 2.0). Therefore you need always to switch to &amp;#8220;fat&amp;#8221; Ruby before running &amp;#8220;cap deploy&amp;#8221;.&lt;/li&gt;
	&lt;li&gt;As I also wanted that MySQL is running under &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; I got some issues with MySQL native extensions compilation &amp;#8211; I solved them using the &lt;a href=&quot;http://www.fatmixx.com/2007/05/30/ruby-mysql-gem-error/&quot;&gt;following description&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;ruby-ldap connections were failing when running  in &lt;span class=&quot;caps&quot;&gt;PPC&lt;/span&gt; Ruby within Ruby on Rails. I managed to fix it by putting &amp;#8220;require ldap&amp;#8221; as a first line in config/environment.rb file.&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>How to explicitly set Oracle DATE column as Ruby Date attribute</title>
   <link href="http://blog.rayapps.com/2007/08/27/how-to-explicitly-set-oracle-date-column-as-ruby-date-attribute/"/>
   <updated>2007-08-27T00:00:00+03:00</updated>
   <id>http://blog.rayapps.com/2007/08/27/how-to-explicitly-set-oracle-date-column-as-ruby-date-attribute</id>
   <content type="html">&lt;p&gt;As you probably have noticed Oracle has just one &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; type for table columns which is supposed both for storing just dates and dates with time. From the other side Ruby has different classes Date and Time. If you are using Rails then Rails tries to guess from the database column types what are the classes for corresponding object attributes in Ruby. And as both dates and dates with time appear as &lt;span class=&quot;caps&quot;&gt;DATE&lt;/span&gt; columns Rails has difficulties to guess whether it should be Ruby Date or Ruby Time.&lt;/p&gt;
&lt;p&gt;Current Rails Oracle adapter has the following workaround implemented:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# * Oracle uses DATE or TIMESTAMP datatypes for both dates and times.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   Consequently some hacks are employed to map data back to Date or Time&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   in Ruby. If the column_name ends in _time it&amp;#39;s created as a Ruby Time.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   Else if the hours/minutes/seconds are 0, I make it a Ruby Date. Else&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   it&amp;#39;s a Ruby Time. This is a bit nasty - but if you use Duck Typing&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   you&amp;#39;ll probably not care very much. In 9i and up it&amp;#39;s tempting to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   map DATE to Date and TIMESTAMP to Time, but too many databases use&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   DATE for both. Timezones and sub-second precision on timestamps are&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   not supported.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This workaround is problematic if you have date columns which can be &lt;span class=&quot;caps&quot;&gt;NULL&lt;/span&gt;. In this case Rails cannot determine if this is date or datetime column. And if you use standard scaffolds or, for example, &lt;a href=&quot;http://activescaffold.com/&quot;&gt;ActiveScaffold&lt;/a&gt;, it will use &lt;em&gt;datetime_select&lt;/em&gt; helper and not &lt;em&gt;date_select&lt;/em&gt; helper for this column &amp;#8211; which means that you will be asked to specify also time for new dates.&lt;/p&gt;
&lt;p&gt;Therefore, as I typically name all date columns with _DATE at the end, I created a patch which makes all such columns to be handled as Ruby Date attributes:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# RSI: OracleAdapter patch - treat columns which end with &amp;#39;date&amp;#39; as ruby date type&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ActiveRecord::ConnectionAdapters&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OracleColumn&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simplified_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:boolean&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OracleAdapter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emulate_booleans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;field_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;NUMBER(1)&amp;#39;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RSI: treat columns which end with &amp;#39;date&amp;#39; as ruby date columns&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /date$/i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:date&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RSI: removed &amp;#39;date&amp;#39; from regex&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt; /time/i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:datetime&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Include this in environment.rb file or put it into separate file in e.g. lib directory and require it in environment.rb file.&lt;/p&gt;</content>
 </entry>
 

</feed>
