diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..85dfb39505fd53416248ca766a8a03145427611e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.buildpath
+.project
+.idea
+*.gem
diff --git a/Changelog b/Changelog
new file mode 100644
index 0000000000000000000000000000000000000000..186f9163be42c803b68f4e49239d6c2b571b5b8d
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,38 @@
+* Tue 30 Jun 2009 22:14:38 CEST
+Added test cases for the standalone driver (ruby unit test).
+
+* Thu 25 Jun 2009 17:31:02 CEST
+Fixed a major bug that resulted in data corruption;
+MAPI implementation code cleanup and bug fixes;
+Support to ruby 1.9;
+Both the standalone driver and activerecord now support transactions; nested transactions
+are simulated via savepoints in activerecord.
+Added a Rakefile and script to run activerecord unit test suite.
+Type conversion in the standalone driver is now performed after data has been retrieved and can be executed on single fields.
+
+* Mon 25 May 2009 17:52:01 CEST
+Imported last week changes (protocol 9 support, parametrized the connection options in the activerecord adapter, fixed a bug in the auth protocol v8).
+Fixed a bug in the mapi protocol that resulted in data loss (wrong handling of TRANSACTIONS).
+Began to port the activerecord test suite to monetdb (not all test cases can be performed).
+Removed an unneeded file ('lib/MonetDBStatement.rb') from the gemspec of the standalone driver (the feature will be moved to HEAD).
+Began to port the driver to ruby 1.9.
+Removed *.gem files from cvs.
+
+* Mon 18 May 2009 15:22:31 CEST
+Fixed bugs that prevented the correct working of activerecords' migration;
+The activerecord connector now supports insertion, update and alter table operations;
+Type casting is working in activerecord;
+Added a rubygem and rakefile for activerecord-monetdb-adapter;
+Added a new usage example for activerecord to the README file;
+Added an example directory to the cvs tree;
+The driver now correctly works with merovingian.
+
+
+* Sat  9 May 2009 15:58:36 CEST
+Fixed bugs with the query processing in the standalone driver;
+Added INSERT and UPDATE methods in the activerecord connector.
+
+* Thu  7 May 2009 17:03:01 CEST
+
+Added a check against the protocol version during authentication;
+Imported the activerecord code (available under adapter/).
diff --git a/README b/README
new file mode 100644
index 0000000000000000000000000000000000000000..4143b64561faa30531f831aab92ca74079468429
--- /dev/null
+++ b/README
@@ -0,0 +1,154 @@
+== Standalone driver ==
+This directory contains the a ruby interface to monetdb5 
+written in pure ruby.
+
+lib/MonetDB.rb
+lib/MonetDBConnection.rb
+lib/MonetDBStatements.rb
+lib/MonetDBData.rb
+lib/MonetDBExceptions.rb
+lib/hasher.rb
+lib/demo.rb: demo application how to interact with the database
+
+ruby-monetdb-sql-0.1.gemspec: make file for rubygems
+
+doc/: rubydoc in HTML format
+
+== Installation ==
+
+The standalone monetdb driver can be installed using the RubyGems Package Manager.
+
+First build a gem file starting from the gemspec configuration:
+
+$ gem build ruby-monetdb-sql-0.1.gemspec
+
+Then install with the command:
+
+$ gem install ruby-monetdb-sql-0.1.gem
+
+== Usage ==
+To use the standalone driver import the 'MonetDB' class and 'rubygems' (in case you installed it using gems).
+
+A typical sequence of events is as follows:
+Invoke query using the database handle to send the statement to the server and get back a result set object.
+
+A result set object  has methods for fetching rows, moving around in the result set, obtaining column metadata, and releasing the result set.
+Use a row fetching method such as fetch_row or an iterator such as each to access the rows of the result set.
+If you want a count of the number of rows in the result set: invoke 'num_rows' method.
+Invoke 'free' to release the result set. 
+
+== Example ==
+
+require 'MonetDB'
+
+db = MonetDB.new
+db.connect(user = "monetdb", passwd = "monetdb", lang = "sql", host="127.0.0.1", port = 50000, db_name = "demo", auth_type = "SHA1")
+
+# set type_cast=true to enable MonetDB to Ruby type mapping
+res = db.query("SELECT * from tables;", type_cast = false)
+
+#puts res.debug_columns_type
+
+puts "Number of rows returned: " + res.num_rows.to_s
+puts "Number of fields: " + res.num_fields.to_s
+
+
+# Get the columns' name
+col_names = res.name_fields
+
+
+# Iterate over the record set and retrieve on row at a time
+puts res.fetch
+while row = res.fetch do
+  printf "%s \n", row
+end
+
+# Release the result set.
+res.free
+
+# Disconnect from server
+db.close
+
+See lib/demo.rb and the MonetDBDatar class documentation for more examples.
+
+
+
+== ActiveRecord connector adapter ==
+Active Record connects business objects and database tables to create a persistable domain model where logic and data are presented in one wrapping. It‘s an implementation of the object-relational mapping (ORM) pattern.
+
+Required files:
+
+adapter/lib/active_record/monetdb_adapter.rb
+
+Usage example follows:
+require 'active_record'
+
+ActiveRecord::Base.logger = Logger.new(STDERR)
+ActiveRecord::Base.colorize_logging = true
+
+ActiveRecord::Base.establish_connection(
+        :adapter => "monetdb",
+        :host => "localhost",
+        :database => "demo"
+)
+
+# Create a new table
+class AddTests < ActiveRecord::Migration
+  def self.up
+    create_table :tests do |table|
+        table.column :name, :string
+        table.column :surname, :string
+    end
+  end
+
+  def self.down
+   drop_table :tests
+  end
+
+end
+
+AddTests.up
+
+# Migration: add a column name with a default value
+class AddAge < ActiveRecord::Migration 
+  def self.up
+    add_column :tests, :age, :smallint, :default => 18
+  end
+
+  def self.down
+    remove_column :tests, :age
+  end
+
+end
+
+class Test < ActiveRecord::Base
+end
+
+# Insert an entry in the table
+Test.create(:name => 'X', :surname => 'Y')
+
+# add a column
+AddAge.up
+
+# return the first result of the query SELECT * from tables
+row = Test.find(:first)
+printf "SELECT * from tests LIMIT 1:\n"
+printf "Name: %s, Surname: %s, Age: %s\n", row.name, row.surname, row.age
+
+# Drop the table
+AddTests.down
+
+== Rubygem ==
+
+The standalone ruby driver can be distributed as a ruby gem.
+A gem file is already available; however, it can be generated 
+starting from the ruby-monetdb-sql-0.1.gemspec file:
+
+$ gem build ruby-monetdb-sql-0.1.gemspec
+
+To install the file run the command:
+
+$ gem install ruby-monetdb-sql-0.1.gem
+
+Documentation in ri and html format will be generated and installed as well
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000000000000000000000000000000000000..8a4470bb1ccf98ed2a4bbfa241340a2e8aeac868
--- /dev/null
+++ b/TODO
@@ -0,0 +1,5 @@
+* test and improve utf8 and type conversion
+
+* documentation cleanup
+
+* OSM on rails demo (slowed down due to third party plugins requirements)
diff --git a/adapter/Makefile.ag b/adapter/Makefile.ag
new file mode 100644
index 0000000000000000000000000000000000000000..b54b10b8363dcd124904aa54b1eecf3caed20665
--- /dev/null
+++ b/adapter/Makefile.ag
@@ -0,0 +1,24 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+gem_adapter = {
+	FILES = activerecord-monetdb-adapter-0.1.gemspec
+	DIR = $(prefix)/$(RUBY_DIR)
+}
+
+EXTRA_DIST = activerecord-monetdb-adapter-0.1.gemspec
+EXTRA_DIST_DIR = active_record lib
diff --git a/adapter/activerecord-monetdb-adapter-0.1.gemspec b/adapter/activerecord-monetdb-adapter-0.1.gemspec
new file mode 100644
index 0000000000000000000000000000000000000000..83d91d3b6aba6d3961f8e63e5c6696a8e832c798
--- /dev/null
+++ b/adapter/activerecord-monetdb-adapter-0.1.gemspec
@@ -0,0 +1,18 @@
+Gem::Specification.new do |s|
+   s.required_ruby_version = '>= 2.1.0'
+   s.name = %q{activerecord-monetdb-adapter}
+   s.version = "0.2"
+   s.date = %q{2009-05-18}
+   s.authors = ["G Modena"]
+   s.email = %q{gm@cwi.nl}
+   s.summary = %q{ActiveRecord Connector for MonetDB}
+   s.homepage = %q{http://monetdb.cwi.nl/}
+   s.description = %q{ActiveRecord Connector for MonetDB built on top of the pure Ruby database driver}
+   s.files = [ "lib/active_record/connection_adapters/monetdb_adapter.rb" ]
+   s.has_rdoc = true
+   s.require_path = 'lib'
+   s.add_dependency(%q<activerecord>, [">= 2.3.2"])
+   s.add_dependency(%q<ruby-monetdb-sql>, [">= 0.1"])
+   # placeholder project to avoid warning about not having a rubyforge_project
+   s.rubyforge_project = "nowarning"
+end
diff --git a/adapter/lib/active_record/connection_adapters/monetdb_adapter.rb b/adapter/lib/active_record/connection_adapters/monetdb_adapter.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fa5a7999f209c1dbe3a7f9fa7749ebb1ba411551
--- /dev/null
+++ b/adapter/lib/active_record/connection_adapters/monetdb_adapter.rb
@@ -0,0 +1,575 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+# MonetDB Active Record adapter
+# monetdb_adapter.rb
+
+# The code is an adaption of the adapter developer by Michalis Polakis (2008), to work on top of the pure ruby MonetDB 
+# interface
+
+# Refreshed by Martin Samson (2011)
+
+MDB_SYS_SCHEMA = "sys."
+MDB_NON_SYSTEM_TABLES_ONLY = "and system = false"
+
+require 'active_record/connection_adapters/abstract_adapter'
+require 'MonetDB'
+
+module ActiveRecord
+  class Base
+    # Establishes a connection to the database that's used by all Active Record objects
+    def self.monetdb_connection(config)
+      # extract connection parameters
+      config = config.symbolize_keys
+
+      host = config[:host] || "127.0.0.1"
+      port = config[:port] || 50000
+      username = config[:username].to_s if config[:username]
+      password = config[:password].to_s if config[:password]
+
+      # Use "sql" as default language if none is specified
+      lang = config[:lang] || "sql"
+
+      if config.key?(:database)
+        database = config[:database]
+      else
+        raise ArgumentError, "No database specified. Missing argument: database."
+      end
+
+      dbh = MonetDB.new
+      ConnectionAdapters::MonetDBAdapter.new(dbh, logger, [host, port, username, password, database, lang], config)
+    end
+  end
+
+
+  module ConnectionAdapters
+    class MonetDBColumn < Column
+      # Handles the case where column type is int but default
+      # column value is the next value of a sequence(string).
+      # By overriding this function, extract_default in
+      # schema_definitions does not return a fixnum(0 or 1) but 
+      # the correct default value.
+      def type_cast(value)
+        if value.nil?
+          nil
+        elsif type == :integer && value =~/next value for/
+          nil
+        else
+          super
+        end
+      end
+
+      private
+
+      def simplified_type(field_type)
+        case field_type
+          when /int|smallint/i
+            :integer
+          when /real|double/i
+            :float
+          when /datetime/i
+            :timestamp
+          when /timestamp/i
+            :timestamp
+          when /char/i, /varchar/i
+            :string
+          when /bigint/i
+            :bigint
+          else
+            super
+        end
+      end
+
+    end #end of MonetDBColumn class
+
+    class TableDefinition
+      # Override so that we handle the fact that MonetDB 
+      # doesn't support "limit" on integer column.
+      # Otherwise same implementation
+      def column(name, type, options = {})
+        column = self[name] || ColumnDefinition.new(@base, name, type)
+
+        if type.to_sym != :integer and type.to_sym != :primary_key
+          column.limit = options[:limit] || native[type.to_sym][:limit] if options[:limit] or native[type.to_sym]
+        end
+
+        column.precision = options[:precision]
+        column.scale = options[:scale]
+        column.default = options[:default]
+        column.null = options[:null]
+
+        @columns << column unless @columns.include? column
+        self
+      end
+
+    end
+
+    class MonetDBAdapter < AbstractAdapter
+      class BindSubstitution < Arel::Visitors::MySQL
+        include Arel::Visitors::BindVisitor
+      end
+
+      def initialize(connection, logger, connection_options, config)
+        super(connection, logger)
+        @visitor = BindSubstitution.new self
+        @connection_options, @config = connection_options, config
+        connect
+      end
+
+      def adapter_name #:nodoc:
+        'MonetDB'
+      end
+
+      # Functions like rename_table, rename_column and 
+      # change_column cannot be implemented in MonetDB.
+      def supports_migrations?
+        true
+      end
+
+      # testing savepoints in progress
+      def supports_savepoints? #:nodoc:
+        true
+      end
+
+      def support_transaction? #:nodoc:
+        false
+      end
+
+      def supports_ddl_transactions?
+        false
+      end
+
+      def native_database_types
+        {
+            :primary_key => "int NOT NULL auto_increment PRIMARY KEY",
+            :string => {:name => "varchar", :limit => 255},
+            :text => {:name => "clob"},
+            :integer => {:name => "int"},
+            :float => {:name => "float"},
+            :decimal => {:name => "decimal"},
+            :datetime => {:name => "timestamp"},
+            :timestamp => {:name => "timestamp"},
+            :time => {:name => "time"},
+            :date => {:name => "date"},
+            :binary => {:name => "blob"},
+            :boolean => {:name => "boolean"},
+            :bigint => {:name => "bigint"}
+        }
+      end
+
+      #MonetDB does not support using DISTINCT withing COUNT
+      #by default
+      def supports_count_distinct?
+        false
+      end
+
+      #----------CONNECTION MANAGEMENT------------------
+
+      # Check if the connection is active
+      def active?
+        if @connection != nil
+          @connection.is_connected?
+        end
+
+        return false
+      end
+
+      # Close this connection and open a new one in its place.
+      def reconnect!
+        if @connection != nil
+          #@connection.reconnect
+          false
+        end
+      end
+
+      def disconnect!
+        #@connection.auto_commit(flag=true)
+        @connection.close
+      end
+
+      # -------END OF CONNECTION MANAGEMENT----------------
+
+
+      # ===============SCHEMA DEFINITIONS===========#
+
+      def binary_to_string(value)
+        res = ""
+        value.scan(/../).each { |i| res << i.hex.chr }
+        res
+      end
+
+      # ===========END OF SCHEMA DEFINITIONS========#
+
+
+      #===============SCHEMA STATEMENTS===========#
+      # The following schema_statements.rb functions are not supported by MonetDB (19/5/2008).
+      #
+      # -rename_table : not such functionality by MonetDB's API. Altering some 
+      #  administratives' tables values has no result.
+      #
+      # -rename_column : Could be possible if I make a new_name column copy the
+      # data from the old column there and then drop that column. But I would 
+      # also have to take care of references and other constraints. Not sure if
+      # this is desired.
+      # 
+      # -change_column : Alteration of a column's datatype is not supported. 
+      # NOTE WE MAY BE ABLE TO "CHANGE" A COLUMN DEFINITION IF WE DROP THE COLUMN
+      # AND CREATE A NEW ONE WITH THE OLD NAME. THIS COULD WORK AS LONG AS WE DON'T
+      # LOSE ANY DATA.
+
+
+      # Sets a new default value for a column.
+      # ===== Examples =====
+      #  change_column_default(:suppliers, :qualification, 'new')
+      #  change_column_default(:accounts, :authorized, 1)
+      def change_column_default(table_name, column_name, default)
+        sql = "ALTER TABLE #{table_name} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT" #{quote(default)}"
+
+        if (default.nil? || (default.casecmp("NULL")==0))
+          sql << " NULL"
+        else
+          sql << quote(default)
+        end
+        p "SQL: " + sql + '\n'
+        hdl = execute(sql)
+      end
+
+      def remove_index(table_name, options = {})
+        hdl = execute("DROP INDEX #{index_name(table_name, options)}")
+      end
+
+      # MonetDB does not support limits on certain data types
+      # Limit is supported for the {char, varchar, clob, blob, time, timestamp} data types.
+      def type_to_sql(type, limit = nil, precision = nil, scale = nil)
+        return super if limit.nil?
+
+        # strip off limits on data types not supporting them
+        if [:integer, :double, :date, :bigint].include? type
+          type.to_s
+        else
+          super
+        end
+      end
+
+      # Returns an array of Column objects for the table specified by +table_name+.
+      def columns(table_name, name = nil)
+        return [] if table_name.to_s.strip.empty?
+        table_name = table_name.to_s if table_name.is_a?(Symbol)
+        table_name = table_name.split('.')[-1] unless table_name.nil?
+
+        hdl = execute("	SELECT name, type, type_digits, type_scale, \"default\", \"null\"  FROM #{MDB_SYS_SCHEMA}_columns 	WHERE table_id in (SELECT id FROM #{MDB_SYS_SCHEMA}_tables WHERE name = '#{table_name}' #{MDB_NON_SYSTEM_TABLES_ONLY})", name)
+
+        num_rows = hdl.num_rows
+        return [] unless num_rows >= 1
+
+        result = []
+
+
+        while row = hdl.fetch_hash do
+          col_name = row['name']
+          col_default = row['default']
+          # If there is no default value, it assigns NIL
+          col_default = nil if (col_default && col_default.upcase == 'NULL')
+          # Removes single quotes from the default value
+          col_default.gsub!(/^'(.*)'$/, '\1') unless col_default.nil?
+
+          # A string is returned so we must convert it to boolean
+          col_nullable = row['null']
+
+          if (col_nullable.casecmp("true") == 0)
+            col_nullable = true
+          elsif (col_nullable.casecmp("false") == 0)
+            col_nullable = false
+          end
+
+          col_type = row['type']
+          type_digits = row['type_digits']
+          type_scale = row['type_scale']
+
+
+          # Don't care about datatypes that aren't supported by
+          # ActiveRecord, like interval. 
+          # Also do nothing for datatypes that don't support limit
+          # like integer, double, date, bigint
+          if (col_type == "clob" || col_type == "blob")
+            if (type_digits.to_i > 0)
+              col_type << "(#{type_digits})"
+            end
+          elsif (col_type == "char" ||
+              col_type == "varchar" ||
+              col_type == "time" ||
+              col_type == "timestamp"
+          )
+            col_type << "(#{type_digits})"
+          elsif (col_type == "decimal")
+            if (type_scale.to_i == 0)
+              col_type << "(#{type_digits})"
+            else
+              col_type << "(#{type_digits},#{type_scale})"
+            end
+          end
+
+          # instantiate a new column and insert into the result array
+          result << MonetDBColumn.new(col_name, col_default, col_type, col_nullable)
+
+        end
+
+        #  check that free has been correctly performed
+        hdl.free
+
+        return result
+      end
+
+      def primary_key(table)
+        'id'
+      end
+
+      # Adds a new column to the named table.
+      # See TableDefinition#column for details of the options you can use.
+      def add_column(table_name, column_name, type, options = {})
+        if ((type.to_sym == :decimal) && (options[:precision].to_i+options[:scale].to_i > 18))
+          raise StandardError, "It is not possible to have a decimal column where Precision + Scale > 18 . The column will not be added to the table!"
+          return
+        else
+          super
+        end
+      end
+
+      # Return an array with all non-system table names of the current 
+      # database schema
+      def tables(name = nil)
+        cur_schema = select_value("select current_schema", name)
+        select_values("	SELECT t.name FROM #{MDB_SYS_SCHEMA}_tables t, sys.schemas s
+  			WHERE s.name = '#{cur_schema}' 
+  				AND t.schema_id = s.id 
+  				AND t.system = false", name)
+      end
+
+      # Returns an array of indexes for the given table.
+      def indexes(table_name, name = nil)
+        sql_query = "	SELECT distinct i.name as index_name, k.\"name\", k.nr
+  	 		FROM
+  				#{MDB_SYS_SCHEMA}idxs i, #{MDB_SYS_SCHEMA}_tables t, #{MDB_SYS_SCHEMA}objects k
+  	 		WHERE
+  				i.type = 0 AND i.name not like '%pkey' 
+  				AND i.id = k.id AND t.id = i.table_id 
+  				AND t.name = '#{table_name.to_s}'
+  	 		ORDER BY i.name, k.nr;"
+        result = select_all(sql_query, name);
+
+        cur_index = nil
+        indexes = []
+
+        result.each do |row|
+          if cur_index != row['index_name']
+            indexes << IndexDefinition.new(table_name, row['index_name'], false, [])
+            cur_index = row['index_name']
+          end
+
+          indexes.last.columns << row['name']
+        end
+
+        indexes
+      end
+
+      # ===========END OF SCHEMA STATEMENTS========#
+
+      # ===========QUOTING=========================#
+      def quote(value, column = nil)
+        if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
+          s = column.class.string_to_binary(value).unpack("H*")[0]
+          "BLOB '#{s}'"
+        else
+          super
+        end
+      end
+
+      def quote_column_name(name) #:nodoc:
+        "\"#{name.to_s}\""
+      end
+
+      def quote_table_name(name) #:nodoc:
+        quote_column_name(name).gsub('.', '"."')
+      end
+
+      # If the quoted true is 'true' MonetDB throws a string cast exception
+      def quoted_true
+        "true"
+      end
+
+      # If the quoted false is 'false' MonetDB throws a string cast exception
+      def quoted_false
+        "false"
+      end
+
+      # ===========END-OF-QUOTING==================#
+
+
+      # =========DATABASE=STATEMENTS===============#
+
+      # Returns an array of arrays containing the field values.
+      # Order of columns in tuple arrays is not guaranteed.
+      def select_rows(sql, name = nil)
+        result = select(sql, name)
+        result.map { |v| v.values }
+      end
+
+      def execute(sql, name = nil)
+        sql = sql.gsub('!=', '<>')
+        sql += ';'
+        @connection.query(sql)
+      end
+
+      def exec_query(sql, name = nil, binds = [])
+        select_rows(sql, name)
+      end
+
+      def last_inserted_id(result)
+        result.last_insert_id
+      end
+
+      def delete(arel, name = nil, binds = [])
+        res = super(arel, name, binds)
+        res.affected_rows
+      end
+
+      # Begins the transaction.
+      def begin_db_transaction
+        hdl = execute("START TRANSACTION")
+      end
+
+      # Commits the transaction (ends TRANSACTIOM). 
+      def commit_db_transaction
+        hdl = execute("COMMIT")
+      end
+
+      # Rolls back the transaction. Must be
+      # done if the transaction block raises an exception or returns false (ends TRANSACTIOM).
+      def rollback_db_transaction
+        hdl = execute("ROLLBACK")
+      end
+
+      def current_savepoint_name
+        @connection.transactions || 0
+      end
+
+      # Create a new savepoint
+      def create_savepoint
+        @connection.save
+        execute("SAVEPOINT #{current_savepoint_name}")
+      end
+
+      # rollback to the last savepoint
+      def rollback_to_savepoint
+        execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
+      end
+
+      # release current savepoint
+      def release_savepoint
+        execute("RELEASE SAVEPOINT #{current_savepoint_name}")
+      end
+
+      def add_lock!(sql, options)
+        @logger.info "Warning: MonetDB :lock option '#{options[:lock].inspect}' not supported. Returning unmodified sql statement!" if @logger && options.has_key?(:lock)
+        sql
+      end
+
+      def empty_insert_statement(table_name)
+        # Ensures that the auto-generated id  value will not violate the primary key constraint.
+        # comment out for production code(?)
+        #make_sure_pk_works(table_name, nil)
+        #"INSERT INTO #{quote_table_name(table_name)}"
+      end
+
+      #=======END=OF=DATABASE=STATEMENTS=========#
+
+      # Returns an array of record hashes with the column names as keys and
+      # column values as values.
+      def select(sql, name = nil, binds = [])
+        hdl = execute(sql, name)
+        hdl.result_hashes
+      end
+
+      # Executes the update statement and returns the number of rows affected.
+      def update_sql(sql, name = nil)
+        hdl = execute(sql, name)
+        hdl.affected_rows
+      end
+
+      # Returns the last auto-generated ID from the affected table.
+      def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
+        # Ensures that the auto-generated id  value will not violate the
+        # primary key constraint. Read the comments of make_sure_pk_works
+        # and documentation for further information.
+        # comment out for production code(?)
+        # table_name = extract_table_name_from_insertion_query(sql)
+        # make_sure_pk_works(table_name,name)
+        hdl = execute(sql, name)
+        hdl.last_insert_id
+      end
+
+      protected
+      # Some tests insert some tuples with the id values set. In other words, the sequence
+      # is not used to generate a value for the primary key column named id. When a new tuple
+      # it to be inserted, where the id value is not set explicitly, a primary key violation will
+      # be raised because the generated from the sequence value is the same as one of the existing
+      # id values. This happens in unit tests quite often. So this function serves that the unit tests
+      # pass. However it is very expensive( sends 4 queries to the server) and probably not suitable for
+      # production code. Check the implementation for further info/details.
+      def make_sure_pk_works(table_name, name)
+        # Ensure the auto-generated id will not violate the primary key constraint.
+        # This is expensive and it's used so that the tests pass. Comment out for production code(?).
+        # Assume that table name has one primary key column named id that is associated with a sequence,
+        # otherwise return
+        hdl = nil
+        sequence_name = extract_sequence_name(select_value("select \"default\" from #{MDB_SYS_SCHEMA}_columns where table_id in (select id from #{MDB_SYS_SCHEMA}_tables where name = '#{table_name}') and name='id';"))
+
+        return if sequence_name.blank?
+
+        max_id = select_value("select max(id) from #{table_name}").to_i
+        next_seq_val = select_value("select next value for #{sequence_name}").to_i
+
+        if (max_id > next_seq_val)
+          hdl = execute("ALTER SEQUENCE #{sequence_name} RESTART WITH #{max_id+1}", name)
+        else
+          hdl = execute("ALTER SEQUENCE #{sequence_name} RESTART WITH #{next_seq_val+1}", name)
+        end
+      end
+
+      # Auxiliary function that extracts the table name from an insertion query
+      # It's called by insert_sql in order to assist at make_sure_pk_works.
+      # Ideally, if make_sure_pk_works is commented out for production code, this
+      # function will be never called.
+      def extract_table_name_from_insertion_query(sql)
+        $1 if sql =~ /INSERT INTO "(.*)" \(/
+      end
+
+      # Auxiliary function that extracts the sequence name.
+      # It's called by make_sure_pk_works.
+      # Ideally, if make_sure_pk_works is commented out for production code, this
+      # function will be never called.
+      def extract_sequence_name(seqStr)
+        $1 if seqStr =~ /\."(.*)"/
+      end
+
+      private
+      def connect
+        @connection.connect(user = @connection_options[2], passwd = @connection_options[3], lang = @connection_options[5], host = @connection_options[0], port = @connection_options[1], db_name = @connection_options[4], auth_type = "SHA1") if @connection
+      end
+    end
+  end
+end
diff --git a/doc/rails.txt b/doc/rails.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ba869de6a9ee87c7cee2068d3ef9f848bcef42d5
--- /dev/null
+++ b/doc/rails.txt
@@ -0,0 +1,98 @@
+= MonetDB on rails =
+
+This file documents the steps necessary to make rails working with MonetDB.
+Database management in rails is performend via the ActiveRecord (ORM) adapter (http://api.rubyonrails.org/files/vendor/rails/activerecord/README.html).
+
+The ruby/monetdb driver comes packaged as:
+
+1) a standalone driver (only depends on ruby 1.8 and ruby 1.9);
+2) and activerecord connector built on top of the standalone driver.
+
+The following steps assumes that you already have obtained and installed a working copy of the rails framework and the 'rubygems' package manager.
+
+For more informations about rubygems please refer to: http://rubyforge.org/projects/rubygems/
+
+== Installation == 
+
+On rpm base systems both the activerecord and standalone driver should be installed via the monetdb-clients package.
+Please note that the building and installing process do not require root privileges.
+
+
+=== Install the standalone driver ===
+
+If you are using a source code version of monetdb cd into the driver directory located at './clients/src/ruby'
+
+First build a gem file starting from the given gemspec:
+
+$ gem build ruby-monetdb-sql-0.1.gemspec
+
+and install the resulting gem with the command:
+
+$ gem install --local ruby-monetdb-sql-0.1.gem
+
+
+=== Install the activerecord connector ===
+
+If you are using a source code version of monetdb cd into the activerecord adapter directory located at './clients/src/ruby/adapter'
+
+First build a gem file starting from the given gemspec:
+
+$ gem build activerecord-monetdb-adapter-0.1.gemspec
+
+and install the resulting gem with the command:
+
+$ gem install --local activerecord-monetdb-adapter-0.1.gem
+
+
+== Configuration ==
+
+Create a new rails application with the 'rails' command and cd into it:
+
+$ rails myapp
+$ cd myapp
+
+This will create the usual Rails folder structure.
+
+In order to start using rails with MonetDB as a backend we need to properly configure the databases by editing the file 'config/database.yml'
+
+This is a sample configuration used to connect to a database named 'test':
+
+  adapter: monetdb
+  username: monetdb 
+  password: monetdb
+  hostname: localhost
+  port:    50000
+  database: test
+
+
+Where adapter is the name of the activerecord connector you want to use (in this case 'monetdb').
+
+The driver works either by directly connecting to a mserver5 instance or through merovingian. Make sure to create the database ('test') before proceeding.
+
+Once the database.yml file as been properly configured proceed by creating the Controller files either manually or by using the scaffolding script:
+
+$ ./script/generate scaffold
+
+Operations on the database are performed in the fashion of rake tasks; once the Controllers have been properly created and customized, schemas can be generated with the  task 'migrate':
+
+$ rake db:migrate
+
+The current schema version number can be obtained with the task 'version':
+
+$ rake db:version
+
+It is possible to revert to previous schemas definitions via the 'rollback' task:
+
+$ rake db:rollback
+
+In the same way it is possible to drop all generated schemas with the 'drop' task:
+
+$ rake db:drop:all
+
+== References ==
+
+What follows is a list of tutorials about getting started with rails.
+
+1) http://www.akitaonrails.com/2007/12/12/rolling-with-rails-2-0-the-first-full-tutorial
+2) http://oreilly.com/ruby/archive/rails.html
+3) http://developer.apple.com/tools/rubyonrails.html
diff --git a/examples/activerecord.rb b/examples/activerecord.rb
new file mode 100644
index 0000000000000000000000000000000000000000..366d740db6841ac5215c00bd7f449ec82cb68643
--- /dev/null
+++ b/examples/activerecord.rb
@@ -0,0 +1,81 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+require 'rubygems'
+require 'active_record'
+
+ActiveRecord::Base.logger = Logger.new(STDERR)
+ActiveRecord::Base.colorize_logging = true
+
+ActiveRecord::Base.establish_connection(
+        :adapter  => "monetdb",
+        :host     => "localhost",
+        :database => "test",
+        :username => "monetdb",
+        :password => "monetdb",
+        :hostname => "localhost",
+        :port     => 50000
+)
+
+# Create a new table
+class AddTests < ActiveRecord::Migration
+  def self.up
+    create_table :tests do |table|
+        table.column :name, :string
+        table.column :surname, :string
+    end
+  end
+
+  def self.down
+   drop_table :tests
+  end
+
+end
+
+AddTests.up
+
+# Migration: add a column name with a default value
+class AddAge < ActiveRecord::Migration 
+  def self.up
+    add_column :tests, :age, :smallint, :default => 18
+  end
+
+  def self.down
+    remove_column :tests, :age
+  end
+
+end
+
+class Test < ActiveRecord::Base
+end
+
+# Insert an entry in the table
+Test.create(:name => 'X', :surname => 'Y')
+
+# add a column
+AddAge.up
+
+# return the first result of the query SELECT * from tables
+row = Test.find(:first)
+printf "SELECT * from tests LIMIT 1:\n"
+printf "Name: %s, Surname: %s, Age: %s\n", row.name, row.surname, row.age
+
+# revert the added column
+AddAge.down
+
+# Drop the table
+AddTests.down
diff --git a/examples/standalone.rb b/examples/standalone.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bce8a6cb6f36264a03f7287b86626b335b9103be
--- /dev/null
+++ b/examples/standalone.rb
@@ -0,0 +1,86 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+require 'rubygems'
+require 'MonetDB'
+
+db = MonetDB.new
+
+db.connect(user = "monetdb", passwd = "monetdb", lang = "sql", host="127.0.0.1", port = 50000, db_name = "test", auth_type = "SHA1")
+
+# set type_cast=true to enable MonetDB to Ruby type mapping
+res = db.query("select * from tables");
+
+puts "Number of rows returned: " + res.num_rows.to_s
+puts "Number of fields: " + res.num_fields.to_s
+
+
+# Get the columns' name
+#col_names = res.name_fields
+
+# Get the columns' type
+#col_types = res.type_fields
+
+###### Fetch all rows and store them
+#puts res.fetch_all
+
+
+# Iterate over the record set and retrieve on row at a time
+while row = res.fetch do
+  printf "%s \n", row
+end
+
+
+###### Get all records and hash them by column name
+#row = res.fetch_all_hash()
+
+#puts col_names[0] + "\t\t" + col_names[1]
+#0.upto(res.num_rows) { |i|
+#  puts row['id'][i] + "\t\t" + row['name'][i] 
+#}
+
+
+###### Iterator over columns (on cell at a time), convert the "id" field to a ruby integer value.  
+
+#while row = res.fetch_hash do
+#  printf "%s, %i\n", row["name"], row["id"].getInt
+#end
+
+###### Transactions
+
+db.query("START TRANSACTION")
+db.auto_commit(false)
+# create a savepoint
+db.save
+db.query("SAVEPOINT #{db.transactions} ;")
+
+# Modify the database
+db.query('CREATE TABLE test (col1 INT, col2 INT)')
+
+# Rollback to previous savepoint, discard changes
+
+db.query("ROLLBACK TO SAVEPOINT #{db.transactions}")
+# Release the save point
+db.release
+
+# Switch to auto commit mode
+db.auto_commit(true)
+
+# Deallocate memory used for storing the record set
+res.free
+
+db.close
diff --git a/lib/MonetDB.rb b/lib/MonetDB.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d1936dc464ea7f74f7d87c025be17a2fa117d61f
--- /dev/null
+++ b/lib/MonetDB.rb
@@ -0,0 +1,312 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+
+# A typical sequence of events is as follows:
+# Fire a query using the database handle to send the statement to the server and get back a result set object.
+
+# A result set object  has methods for fetching rows, moving around in the result set, obtaining column metadata, and releasing the result set.
+# Use a row fetching method such as 'fetch_row' or an iterator such as each to access the rows of the result set.
+# Call 'free' to release the result set. 
+
+
+#module MonetDB
+
+  require 'MonetDBConnection'
+  require 'MonetDBData'
+  require 'MonetDBExceptions'
+  
+    # = Introduction
+    #
+    # A typical sequence of events is as follows:
+    # Create a database instance (handle), invoke query using the database handle to send the statement to the server and get back a result set object.
+    #
+    # A result set object  has methods for fetching rows, moving around in the result set, obtaining column metadata, and releasing the result set.
+    # A result set object is an instance of the MonetDBData class.
+    #
+    # Records can be returneds as arrays and iterators over the set.
+    #
+    # A database handler (dbh) is and instance of the MonetDB class.
+    #
+    # = Connection management 
+    #
+    #  connect    -  establish a new connection
+    #                * user: username (default is monetdb)
+    #                * passwd: password (default is monetdb)
+    #                * lang: language (default is sql) 
+    #                * host: server hostanme or ip  (default is localhost)
+    #                * port: server port (default is 50000)
+    #                * db_name: name of the database to connect to
+    #                * auth_type: hashing function to use during authentication (default is SHA1)
+    #
+    #  is_connected? - returns true if there is an active connection to a server, false otherwise 
+    #  reconnect     - recconnect to a server
+    #  close         - terminate a connection
+    #  auto_commit?  - returns ture if the session is running in auto commit mode, false otherwise  
+    #  auto_commit   - enable/disable auto commit mode.
+    #
+    #  query         - fire a query
+    #
+    # Currently MAPI protocols 8 and 9 are supported.
+    #
+    # = Managing record sets 
+    #
+    #
+    # A record set is represented as an instance of the MonetDBData class; the class provides methods to manage retrieved data.
+    #
+    #
+    # The following methods allow to iterate over data:
+    # 
+    # fetch          - iterates over the record set and retrieves on row at a time. Each row is returned as an array.
+    # fetch_hash     - iterates over columns (on cell at a time). 
+    # fetch_all_hash - returns record set entries hashed by column name orderd by column position.
+    # 
+    # To return the record set as an array (with each tuple stored as array of fields) the following method can be used:
+    # 
+    # fetch_all      - fetch all rows and store them  
+    #
+    #
+    # Information about the retrieved record set can be obtained via the following methods:
+    #
+    # num_rows       - returns the number of rows present in the record set
+    # num_fields     - returns the number of fields (columns) that compose the schema
+    # name_fields    - returns the (ordered) name of the schema's columns
+    # type_fields    - returns the (ordered) types list of the schema's columns
+    #
+    # To release a record set MonetDBData#free can be used.
+    #
+    # = Type conversion
+    #
+    # A mapping between SQL and ruby type is supported. Each retrieved field can be converted to a ruby datatype via 
+    # a getTYPE method.
+    #
+    # The currently supported cast methods are:
+    #
+    # getInt        - convert to an integer value
+    # getFloat      - convert to a floating point value
+    # getString     - return a string representation of the value, with trailing and leading " characters removed
+    # getBlob       - convert an SQL stored HEX string to its binary representation
+    # getTime       - return a string representation of a TIME field
+    # getDate       - return a string representation of a DATE field
+    # getDateTime   - convert a TIMESTAMP field to a ruby Time object
+    # getChar       - on ruby >= 1.9, convert a CHAR field to char 
+    # getBool       - convert a BOOLEAN field to a ruby bool object. If the value of the field is unknown, nil is returned
+    # getNull       - convert a NULL value to a nil object
+    #
+    #
+    # = Transactions 
+    #
+    # By default monetdb works in auto_commit mode. To turn this feature off MonetDB#auto_commit(flag=false) can be used.
+    #
+    # Once auto_commit has been disable it is possible to start transactions, create/delete savepoints, rollback and commit with 
+    # the usual SQL statements.
+    #
+    # Savepoints IDs can be generated using the MonetDB#save method. To release a savepoint ID use MonetDB#release.
+    # 
+    # Savepoints can be accessed (as a stack) with the MonetDB#transactions method.
+    #
+    # example/standalone.rb contains usage example of the above mentioned methods.
+
+    # = Introduction
+    #
+    # A typical sequence of events is as follows:
+    # Create a database instance (handle), invoke query using the database handle to send the statement to the server and get back a result set object.
+    #
+    # A result set object  has methods for fetching rows, moving around in the result set, obtaining column metadata, and releasing the result set.
+    # A result set object is an instance of the MonetDBData class.
+    #
+    # Records can be returneds as arrays and iterators over the set.
+    #
+    # A database handler (dbh) is and instance of the MonetDB class.
+    #
+    # = Connection management 
+    #
+    #  connect    -  establish a new connection
+    #                * user: username (default is monetdb)
+    #                * passwd: password (default is monetdb)
+    #                * lang: language (default is sql) 
+    #                * host: server hostanme or ip  (default is localhost)
+    #                * port: server port (default is 50000)
+    #                * db_name: name of the database to connect to
+    #                * auth_type: hashing function to use during authentication (default is SHA1)
+    #
+    #  is_connected? - returns true if there is an active connection to a server, false otherwise 
+    #  reconnect     - recconnect to a server
+    #  close         - terminate a connection
+    #  auto_commit?  - returns ture if the session is running in auto commit mode, false otherwise  
+    #  auto_commit   - enable/disable auto commit mode.
+    #
+    #  query         - fire a query
+    #
+    # Currently MAPI protocols 8 and 9 are supported.
+    #
+    # = Managing record sets 
+    #
+    #
+    # A record set is represented as an instance of the MonetDBData class; the class provides methods to manage retrieved data.
+    #
+    #
+    # The following methods allow to iterate over data:
+    # 
+    # fetch          - iterates over the record set and retrieves on row at a time. Each row is returned as an array.
+    # fetch_hash     - iterates over columns (on cell at a time). 
+    # fetch_all_hash - returns record set entries hashed by column name orderd by column position.
+    # 
+    # To return the record set as an array (with each tuple stored as array of fields) the following method can be used:
+    # 
+    # fetch_all      - fetch all rows and store them  
+    #
+    #
+    # Information about the retrieved record set can be obtained via the following methods:
+    #
+    # num_rows       - returns the number of rows present in the record set
+    # num_fields     - returns the number of fields (columns) that compose the schema
+    # name_fields    - returns the (ordered) name of the schema's columns
+    #
+    # To release a record set MonetDBData#free can be used.
+    #
+    # = Type conversion 
+    #
+    # Invoking MonetDB#query with the flag type_conversion=true will result in a type cast of the record set fields from SQL types to ruby types
+    #
+    # demo.rb contains usage example of the above mentioned methods.
+
+  class MonetDB
+    DEFAULT_USERNAME = "monetdb"
+    DEFAULT_PASSWORD = "monetdb"
+    DEFAULT_LANG     = LANG_SQL
+    DEFAULT_HOST     = "127.0.0.1"
+    DEFAULT_PORT     = 50000
+    DEFAULT_DATABASE = "test"
+    DEFAULT_AUTHTYPE = "SHA1"
+    
+    def initalize()
+      @connection = nil 
+    end
+  
+    # Establish a new connection.
+    #                * username: username (default is monetdb)
+    #                * password: password (default is monetdb)
+    #                * lang: language (default is sql) 
+    #                * host: server hostanme or ip  (default is localhost)
+    #                * port: server port (default is 50000)
+    #                * db_name: name of the database to connect to
+    #                * auth_type: hashing function to use during authentication (default is SHA1)
+    def connect(username=DEFAULT_USERNAME, password=DEFAULT_PASSWORD, lang=DEFAULT_LANG, host=DEFAULT_HOST, port=DEFAULT_PORT, db_name=DEFAULT_DATABASE, auth_type=DEFAULT_AUTHTYPE)
+      # TODO: handle pools of connections
+      
+      @username = username
+      @password = password
+      @lang = lang
+      @host = host
+      @port = port
+      @db_name = db_name
+      @auth_type = auth_type
+      
+      @connection = MonetDBConnection.new(user = @username, passwd = @password, lang = @lang, host = @host, port = @port)
+      @connection.connect(@db_name, @auth_type)
+    end
+  
+    # Establish a new connection using named parameters.
+    #                * user: username (default is monetdb)
+    #                * passwd: password (default is monetdb)
+    #                * language: lang (default is sql) 
+    #                * host: host to connect to  (default is localhost)
+    #                * port: port to connect to (default is 50000)
+    #                * database: name of the database to connect to
+    #                * auth_type: hashing function to use during authentication (default is SHA1)
+    #
+    # Conventionally named parameters are passed as an hash.
+    #
+    # Ruby 1.8:
+    # MonetDB::conn({ :user => "username", :passwd => "password", :database => "database"})
+    #
+    # Ruby 1.9:
+    # MonetDB::conn(user: "username", passwd: "password", database: "database")
+    def conn(options)      
+      user        = options[:user] || DEFAULT_USERNAME
+      passwd      = options[:passwd] || DEFAULT_PASSWORD
+      language    = options[:language] || DEFAULT_LANG
+      host        = options[:host] || DEFAULT_HOST
+      port        = options[:port] || DEFAULT_PORT
+      database    = options[:database] || DEFAULT_DATABASE
+      auth_type   = options[:auth_type] || DEFAULT_AUTHTYPE
+      
+      connect(user, passwd, language, host, port, database, auth_type)
+    end
+  
+    # Send a <b> user submitted </b> query to the server and store the response.
+    # Returns and instance of MonetDBData.
+    def query(q="")
+      if  @connection != nil 
+        @data = MonetDBData.new(@connection)
+        @data.execute(q)
+      end
+      return @data
+    end
+    
+    # Return true if there exists a "connection" object
+    def is_connected?
+      if @connection == nil
+        return false
+      else 
+        return true
+      end
+    end
+  
+    # Reconnect to the server
+    def reconnect
+      if @connection != nil
+        self.close
+        
+        @connection = MonetDBConnection.new(user = @username, passwd = @password, lang = @lang, host = @host, port = @port)
+        @connection.connect(db_name = @db_name, auth_type = @auth_type)
+      end
+    end
+    
+    # Turn auto commit on/off
+    def auto_commit(flag=true)
+      @connection.set_auto_commit(flag)
+    end
+  
+    # Returns the current auto commit  (on/off) settings.
+    def auto_commit?
+      @connection.auto_commit?
+    end
+    
+    # Returns the name of the last savepoint in a transactions pool
+    def transactions
+      @connection.savepoint
+    end
+    
+    # Create a new savepoint ID
+    def save
+      @connection.transactions.save
+    end
+    
+    # Release a savepoint ID
+    def release
+      @connection.transactions.release
+    end
+    
+    # Close an active connection
+    def close()
+      @connection.disconnect
+      @connection = nil
+    end
+  end
+#end
diff --git a/lib/MonetDBConnection.rb b/lib/MonetDBConnection.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e18df90bc14416eb5651a3457488dc53d2cd007e
--- /dev/null
+++ b/lib/MonetDBConnection.rb
@@ -0,0 +1,548 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+# Implements the MAPI communication protocol
+
+
+require 'socket'
+require 'time'
+require 'hasher'
+require 'MonetDBExceptions'
+require 'uri' # parse merovingian redirects
+
+Q_TABLE = "1" # SELECT operation
+Q_UPDATE = "2" # INSERT/UPDATE operations
+Q_CREATE = "3" # CREATE/DROP TABLE operations
+Q_TRANSACTION = "4" # TRANSACTION
+Q_PREPARE = "5"
+Q_BLOCK = "6" # QBLOCK message
+
+MSG_REDIRECT = '^' # auth redirection through merovingian
+MSG_QUERY = '&'
+MSG_SCHEMA_HEADER = '%'
+MSG_INFO = '!' # info response from mserver
+MSG_TUPLE = '['
+MSG_PROMPT = ""
+
+
+REPLY_SIZE = '-1'
+
+MAX_AUTH_ITERATION = 10 # maximum number of atuh iterations (thorough merovingian) allowed
+
+MONET_ERROR = -1
+
+LANG_SQL = "sql"
+
+# Protocols
+MAPIv8 = 8
+MAPIv9 = 9
+
+MONETDB_MEROVINGIAN = "merovingian"
+MONETDB_MSERVER = "monetdb"
+
+MEROVINGIAN_MAX_ITERATIONS = 10
+
+class MonetDBConnection
+  # enable debug output
+  @@DEBUG = false
+
+  # hour in seconds, used for timezone calculation
+  @@HOUR = 3600
+
+  # maximum size (in bytes) for a monetdb message to be sent
+  @@MAX_MESSAGE_SIZE = 2048
+
+  # endianness of a message sent to the server
+  @@CLIENT_ENDIANNESS = "BIG"
+
+  # MAPI protocols supported by the driver
+  @@SUPPORTED_PROTOCOLS = [MAPIv8, MAPIv9]
+
+  attr_reader :socket, :auto_commit, :transactions, :lang
+
+  # Instantiates a new MonetDBConnection object
+  # * user: username (default is monetdb)
+  # * passwd: password (default is monetdb)
+  # * lang: language (default is sql) 
+  # * host: server hostanme or ip  (default is localhost)
+  # * port: server port (default is 50000)
+
+  def initialize(user = "monetdb", passwd = "monetdb", lang = "sql", host="127.0.0.1", port = "50000")
+    @user = user
+    @passwd = passwd
+    @lang = lang.downcase
+    @host = host
+    @port = port
+
+    @client_endianness = @@CLIENT_ENDIANNESS
+
+    @auth_iteration = 0
+    @connection_established = false
+
+    @transactions = MonetDBTransaction.new # handles a pool of transactions (generates and keeps track of savepoints)
+
+    if @@DEBUG == true
+      require 'logger'
+    end
+
+    if @lang[0, 3] == 'sql'
+      @lang = "sql"
+    end
+
+  end
+
+  # Connect to the database, creates a new socket
+  def connect(db_name = 'demo', auth_type = 'SHA1')
+    @database = db_name
+    @auth_type = auth_type
+
+    @socket = TCPSocket.new(@host, @port.to_i)
+    if real_connect
+      if @lang == LANG_SQL
+        set_timezone
+        set_reply_size
+      end
+      true
+    end
+    false
+  end
+
+  # perform a real connection; retrieve challenge, proxy through merovinginan, build challenge and set the timezone
+  def real_connect
+
+    server_challenge = retrieve_server_challenge()
+    if server_challenge != nil
+      salt = server_challenge.split(':')[0]
+      @server_name = server_challenge.split(':')[1]
+      @protocol = server_challenge.split(':')[2].to_i
+      @supported_auth_types = server_challenge.split(':')[3].split(',')
+      @server_endianness = server_challenge.split(':')[4]
+      if @protocol == MAPIv9
+        @pwhash = server_challenge.split(':')[5]
+      end
+    else
+      raise MonetDBConnectionError, "Error: server returned an empty challenge string."
+    end
+
+    # The server supports only RIPMED168 or crypt as an authentication hash function, but the driver does not.
+    if @supported_auth_types.length == 1
+      auth = @supported_auth_types[0]
+      if auth.upcase == "RIPEMD160" or auth.upcase == "CRYPT"
+        raise MonetDBConnectionError, auth.upcase + " " + ": algorithm not supported by ruby-monetdb."
+      end
+    end
+
+
+    # If the server protocol version is not 8: abort and notify the user.
+    if @@SUPPORTED_PROTOCOLS.include?(@protocol) == false
+      raise MonetDBProtocolError, "Protocol not supported. The current implementation of ruby-monetdb works with MAPI protocols #{@@SUPPORTED_PROTOCOLS} only."
+
+    elsif mapi_proto_v8?
+      reply = build_auth_string_v8(@auth_type, salt, @database)
+    elsif mapi_proto_v9?
+      reply = build_auth_string_v9(@auth_type, salt, @database)
+    end
+
+    if @socket != nil
+      @connection_established = true
+
+      send(reply)
+      monetdb_auth = receive
+
+      if monetdb_auth.length == 0
+        # auth succedeed
+        true
+      else
+        if monetdb_auth[0].chr == MSG_REDIRECT
+          #redirection
+
+          redirects = [] # store a list of possible redirects
+
+          monetdb_auth.split('\n').each do |m|
+            # strip the trailing ^mapi:
+            # if the redirect string start with something != "^mapi:" or is empty, the redirect is invalid and shall not be included.
+            if m[0..5] == "^mapi:"
+              redir = m[6..m.length]
+              # url parse redir
+              redirects.push(redir)
+            else
+              $stderr.print "Warning: Invalid Redirect #{m}"
+            end
+          end
+
+          if redirects.size == 0
+            raise MonetDBConnectionError, "No valid redirect received"
+          else
+            begin
+              uri = URI.split(redirects[0])
+              # Splits the string on following parts and returns array with result:
+              #
+              #  * Scheme
+              #  * Userinfo
+              #  * Host
+              #  * Port
+              #  * Registry
+              #  * Path
+              #  * Opaque
+              #  * Query
+              #  * Fragment
+              server_name = uri[0]
+              host = uri[2]
+              port = uri[3]
+              database = uri[5].gsub(/^\//, '') if uri[5] != nil
+            rescue URI::InvalidURIError
+              raise MonetDBConnectionError, "Invalid redirect: #{redirects[0]}"
+            end
+          end
+
+          if server_name == MONETDB_MEROVINGIAN
+            if @auth_iteration <= MEROVINGIAN_MAX_ITERATIONS
+              @auth_iteration += 1
+              real_connect
+            else
+              raise MonetDBConnectionError, "Merovingian: too many iterations while proxying."
+            end
+          elsif server_name == MONETDB_MSERVER
+            begin
+              @socket.close
+            rescue
+              raise MonetDBConnectionError, "I/O error while closing connection to #{@socket}"
+            end
+            # reinitialize a connection
+            @host = host
+            @port = port
+
+            connect(database, @auth_type)
+          else
+            @connection_established = false
+            raise MonetDBConnectionError, monetdb_auth
+          end
+        elsif monetdb_auth[0].chr == MSG_INFO
+          raise MonetDBConnectionError, monetdb_auth
+        end
+      end
+    end
+  end
+
+  def savepoint
+    @transactions.savepoint
+  end
+
+  # Formats a <i>command</i> string so that it can be parsed by the server
+  def format_command(x)
+    return "X" + x + "\n"
+  end
+
+  # send an 'export' command to the server
+  def set_export(id, idx, offset)
+    send(format_command("export " + id.to_s + " " + idx.to_s + " " + offset.to_s))
+  end
+
+  # send a 'reply_size' command to the server
+  def set_reply_size
+    send(format_command(("reply_size " + REPLY_SIZE)))
+
+    response = receive
+
+    if response == MSG_PROMPT
+      true
+    elsif response[0] == MSG_INFO
+      raise MonetDBCommandError, "Unable to set reply_size: #{response}"
+    end
+
+  end
+
+  def set_output_seq
+    send(format_command("output seq"))
+  end
+
+  # Disconnect from server
+  def disconnect()
+    if @connection_established
+      begin
+        @socket.close
+      rescue => e
+        $stderr.print e
+      end
+    else
+      raise MonetDBConnectionError, "No connection established."
+    end
+  end
+
+  # send data to a monetdb5 server instance and returns server's response
+  def send(data)
+    encode_message(data).each do |m|
+      @socket.write(m)
+    end
+  end
+
+  # receive data from a monetdb5 server instance
+  def receive
+    is_final, chunk_size = recv_decode_hdr
+
+    if chunk_size == 0
+      return "" # needed on ruby-1.8.6 linux/64bit; recv(0) hangs on this configuration.
+    end
+
+    data = @socket.recv(chunk_size)
+
+    if is_final == false
+      while is_final == false
+        is_final, chunk_size = recv_decode_hdr
+        data += @socket.recv(chunk_size)
+      end
+    end
+
+    return data
+  end
+
+  # Builds and authentication string given the parameters submitted by the user (MAPI protocol v8).
+  # 
+  def build_auth_string_v8(auth_type, salt, db_name)
+    # seed = password + salt
+    if (auth_type.upcase == "MD5" or auth_type.upcase == "SHA1") and @supported_auth_types.include?(auth_type.upcase)
+      auth_type = auth_type.upcase
+      digest = Hasher.new(auth_type, @passwd+salt)
+      hashsum = digest.hashsum
+    elsif auth_type.downcase == "plain" or not @supported_auth_types.include?(auth_type.upcase)
+      auth_type = 'plain'
+      hashsum = @passwd + salt
+
+    elsif auth_type.downcase == "crypt"
+      auth_type = @supported_auth_types[@supported_auth_types.index(auth_type)+1]
+      $stderr.print "The selected hashing algorithm is not supported by the Ruby driver. #{auth_type} will be used instead."
+      digest = Hasher.new(auth_type, @passwd+salt)
+      hashsum = digest.hashsum
+    else
+      # The user selected an auth type not supported by the server.
+      raise MonetDBConnectionError, "#{auth_type} not supported by the server. Please choose one from #{@supported_auth_types}"
+
+    end
+    # Build the reply message with header
+    reply = @client_endianness + ":" + @user + ":{" + auth_type + "}" + hashsum + ":" + @lang + ":" + db_name + ":"
+  end
+
+  #
+  # Builds and authentication string given the parameters submitted by the user (MAPI protocol v9).
+  # 
+  def build_auth_string_v9(auth_type, salt, db_name)
+    if (auth_type.upcase == "MD5" or auth_type.upcase == "SHA1") and @supported_auth_types.include?(auth_type.upcase)
+      auth_type = auth_type.upcase
+      # Hash the password
+      pwhash = Hasher.new(@pwhash, @passwd)
+
+      digest = Hasher.new(auth_type, pwhash.hashsum + salt)
+      hashsum = digest.hashsum
+
+    elsif auth_type.downcase == "plain" # or not  @supported_auth_types.include?(auth_type.upcase)
+      # Keep it for compatibility with merovingian
+      auth_type = 'plain'
+      hashsum = @passwd + salt
+    elsif @supported_auth_types.include?(auth_type.upcase)
+      if auth_type.upcase == "RIPEMD160"
+        auth_type = @supported_auth_types[@supported_auth_types.index(auth_type)+1]
+        $stderr.print "The selected hashing algorithm is not supported by the Ruby driver. #{auth_type} will be used instead."
+      end
+      # Hash the password
+      pwhash = Hasher.new(@pwhash, @passwd)
+
+      digest = Hasher.new(auth_type, pwhash.hashsum + salt)
+      hashsum = digest.hashsum
+    else
+      # The user selected an auth type not supported by the server.
+      raise MonetDBConnectionError, "#{auth_type} not supported by the server. Please choose one from #{@supported_auth_types}"
+    end
+    # Build the reply message with header
+    reply = @client_endianness + ":" + @user + ":{" + auth_type + "}" + hashsum + ":" + @lang + ":" + db_name + ":"
+  end
+
+  # builds a message to be sent to the server
+  def encode_message(msg = "")
+    message = Array.new
+    data = ""
+
+    hdr = 0 # package header
+    pos = 0
+    is_final = false # last package in the stream
+
+    while (!is_final)
+      data = msg[pos..pos+[@@MAX_MESSAGE_SIZE.to_i, (msg.length - pos).to_i].min]
+      pos += data.length
+
+      if (msg.length - pos) == 0
+        last_bit = 1
+        is_final = true
+      else
+        last_bit = 0
+      end
+
+      hdr = [(data.length << 1) | last_bit].pack('v')
+
+      message << hdr + data.to_s # Short Little Endian Encoding  
+    end
+
+    message.freeze # freeze and return the encode message
+  end
+
+  # Used as the first step in the authentication phase; retrives a challenge string from the server.
+  def retrieve_server_challenge()
+    server_challenge = receive
+  end
+
+  # reads and decodes the header of a server message
+  def recv_decode_hdr()
+    if @socket != nil
+      fb = @socket.recv(1)
+      sb = @socket.recv(1)
+
+      # Use execeptions handling to keep compatibility between different ruby
+      # versions.
+      #
+      # Chars are treated differently in ruby 1.8 and 1.9
+      # try do to ascii to int conversion using ord (ruby 1.9)
+      # and if it fail fallback to character.to_i (ruby 1.8)
+      begin
+        fb = fb[0].ord
+        sb = sb[0].ord
+      rescue NoMethodError => one_eight
+        fb = fb[0].to_i
+        sb = sb[0].to_i
+      end
+
+      chunk_size = (sb << 7) | (fb >> 1)
+
+      is_final = false
+      if ((fb & 1) == 1)
+        is_final = true
+
+      end
+      # return the size of the chunk (in bytes)
+      return is_final, chunk_size
+    else
+      raise MonetDBSocketError, "Error while receiving data\n"
+    end
+  end
+
+  # Sets the time zone according to the Operating System settings
+  def set_timezone()
+    tz = Time.new
+    tz_offset = "%+03d:00" % (tz.gmt_offset / @@HOUR)
+
+    query_tz = "sSET TIME ZONE INTERVAL '#{tz_offset}' HOUR TO MINUTE;"
+
+    # Perform the query directly within the method
+    send(query_tz)
+    response = receive()
+
+    if response == MSG_PROMPT
+      true
+    elsif response[0].chr == MSG_INFO
+      raise MonetDBQueryError, response
+    end
+  end
+
+  # Turns auto commit on/off
+  def set_auto_commit(flag=true)
+    if flag == false
+      ac = " 0"
+    else
+      ac = " 1"
+    end
+
+    send(format_command("auto_commit " + ac))
+
+    response = receive
+    if response == MSG_PROMPT
+      @auto_commit = flag
+    elsif response[0].chr == MSG_INFO
+      raise MonetDBCommandError, response
+      return
+    end
+
+  end
+
+  # Check the auto commit status (on/off)
+  def auto_commit?
+    @auto_commit
+  end
+
+  # Check if monetdb is running behind the merovingian proxy and forward the connection in case
+  def merovingian?
+    if @server_name.downcase == MONETDB_MEROVINGIAN
+      true
+    else
+      false
+    end
+  end
+
+  def mserver?
+    if @server_name.downcase == MONETDB_MSERVER
+      true
+    else
+      false
+    end
+  end
+
+  # Check which protocol is spoken by the server
+  def mapi_proto_v8?
+    if @protocol == MAPIv8
+      true
+    else
+      false
+    end
+  end
+
+  def mapi_proto_v9?
+    if @protocol == MAPIv9
+      true
+    else
+      false
+    end
+  end
+end
+
+# handles transactions and savepoints. Can be used to simulate nested transactions.
+class MonetDBTransaction
+  SAVEPOINT_STRING = "monetdbsp"
+
+  def initialize
+    @id = 0
+    @savepoint = ""
+  end
+
+  def savepoint
+    @savepoint = SAVEPOINT_STRING + @id.to_s
+  end
+
+  def release
+    prev_id
+  end
+
+  def save
+    next_id
+  end
+
+  private
+  def next_id
+    @id += 1
+  end
+
+  def prev_id
+    @id -= 1
+  end
+
+end
diff --git a/lib/MonetDBData.rb b/lib/MonetDBData.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7dd8509aca9653976a73c9350167cbf17e6b054c
--- /dev/null
+++ b/lib/MonetDBData.rb
@@ -0,0 +1,420 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+# Models a MonetDB RecordSet
+require 'time'
+require 'ostruct'
+
+require "bigdecimal"
+
+require 'MonetDBConnection'
+
+require 'logger'
+
+class MonetDBData
+  @@DEBUG = false
+  attr_accessor :last_insert_id, :affected_rows
+
+  def initialize(connection)
+    @connection = connection
+    @lang = @connection.lang
+
+    # Structure containing the header+results set for a fired Q_TABLE query     
+    @header = []
+    @query = {}
+
+    @record_set = []
+    @index = 0 # Position of the last returned record
+
+    @row_count = 0
+    @row_offset = 10
+    @row_index = Integer(REPLY_SIZE)
+  end
+
+  # Fire a query and return the server response
+  def execute(q)
+    # fire a query and get ready to receive the data
+    @connection.send(format_query(q))
+    data = @connection.receive
+
+    return if data == nil
+
+    # temporarly store retrieved rows
+    record_set = receive_record_set(data)
+
+    if (@lang == LANG_SQL)
+      # the fired query is a SELECT; store and return the whole record set
+      if @action == Q_TABLE
+        @header = parse_header_table(@header)
+        @header.freeze
+
+        if @row_index.to_i < @row_count.to_i
+          block_rows = ""
+          while next_block
+            data = @connection.receive
+            block_rows += receive_record_set(data)
+          end
+          record_set += block_rows
+        end
+      end
+
+      # ruby string management seems to not properly understand the MSG_PROMPT escape character.
+      # In order to avoid data loss the @record_set array is built once that all tuples have been retrieved
+      @record_set = record_set.split("\t]\n")
+
+      if @record_set.length != @query['rows'].to_i
+        raise MonetDBQueryError, "Warning: Query #{@query['id']} declared to result in #{@query['rows']} but #{@record_set.length} returned instead"
+      end
+    end
+    @record_set.freeze
+  end
+
+  # Free memory used to store the record set
+  def free()
+    @connection = nil
+
+    @header = []
+    @query = {}
+
+    @record_set = []
+    @index = 0 # Position of the last returned record
+
+
+    @row_index = Integer(REPLY_SIZE)
+    @row_count = 0
+    @row_offset = 10
+
+  end
+
+  # Returns the record set entries hashed by column name orderd by column position
+  def fetch_all_hash()
+    columns = {}
+    @header["columns_name"].each do |col_name|
+      columns[col_name] = fetch_column_name(col_name)
+    end
+
+    return columns
+  end
+
+  def fetch_hash()
+    if @index >= @query['rows'].to_i
+      return false
+    else
+      columns = {}
+      @header["columns_name"].each do |col_name|
+        position = @header["columns_order"].fetch(col_name)
+        row = parse_tuple(@record_set[@index])
+        columns[col_name] = row[position]
+      end
+      @index += 1
+      return columns
+    end
+  end
+
+  # Returns the values for the column 'field'
+  def fetch_column_name(field="")
+    position = @header["columns_order"].fetch(field)
+
+    col = Array.new
+    # Scan the record set by row
+    @record_set.each do |row|
+      col << parse_tuple(row)[position]
+    end
+
+    return col
+  end
+
+  # returns result as an array of hashes
+  def result_hashes
+    result = []
+    @record_set.each do |row|
+      rec = parse_tuple(row)
+      hash = {}
+      @header['columns_name'].each_with_index do |item, i|
+        hash[item] = rec[i]
+        hash[item] = nil if hash[item] == 'NULL'
+      end
+      result << hash
+    end
+    result
+  end
+
+  def fetch()
+    @index
+    if @index > @query['rows'].to_i
+      false
+    else
+      parse_tuple(@record_set[@index])
+      @index += 1
+    end
+  end
+
+  # Cursor method that retrieves all the records present in a table and stores them in a cache.
+  def fetch_all()
+    if @query['type'] == Q_TABLE
+      rows = Array.new
+      @record_set.each do |row|
+        rows << parse_tuple(row)
+      end
+      @index = Integer(rows.length)
+    else
+      raise MonetDBDataError, "There is no record set currently available"
+    end
+
+    return rows
+  end
+
+  # Returns the number of rows in the record set
+  def num_rows()
+    return @query['rows'].to_i
+  end
+
+  # Returns the number of fields in the record set
+  def num_fields()
+    return @query['columns'].to_i
+  end
+
+  # Returns the (ordered) name of the columns in the record set
+  def name_fields()
+    return @header['columns_name']
+  end
+
+  # Returns the (ordered) name of the columns in the record set
+  def type_fields
+    return @header['columns_type']
+  end
+
+  private
+
+  # store block of data, parse it and store it.
+  def receive_record_set(response)
+    rows = ""
+    lines = response.lines.to_a
+    response.each_line do |row|
+      if row[0].chr == MSG_QUERY
+        if row[1].chr == Q_TABLE
+          @action = Q_TABLE
+          @query = parse_header_query(row)
+          @query.freeze
+          @row_count = @query['rows'].to_i #total number of rows in table            
+        elsif row[1].chr == Q_BLOCK
+          # strip the block header from data
+          @action = Q_BLOCK
+          @block = parse_header_query(row)
+        elsif row[1].chr == Q_TRANSACTION
+          @action = Q_TRANSACTION
+        elsif row[1].chr == Q_CREATE
+          @action = Q_CREATE
+        elsif row[1].chr == Q_UPDATE
+          @action = Q_UPDATE
+          result = row.split(' ')
+          @affected_rows = result[1].to_i
+          @last_insert_id = result[2].to_i
+        end
+      elsif row[0].chr == MSG_INFO
+        raise MonetDBQueryError, row
+      elsif row[0].chr == MSG_SCHEMA_HEADER
+        # process header data
+        @header << row
+      elsif row[0].chr == MSG_TUPLE
+        if REPLY_SIZE.to_i == -1
+          # if all results are returned in this response, we don't have to look ahead further
+          return lines.join
+        end
+        rows += row
+      elsif row[0] == MSG_PROMPT
+        return rows
+      end
+      lines.shift
+    end
+    rows # return an array of unparsed tuples
+  end
+
+  def next_block
+    if REPLY_SIZE.to_i == -1 or @row_index == @row_count
+      return false
+    else
+      # The increment step is small to better deal with ruby socket's performance.
+      # For larger values of the step performance drop;
+      #
+      @row_offset = [@row_offset, (@row_count - @row_index)].min
+
+      # export offset amount
+      @connection.set_export(@query['id'], @row_index.to_s, @row_offset.to_s)
+      @row_index += @row_offset
+      @row_offset += 1
+    end
+    return true
+  end
+
+  # Formats a query <i>string</i> so that it can be parsed by the server
+  def format_query(q)
+    if @lang == LANG_SQL
+      return "s" + q + ";"
+    else
+      raise LanguageNotSupported, @lang
+    end
+  end
+
+  # parse one tuple as returned from the server
+  def parse_tuple(tuple)
+    fields = Array.new
+    # remove trailing  "["
+    tuple = tuple.to_s.gsub(/^\[\s+/, '')
+
+    tuple.split(/,\t/).each do |f|
+      fields << f.gsub(/\\n/, "\n").gsub(/\\/, '').gsub(/^"/, '').gsub(/"$/, '').gsub(/\"/, '')
+    end
+
+    return fields.freeze
+  end
+
+  # Parses a query header and returns information about the query.
+  def parse_header_query(row)
+    type = row[1].chr
+    if type == Q_TABLE
+      # Performing a SELECT: store informations about the table size, query id, total number of records and returned.
+      id = row.split(' ')[1]
+      rows = row.split(' ')[2]
+      columns = row.split(' ')[3]
+      returned = row.split(' ')[4]
+
+      header = {"id" => id, "type" => type, "rows" => rows, "columns" => columns, "returned" => returned}
+    elsif type == Q_BLOCK
+      # processing block header
+
+      id = row.split(' ')[1]
+      columns = row.split(' ')[2]
+      remains = row.split(' ')[3]
+      offset = row.split(' ')[4]
+
+      header = {"id" => id, "type" => type, "remains" => remains, "columns" => columns, "offset" => offset}
+    else
+      header = {"type" => type}
+    end
+
+    return header.freeze
+  end
+
+  # Parses a Q_TABLE header and returns information about the schema.
+  def parse_header_table(header_t)
+    if @query["type"] == Q_TABLE
+      if header_t != nil
+        name_t = header_t[0].split(' ')[1].gsub(/,$/, '')
+        name_cols = Array.new
+
+        header_t[1].split('%')[1].gsub(/'^\%'/, '').split('#')[0].split(' ').each do |col|
+          name_cols << col.gsub(/,$/, '')
+        end
+
+        type_cols = {}
+        header_t[2].split('%')[1].gsub(/'^\%'/, '').split('#')[0].split(' ').each_with_index do |col, i|
+          if col.gsub(/,$/, '') != nil
+            type_cols[name_cols[i]] = col.gsub(/,$/, '')
+          end
+        end
+
+        length_cols = {}
+        header_t[3].split('%')[1].gsub(/'^\%'/, '').split('#')[0].split(' ').each_with_index do |col, i|
+          length_cols[name_cols[i]] = col.gsub(/,$/, '')
+        end
+
+        columns_order = {}
+        name_cols.each_with_index do |col, i|
+          columns_order[col] = i
+        end
+
+        return {"table_name" => name_t, "columns_name" => name_cols, "columns_type" => type_cols,
+                "columns_length" => length_cols, "columns_order" => columns_order}.freeze
+      end
+    end
+  end
+end
+
+# Overload the class string to convert monetdb to ruby types.
+class String
+  def getInt
+    self.to_i
+  end
+
+  def getFloat
+    self.to_f
+  end
+
+  def getString
+    self.gsub(/^"/, '').gsub(/"$/, '')
+  end
+
+  def getBlob
+    # first strip trailing and leading " characters 
+    self.gsub(/^"/, '').gsub(/"$/, '')
+
+    # convert from HEX to the origianl binary data.
+    blob = ""
+    self.scan(/../) { |tuple| blob += tuple.hex.chr }
+    return blob
+  end
+
+  # ruby currently supports only time + date frommatted timestamps;
+  # treat TIME and DATE as strings.
+  def getTime
+    # HH:MM:SS
+    self.gsub(/^"/, '').gsub(/"$/, '')
+  end
+
+  def getDate
+    self.gsub(/^"/, '').gsub(/"$/, '')
+  end
+
+  def getDateTime
+    #YYYY-MM-DD HH:MM:SS
+    date = self.split(' ')[0].split('-')
+    time = self.split(' ')[1].split(':')
+
+    Time.gm(date[0], date[1], date[2], time[0], time[1], time[2])
+  end
+
+  def getChar
+    # ruby < 1.9 does not have a Char datatype
+    begin
+      c = self.ord
+    rescue
+      c = self
+    end
+
+    return c
+  end
+
+  def getBool
+    if ['1', 'y', 't', 'true'].include?(self)
+      return true
+    elsif ['0', 'n', 'f', 'false'].include?(self)
+      return false
+    else
+      # unknown
+      return nil
+    end
+  end
+
+  def getNull
+    if self.upcase == 'NONE'
+      return nil
+    else
+      raise "Unknown value"
+    end
+  end
+end
diff --git a/lib/MonetDBExceptions.rb b/lib/MonetDBExceptions.rb
new file mode 100644
index 0000000000000000000000000000000000000000..75745b5144ff680da4a20d97c6fbcaa969efbb40
--- /dev/null
+++ b/lib/MonetDBExceptions.rb
@@ -0,0 +1,25 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+# Exception classes for the ruby-monetdb driver
+
+class MonetDBQueryError < StandardError; end
+class MonetDBDataError < StandardError; end
+class MonetDBCommandError < StandardError; end
+class MonetDBConnectionError < StandardError; end
+class MonetDBSocketError < StandardError; end
+class MonetDBProtocolError < StandardError; end
\ No newline at end of file
diff --git a/lib/demo.rb b/lib/demo.rb
new file mode 100644
index 0000000000000000000000000000000000000000..94fd640a26e980f577b666bf14fc148637e8d5cd
--- /dev/null
+++ b/lib/demo.rb
@@ -0,0 +1,101 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+require 'MonetDB'
+
+db = MonetDB.new
+
+db.conn({ :user => "monetdb", :passwd => "monetdb", :port => 50000, :language => "sql", :host => "localhost", :database => "ruby_test", :auth_type => "SHA1" })
+
+# set type_cast=true to enable MonetDB to Ruby type mapping
+#res = db.query("select * from tables, tables, tables;")
+
+#db.query("DROP TABLE tests2 ")
+#db.query(" CREATE TABLE tests2 ( col1  varchar(255), col2 varchar(255)) " )
+
+#puts "Number of rows returned: " + res.num_rows.to_s
+#puts "Number of fields: " + res.num_fields.to_s
+
+# Get the columns' name
+# print res.name_fields
+
+###### Fetch all rows and store them
+
+#puts res.fetch_all
+
+
+# Iterate over the record set and retrieve on row at a time
+#puts res.fetch
+#while row = res.fetch do
+#  printf "%s \n", row
+#end
+
+
+###### Get all records and hash them by column name
+#row = res.fetch_all_hash()
+
+#puts col_names[0] + "\t\t" + col_names[1]
+#0.upto(res.num_rows) { |i|
+#  puts row['id'][i]
+#}
+
+
+###### Iterator over columns (on cell at a time)
+
+#while row = res.fetch_hash do
+#  printf "%s\n",  row["id"]
+#end
+
+# SQL TRANSACTIONS and SAVE POINTS
+
+
+
+db.query('DROP TABLE tests2')
+db.auto_commit(false)
+puts db.auto_commit?
+# create a savepoint
+db.save
+db.query("CREATE TABLE tests2 (col1 VARCHAR(255), col2 VARCHAR(255))")
+res = db.query("SAVEPOINT #{db.transactions} ;")
+res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+#res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+#res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+#res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+#res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+#res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+#res = db.query("INSERT INTO \"tests2\" VALUES ('€¿®µ¶¹', '€¿®µ¶¹')")
+db.query("COMMIT")
+db.release
+
+db.save
+res = db.query("SAVEPOINT #{db.transactions} ;")
+res = db.query("INSERT INTO \"tests2\" VALUES('NAME4', 'SURNAME4')")
+
+res = db.query("ROLLBACK TO SAVEPOINT #{db.transactions};")
+db.release
+
+db.auto_commit(true)
+puts db.auto_commit?
+res = db.query('SELECT * from tests2')
+while row = res.fetch do
+  printf "%s \n", row
+end
+
+res.free
+
+db.close
diff --git a/lib/hasher.rb b/lib/hasher.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2501266dc54e34bdc0f5bee433b8f821a675f7db
--- /dev/null
+++ b/lib/hasher.rb
@@ -0,0 +1,56 @@
+# The contents of this file are subject to the MonetDB Public License
+# Version 1.1 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://monetdb.cwi.nl/Legal/MonetDBLicense-1.1.html
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the MonetDB Database System.
+#
+# The Initial Developer of the Original Code is CWI.
+# Portions created by CWI are Copyright (C) 1997-July 2008 CWI.
+# Copyright August 2008-2011 MonetDB B.V.
+# All Rights Reserved.
+
+require 'digest/md5'
+require 'digest/sha1'
+require 'digest/sha2' 
+
+class Hasher
+	# Constructor
+	# method = "SHA1" or "MD5"
+	# pwd = Password
+	def initialize(method, pwd)
+          if (method.upcase == "SHA1")
+                  @hashfunc = Digest::SHA1.new
+                  @hashname = method.upcase
+          elsif (method.upcase == "SHA256") 
+            @hashfunc = Digest::SHA256.new
+            @hashname = method.upcase
+          elsif (method.upcase == "SHA384")
+            @hashfunc = Digest::SHA384.new
+            @hashname = method.upcase
+          elsif (method.upcase == "SHA512")
+            @hashfunc = Digest::SHA512.new
+            @hashname = method.upcase
+          else
+            # default to MD5
+                  @hashfunc = Digest::MD5.new
+                  @hashname = "MD5"
+          end
+          @pwd = pwd
+  end
+  
+
+	def hashname
+		@hashname
+	end
+
+	# Compute hash code
+	def hashsum
+		return @hashfunc.hexdigest(@pwd)
+	end
+end
diff --git a/lib/test/test_capabilities.rb b/lib/test/test_capabilities.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fc2146b2d715795ca9fed5be7d081c1b7b38df90
--- /dev/null
+++ b/lib/test/test_capabilities.rb
@@ -0,0 +1,310 @@
+# unit test suite for monetdb.
+# connects to the 'ruby_test' database and runs test on the server capabilities and SQL language.
+# Create first a database with the command:
+# $ monetdb create ruby_test
+# $ monetdb start ruby_start
+#
+# Tests examples have been taken from the python and java internfaces and mysql driver.
+
+require 'MonetDB'
+require 'test/unit'
+
+require 'time'
+require 'date'
+
+
+class TC_MonetDBCapabilities < Test::Unit::TestCase
+  # ruby rand function does not support MIN..MAX bounds.
+  # This alias adds that feature.
+  alias original_rand rand
+  def rand(arg1=nil, arg2=nil) 
+    if !arg1.kind_of?(Enumerable) && arg2 == nil 
+      original_rand(arg1)
+    elsif arg1.kind_of? Enumerable
+      as_array = arg1.to_a
+      as_array[original_rand(as_array.length)]
+    elsif arg1 != nil
+      arg1 + original_rand(arg2)
+    end
+  end
+  
+  # check the existance of a table
+  def table_exists?(table='test_ruby')    
+    begin
+      res = @db.query("select * from #{table} where 1=0")
+      return true
+    rescue
+      return false
+    end
+  end
+  
+  def drop_table(table='test_ruby')
+    res = @db.query("DROP TABLE #{table}")
+  end
+  
+  def setup
+    @db = MonetDB.new
+    @db.connect(user = "monetdb", passwd = "monetdb", lang = "sql", host="localhost", port = 50000, db_name = "ruby_test", auth_type = "SHA1")
+    
+  end
+
+  def teardown
+    @db.close
+  end
+  
+  # CREATE TABLE test
+  def test_create_table(table='test_ruby', cols = [ "First_Name varchar(255)", "Second_Name varchar(255)"])
+    
+    if table_exists?(table)
+      drop_table(table)
+    end
+    
+    colsdef =  ""
+    cols.each do |c| colsdef += c + ',' end
+      
+    colsdef = colsdef.chop # remove last ',' character
+    
+    
+    res = @db.query('CREATE TABLE ' + table + ' (' + colsdef + ')') 
+  end
+  
+  
+  # perform an inserstion of 'data' into 'table' and check the resulting 
+  # length
+  def test_data_integrity(table='test_ruby', data=["Gabriele", "MODENA"])
+    test_create_table
+        
+    values = ""
+    data.each do |d| values += '\'' + d.to_s + '\'' + ',' end
+    values = values.chop # remove last ',' character
+    
+    insert = 'INSERT INTO ' + table +  ' VALUES ('  + values + ' )' 
+    
+    @db.query(insert)
+    
+    res = @db.query("SELECT * FROM #{table}")
+    rows = res.fetch_all
+    
+    assert_equal(res.num_rows, rows.size)
+  end
+  
+  # test TRANSACTION, COMMIT, ROLLBACK and SAVEPOINT in auto_commit=off mode
+  def test_transactions(table="test_monetdb_transactions",  columndefs=['col1 INT', 'col2 VARCHAR(255)'])
+    test_create_table(table, columndefs)
+     
+    data = [1, 'aa'] 
+    values = ""
+     
+    data.each do |d| values += '\'' + d.to_s + '\'' + ',' end
+    values = values.chop # remove last ',' character 
+     
+    insert = "INSERT INTO " + table + " VALUES " + " ( " + values +  " )"
+     
+    @db.query('START TRANSACTION')
+    @db.auto_commit(flag=false) # if @db.auto_commit?
+    @db.query(insert)
+
+    @db.query("COMMIT")     
+     
+    res = @db.query('SELECT * FROM ' + table)
+    rows_committed = res.fetch_all
+    res.free
+     
+    # create a save point
+    @db.save
+    @db.query("SAVEPOINT #{@db.transactions} ;")
+     
+    @db.query(insert)
+     
+    # rollback to savepoint
+    @db.query("ROLLBACK TO SAVEPOINT #{@db.transactions};")
+    @db.release
+     
+    res = @db.query('SELECT * FROM ' + table)
+    rows_rolled_back = res.fetch_all
+    res.free
+          
+    assert_equal(rows_committed, rows_rolled_back)
+    
+    # restore autocommit for remaining tests
+    @db.auto_commit(flag=true)    
+  end
+  
+  # tests on datatypes conversion
+  def test_char(table="test_monetdb_char", coldefs=["char_field CHAR(1)"])
+      test_create_table(table, coldefs)
+      char = 'a'
+
+      @db.query("INSERT INTO " + table  + " VALUES ( '" + char  +"' ) ")
+
+      res = @db.query("SELECT char_field FROM " + table + " where char_field = '" + char +"'")
+      stored_string = res.fetch_hash
+            
+      assert_equal(char, stored_string['char_field'])      
+  end
+  
+  def test_smallint(table="test_monetdb_smallint", coldefs=["int_field SMALLINT"])   
+      test_create_table(table, coldefs)
+       
+      original_num = rand(-32768, 32767)
+      num = original_num.to_s
+            
+      @db.query("INSERT INTO " + table  + " VALUES ('" + num  +"') ")
+
+      res = @db.query("SELECT int_field FROM " + table + " where int_field = '" + num +"'")
+
+      stored_string = res.fetch_hash
+      
+      assert_equal(num.to_i, stored_string['int_field'].getInt)      
+  end
+ 
+  def test_int(table="test_monetdb_int", coldefs=["int_field INT"])
+      test_create_table(table, coldefs)
+      
+      original_num = rand((2 ** 31 -1))
+      num = original_num.to_s
+
+      @db.query("INSERT INTO " + table  + " VALUES ('" + num  +"') ")
+
+      res = @db.query("SELECT int_field FROM " + table + " where int_field = '" + num +"'")
+
+      stored_string = res.fetch_hash
+      
+      assert_equal(original_num, stored_string['int_field'].getInt)      
+  end
+
+  def test_bigint(table="test_monetdb_bigint", coldefs=["int_field BIGINT"])
+      test_create_table(table, coldefs)
+      
+      original_num = rand((2 ** 63 -1))
+      num = original_num.to_s
+     
+      @db.query("INSERT INTO " + table  + " VALUES ('" + num  +"') ")
+
+      res = @db.query("SELECT int_field FROM " + table + " where int_field = '" + num +"'")
+
+      stored_string = res.fetch_hash
+
+      assert_equal(original_num, stored_string['int_field'].getInt)      
+   end
+
+   def test_real(table="test_monetdb_real", coldefs=["float_field REAL"])
+     test_create_table(table, coldefs)
+     
+     original_num = 1.6065851e+20    
+     num = original_num.to_s
+
+     @db.query("INSERT INTO " + table  + " VALUES ('" + num  +"') ")
+
+     res = @db.query("SELECT float_field FROM " + table + " where float_field = '" + num +"'")
+
+     stored_string = res.fetch_hash
+
+     assert_equal(original_num, stored_string['float_field'].getFloat)       
+   end
+
+   def test_double(table="test_monetdb_double", coldefs=["float_field DOUBLE"])
+     test_create_table(table, coldefs)
+     
+     original_num = 1.6065851e+22     
+     num = original_num.to_s
+
+     @db.query("INSERT INTO " + table  + " VALUES ('" + num  +"') ")
+
+     res = @db.query("SELECT float_field FROM " + table + " where float_field = '" + num +"'")
+
+     stored_string = res.fetch_hash
+
+     assert_equal(original_num, stored_string['float_field'].getFloat)       
+   end
+
+   def test_boolean(table="test_monetdb_boolean", coldefs=["bool_field BOOLEAN"] )
+     test_create_table(table, coldefs)
+     
+     original_bool = false
+     bool = original_bool.to_s
+          
+     @db.query("INSERT INTO " + table  + " VALUES ('" + bool  +"') ")
+
+     res = @db.query("SELECT bool_field FROM " + table + " where bool_field = #{bool}")
+     stored_string = res.fetch_hash
+     assert_equal(original_bool, stored_string['bool_field'].getBool)     
+   end
+   
+   def test_datetime(table="test_monetdb_datetime", coldefs=["dt_field TIMESTAMP"])
+     test_create_table(table, coldefs)
+     
+     timestamp = "2009-07-01 15:34:33"
+     
+     date = timestamp.split(' ')[0].split('-')
+     time = timestamp.split(' ')[1].split(':')
+
+     dt = Time.gm(date[0], date[1], date[2], time[0], time[1], time[2])     
+     
+     @db.query("INSERT INTO " + table  + " VALUES ('" + timestamp  +"') ")
+
+     res = @db.query("SELECT dt_field FROM " + table + " where dt_field = '" + timestamp +"'")
+     stored_string = res.fetch_hash
+     assert_equal(dt, stored_string['dt_field'].getDateTime)      
+   end
+   
+   def test_date(table="test_monetdb_date", coldefs=["dt_field DATE"])
+     test_create_table(table, coldefs)
+     
+     timestamp = "2009-07-01"
+    
+     @db.query("INSERT INTO " + table  + " VALUES ('" + timestamp  +"') ")
+
+     res = @db.query("SELECT dt_field FROM " + table + " where dt_field = '" + timestamp +"'")
+     stored_string = res.fetch_hash
+     assert_equal(timestamp, stored_string['dt_field'].getDate)          
+   end
+    
+   def test_time(table="test_monetdb_time", coldefs=["dt_field TIME"])
+     test_create_table(table, coldefs)
+     
+     timestamp = "15:34:33"
+     
+     @db.query("INSERT INTO " + table  + " VALUES ('" + timestamp  +"') ")
+
+     res = @db.query("SELECT dt_field FROM " + table + " where dt_field = '" + timestamp +"'")
+     stored_string = res.fetch_hash
+     assert_equal(timestamp, stored_string['dt_field'].getTime)     
+   end
+   
+  def test_blob(table="test_monetdb_blob",  coldefs = ["blob_field BLOB"])
+    test_create_table(table, coldefs) 
+    
+    blob = '0000000A146F777BB46B8FBD46AD503A54629C51'
+
+    @db.query("INSERT INTO " + table  + " VALUES ('" + blob + "') ")
+     
+    res = @db.query("SELECT blob_field FROM " + table + " where blob_field = '#{blob}'")
+
+    stored_string = res.fetch_hash
+    assert_equal(blob, stored_string['blob_field'])    
+  end 
+   
+  def test_utf8(table="test_monetdb_utf8", coldefs=["utf8_field varchar(100000)"])
+    test_create_table(table, coldefs)
+    
+    utf8_string = "€¿®µ¶¹€¿®µ¶¹€¿®µ¶¹"
+    
+    @db.query("INSERT INTO " + table  + " VALUES ( '#{utf8_string}' ) ")
+        
+    res = @db.query("SELECT utf8_field FROM #{table} where utf8_field = '#{utf8_string}' ")
+    stored_string = res.fetch_hash
+  
+    assert_equal(utf8_string, stored_string['utf8_field'])    
+  end   
+  
+  # test MonetDB::conn() named parameters connection method.
+  def test_conn_with_named_parameters    
+    db = MonetDB.new()
+        
+    db.conn({ :user => "monetdb", :passwd => "monetdb", :port => 50000, :host => "localhost", :database => "ruby_test"})
+    assert_equal(true, db.is_connected?)
+    db.close
+  end
+  
+end
diff --git a/ruby-monetdb-sql-0.1.gemspec b/ruby-monetdb-sql-0.1.gemspec
new file mode 100644
index 0000000000000000000000000000000000000000..e773f0738fc2abb00c259f2a18acc5a9534ab703
--- /dev/null
+++ b/ruby-monetdb-sql-0.1.gemspec
@@ -0,0 +1,17 @@
+
+Gem::Specification.new do |s|
+   s.required_ruby_version = '>= 2.1.0'
+   s.name = %q{ruby-monetdb-sql}
+   s.version = "0.2"
+   s.date = %q{2009-04-27}
+   s.authors = ["G Modena"]
+   s.email = %q{gm@cwi.nl}
+   s.summary = %q{Pure Ruby database driver for MonetDB/SQL}
+   s.homepage = %q{http://monetdb.cwi.nl/}
+   s.description = %q{Pure Ruby database driver for the MonetDB/SQL columnar database management system}
+   s.files = ["README", "lib/MonetDB.rb", "lib/MonetDBConnection.rb", "lib/MonetDBData.rb", "lib/MonetDBExceptions.rb", "lib/hasher.rb"]
+   s.has_rdoc = true
+   s.require_path = './lib'
+   # placeholder project to avoid warning about not having a rubyforge_project
+   s.rubyforge_project = "nowarning"
+end