Archive for the 'How-to' Category

Essential guide for the Ruby driver

In the past couple of months, I received a fairly large number of requests about how to use the IBM_DB Ruby driver to query DB2. So I decided to create an essential guide for using the Ruby DB2 driver. Amongst the topics I covered, there are: connecting to the database (local or remote), executing queries, retrieving connection and execution errors, fetching results, using prepared statements for parameterized queries and finally how to use the driver for dealing with stored procedures. That should be more than enough to get your started with the driver and, even if it’s about Ruby and not Rails, it will be beneficial to those who develop DB2 on Rails applications.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

February 08 2008 | How-to | No Comments »

How to setup the Ruby driver for DB2 on Linux

Yesterday I wrote a short guide to setting up DB2 9.5, Ruby and the IBM_DB driver on Linux (32 or 64 bits), and published it on my personal blog. I didn’t host it on DB2onRails.com since it also covers the installation of the newly released Python driver, a subject somewhat off-topic for this blog. That said, the step-by-step instructions provided for Ubuntu 7.10 may be very useful to many of our Ruby users following this blog. If you’re experiencing problems with the installation of DB2 9.5 or the ibm_db Ruby gem on Linux, check out Guide to setting up the IBM Ruby and Python drivers for DB2 on Linux (32 or 64 bit) for help.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

November 15 2007 | How-to | 1 Comment »

Troubleshooting DB2 on Rails

DB2 on Rails provides the developer with many ways to retrieve information about errors which have occurred. Rails developers can take a look at the logs within the log folder in order to read the SQL errors returned by the datasever. But what about simple Ruby scripts? Let’s try to connect to DB2 with the wrong user credentials:

conn = IBM_DB::connect("mydb","myuser","my_wrong_pass")
#=> false

false. That doesn’t really help us too much. We know that something went wrong, but we don’t exactly know what. Luckily for us, the IBM_DB driver gives us all the tools that we need to properly troubleshoot problems. The example above can be rewritten in this way:

if conn = IBM_DB::connect("mydb","myuser","my_wrong_pass")
  # do something interesting
else
  # conn is false
  raise IBM_DB::conn_errormsg
end
#=> RuntimeError: [IBM][CLI Driver] SQL30082N Security processing failed with reason
“24″ (”USERNAME AND/OR PASSWORD INVALID”).  SQLSTATE=08001 SQLCODE=-30082

Okay, that should have us covered when it comes to failed attempts to connect to the database, but what about failed queries? Analogously, the IBM_DB driver provides us with the IBM_DB::stmt_errormsg method:

if stmt = IBM_DB::exec(conn, "SELECT * FROM WRONG_TABLE)
  # process the results
else
  # stmt is false
  raise IBM_DB::stmt_errormsg
end
#=> RuntimeError: => [IBM][CLI Driver][DB2/NT] SQL0204N " DB2ADMIN.WRONG_TABLE" is
an undefined name.  SQLSTATE=42704 SQLCODE=-204
    

DB2 error messages are usually easy to understand and with a bit of help from the DB2 Information Center you should be able to get out of trouble most of the time.

DB2 CLI Tracing

Despite the helpful error messages, there are situations in which troubleshooting can be hard because everything seems to be in the right place but your application is still acting up for some reason. The ultimate tool when it comes to troubleshooting for DB2 and Ruby/Rails application problems is to enable DB2 CLI (Call Level Interface) tracing. The CLI trace captures information about applications that access the DB2 CLI driver. Tracing gives you the ability to analyze low level calls to the C driver API with details on the input and output, to and from the database. The resulting trace is not particularly easy to understand for a DB2 novice, but it can offer a microscopic view which is invaluable for understanding problems that are hidden by the abstractions of higher level APIs, and allow you to see to a certain degree what’s happening under the hood.

The two free PDFs, Call Level Interface Guide and Reference, Volume 1 and Volume 2 are the best references if you need to look up calls in your CLI trace files. Instructions on how to enable CLI level tracing for DB2 Express-C LUW (Linux/Unix/Windows) can be found here.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

October 19 2007 | How-to and Tips&Tricks | 5 Comments »

rake db:test:purge and rake db:test:clone

With an increasing number of Rails developers adopting DB2 as their database of choice, and the welcoming approach towards suggestions and requests on our end, it comes as no surprise that the feedback is rolling in faster than ever. We are very pleased about this, and in this short article I’d love to address two of the most requested features.

rake db:test:purge

Running rake db:test:purge generates the following error:

  rake aborted!
  Task not supported by 'ibm_db'

db:test:purge is a rake task defined in the Rails gem within the file rails-1.2.3/lib/tasks/databases.rake. This file takes care of, amongst other things, defining the specific behavior for each database adapter known to rails, when the user requests a database purge. It is essentially a big case statement with specific ruby code which drops all the user objects from the supported database.

ibm_db is currently shipped independently from Rails, therefore it is missing from that case statement, and as a result the task will appear to not be supported by ibm_db.

If you are using the ibm_db adapter for DB2, you don’t want to miss the opportunity to use rake db:test:purge and take advantage of other tasks that rely on this in order to work. What you can do is, manually insert a snippet of code for the ibm_db case in databases.rake.

An easy and straightforward implementation of this would be dropping the database and recreating it from scratch. I’m not allowed into the other adapters implementations, but I assume this could be what some of the other adapters may be doing. I believe this is not the right thing to do with DB2 though. In fact, this would have two main drawbacks. Firstly, creating a database every time, implies that the task becomes quite slow, because the creation of a database in DB2 is a “magical process” that can take up to a minute (for good reason, and that minute can save you lots of money in the years to come as you use the database). Secondly, the database that you have created in the first place may have many options and parameters configured, and collecting them all and reapplying them may not be the easiest or the smartest thing to do.

A different approach would be to handle this the right way, by dropping all the user schemas and the objects contained within the database. The code needs to be placed within the case statement we mentioned above:

    desc Empty the test database
    task :purge => :environment do
      abcs = ActiveRecord::Base.configurations
      case abcs[”test“][”adapter“]
        #…
      end
   end

With the current (Rails 1.2.3) databases.rake you can practically just copy and paste the following code at line 145 in the file:

when ibm_db
  ActiveRecord::Base.establish_connection(:test)
  conn = ActiveRecord::Base.connection.connection

  begin
    # Required for the stored procedure ADMIN_DROP_SCHEMA
    ActiveRecord::Base.connection.execute(”CREATE TABLESPACE SYSTOOLSPACE“)
    systool_existing = false
  rescue
    # The SYSTOOLSPAGE already exists
    systool_existing = true
  end

  # Collects all the user defined schemas
  user_schemas_sql = SELECT SCHEMANAME FROM SYSCAT.SCHEMATA WHERE DEFINER <> ‘SYSIBM’ AND 
  SCHEMANAME NOT IN (’NULLID’, ‘ERRORSCHEMA’, ‘SYSTOOLS’)
  schemas = ActiveRecord::Base.connection.select_all(user_schemas_sql)

  unless schemas.empty?
    errortabschema = ERRORSCHEMA
    errortab = ERRORTABLE

    # Drop each schema and all its objects
    schemas.each do |schema|
      schema_name = schema[”schemaname“].strip.upcase
      sql = CALL SYSPROC.ADMIN_DROP_SCHEMA(’#{schema_name}‘, NULL, ?, ?)
      stmt = IBM_DB::prepare(conn, sql)
      IBM_DB::bind_param(stmt, 1, errortabschema“, IBM_DB::SQL_PARAM_INPUT)
      IBM_DB::bind_param(stmt, 2, errortab“, IBM_DB::SQL_PARAM_INPUT)
      IBM_DB::execute(stmt)
    end

    # If the tablespace SYSTOOLSPACE didn’t exist initially, it gets dropped  
    ActiveRecord::Base.connection.execute(”DROP TABLESPACE SYSTOOLSPACE“) unless systool_existing

    # Drops the remaining schema “ERRORSCHEMA”
    ActiveRecord::Base.connection.execute(”DROP SCHEMA ERRORSCHEMA RESTRICT“)
  end

This can also be used do define a method on its own (e.g. purge_database(:mydb)), should you require that functionality somewhere in your code. In that case, just make sure to modify the first lines in order to use the already established connection or define your own.

rake db:test:clone

Now that rake db:test:purge is working, you will be able to successfully run rake db:test:clone. Out of the box, there are two limitations though. Rails doesn’t acknowledge tablespaces and foreign keys (the lack of the first is understandable as it is strongly related to DB2, but the lack of the second is much less justifiable).

This doesn’t affect many developers but if it does affect you, it is both annoying and problematic. Suppose in fact, that you have created the database objects in your development db through migrations. You may have specified a certain tablespace name by passing :options => “IN mytablespace” to the create_table method. Running rake db:test:clone will generate the table in the test database within the default tablespace (USERSPACE1) rather than in the one that you’ve specified for the development database. Not only this, but if you manually defined foreign keys by executing sql statements in the migrations or directly, these will not appear in the cloned test database.

This is not an issue specific to DB2, it is just the way it works in Rails at the moment. In fact there are third party plugins that attempt to introduce these and other features that are shortcoming of Rails’ core (e.g. Foreign Key Schema Dumper Plugin for MySQL and PostgreSQL).

In order to address those two concerns when using DB2, you don’t have to operate on the definition of the task directly. In fact, the db:test:clone loads the dumped schema in the test environment. The culprit is therefore ActiveRecord SchemaDumper which doesn’t know anything about DB2 Tablespaces and about foreign keys. Changes to this will also affect the db:schema:dump task, which will in turn produce more correct and “database aware” db\schema.rb files.

The file schema_dumper.rb within the ActiveRecord gem (activerecord-1.15.3\lib\active_record\schema_dumper.rb) can be directly modified for your specific needs. At line 21 the dump method becomes:

    def dump(stream)
      header(stream)
      tables(stream)
      # Foreign keys are added for DB2 only
      if @connection.adapter_name == IBM_DB
        foreign_keys(stream)
      end
      trailer(stream)
      stream
    end

At line 89 within the table method, we need to specify code to handle the possibility of a non-default tablespace:

# Options to retrieve the right tablespace are enabled for DB2 only
if @connection.adapter_name == IBM_DB
  tbspace_sql = select TBSPACE from syscat.tables where tabname=’#{table.upcase}
  table_space = @connection.select_one(tbspace_sql)[”tbspace“]
  if table_space != USERSPACE1
    # A different tablespace was defined       
    tbl.print %Q(, :options => “IN #{table_space})
  end
end

At this point, just after the index method, we need to define the method foreign_keys:

def foreign_keys(stream)
  references = @connection.select_all(”SELECT * FROM SYSCAT.REFERENCES“)
  for reference in references
    constraint = reference[”constname“]
    schema = reference[”tabschema“]
    table = reference[”tabname“]
    cols = reference[”fk_colnames“]
    ref_schema = reference[”reftabschema“]
    ref_table = reference[”reftabname“]
    ref_cols = reference[”pk_colnames“]
    if reference[”updaterule“] == R
      update_action = RESTRICT
    else
      update_action = NO ACTION
    end

    delete_action = case reference[”deleterule“]
                          when A
                            NO ACTION
                          when R
                            RESTRICT
                          when C
                            CASCADE
                          when N
                            SET NULL
                          end

    foreign_key_sql =   execute(ALTER TABLE #{schema}.#{table} add 
CONSTRAINT #{constraint} FOREIGN KEY (#{cols.strip})n  
REFERENCES #{ref_schema}.#{ref_table} (#{ref_cols.strip}) 
ON UPDATE #{update_action} ON DELETE #{delete_action}n  
ENFORCED ENABLE QUERY OPTIMIZATION)n  
    stream.print foreign_key_sql
    stream.puts
  end
end

As you can imagine, it is possible to prevent the need to modify the file directly, by simply extending the SchemaDumper class in, for example, a plugin. You would have to overwrite the original methods within the SchemaDumper class:

module ActiveRecord
  class SchemaDumper

    # …

    def dump(stream)
      #…
    end

    private

    # …

    def table(table, stream)
      # …
    end

    # …

    def foreign_keys(stream)
    # …
    end

  end
end

It would be beneficial to aggregate several improvements in a “DB2 PowerPack” plugin of some sort, and it’s very likely that we will eventually work on publishing something like this.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

June 20 2007 | How-to | 1 Comment »

A couple of webcasts on DB2 Express-C

One of the key components of the Starter Toolkit for DB2 on Rails is the free DB2 Express-C data server. Recently we announced that not only do we offer a free DB2 Express-C but that you now also have an option of purchasing support subscription if you need one. With this support subscription you also get data replication and high availability clustering and remote site disaster recovery. Pretty decent set of features for $2995 for a server for one year.
On June 7 we will talk about this product in a couple of free (naturally) webcasts. One of the webcasts called Premiering DB2 Express-C: The truly free database is designed to introduce developers to DB2 Express-C. The other webcast Drive revenue with DB2 Express-C is more suited for ISVs and business partners. If you don’t catch either one of the webcasts on June 7, don’t worry, they will be available for a replay. To register for these webcast or for a later replay click on the links above.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

May 30 2007 | Announcements and How-to | Comments Off

DB2 and Ruby on Rails, Part 1

Developerworks has published the first part of a long and detailed article about DB2 on Rails programming. In this article the basics of how to get started, migrations and an introduction to working with XML are covered. In the follow up article, XML will be covered in detail with informative step-by-step instructions on how to use DB2 pureXML™ in Rails. I’m sure you will find them to be extemely useful and informative.

Please visit and rate the first part of the article here.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

May 28 2007 | Announcements and How-to | Comments Off

Scaffolding XML columns as text area boxes

The Rails adapter and the Ruby driver for IBM DB2 enable you to take full advantage of the exclusive pureXML capabilities. XML fields are properly handled and also recognized when using migrations. We do not bind the content of XML columns to a specific XML Ruby representation (e.g. REXML) but rather let the user decide what they’d prefer to use, in light also of the fact that mapping to a simple string is often all that is required given the fast XQuery/XPath querying features provided out of the box by DB2.

The scaffolding generator ignores XML fields though. This is due to the fact that the bult-in scaffolding generates form elements for only a few datatypes. For example :time and :binary are excluded, and foreign keys are not handled as well. Users will typically want to handle XML fields in a customized way, for instance, showing only certain elements of the XML document in their forms. However if you wish to enable by default the automatic generation of text area boxes when using scaffolding, you can edit C:\ruby\lib\ruby\gems\1.8\gems\actionpack-1.12.5\lib\action_view\helpers\active _record_helper.rb (or the equivalent on your system) by replacing the to_tag method with the following:

def to_tag(options = {})
  case column_type
    when :string
       field_type = @method_name.include?(”password”) ? “password” : “text”
       to_input_field_tag(field_type, options)
    when :text, :xml
       to_text_area_tag(options)
    when :integer, :float
       to_input_field_tag(”text”, options)
    when :date
       to_date_select_tag(options)
    when :datetime, :timestamp
       to_datetime_select_tag(options)
    when :boolean
       to_boolean_select_tag(options)
   end
end

As you can see, all we are doing here is adding the XML datatype to the list of cases which require the rendering of a text area box.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

January 06 2007 | How-to and Tips&Tricks | 1 Comment »

IBM DB2 and migrations

There’ve been a few questions about migrations and the IBM DB2 adapter. I’ve written a short list that explains what transformations are supported and what are not so far.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

June 27 2006 | How-to | Comments Off

New article on DB2 on Rails by Edd Dumbill

When you download Startup Toolkit for DB2 on Rails you get 3 flash movies that help to get you started. But these demos will only give you a taste. On the other hand there are many really good books out there on both Ruby and Rails but they don’t talk about DB2. Now there is also an article on developerDomain. This article is written by Edd Dumbill a guy with a lot of practical experience both doing and teaching Ruby on Rails. So, clear out 15 minutes on your calendar and point your browser to http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0606dumbill/ to read An introduction to Ruby on Rails for DB2 developers.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

June 23 2006 | Announcements and How-to | Comments Off

How to connect Rails to DB2

I’ve just created a page that explains how to configure the database.yml file in Rails so that it works with the IBM DB2 adapter. You can find it here.

We plan to create an extensive FAQ section on this site, where we’ll address several of the main questions that we’ve been receiving over the past few weeks.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

June 22 2006 | How-to | 2 Comments »