1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Multiple enhancements and adjustments to DB2 adaptor. Closes #3377.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3380 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Marcel Molina 2006-01-04 04:17:23 +00:00
parent bbec3ae512
commit a5708b4c1f
7 changed files with 207 additions and 169 deletions

View file

@ -1,5 +1,7 @@
*SVN* *SVN*
* Multiple enhancements and adjustments to DB2 adaptor. #3377 [contact@maik-schmidt.de]
* Sanitize scoped conditions. [Marcel Molina Jr.] * Sanitize scoped conditions. [Marcel Molina Jr.]
* Added option to Base.reflection_of_all_associations to specify a specific association to scope the call. For example Base.reflection_of_all_associations(:has_many) [DHH] * Added option to Base.reflection_of_all_associations to specify a specific association to scope the call. For example Base.reflection_of_all_associations(:has_many) [DHH]

View file

@ -14,16 +14,17 @@ begin
config = config.symbolize_keys config = config.symbolize_keys
usr = config[:username] usr = config[:username]
pwd = config[:password] pwd = config[:password]
schema = config[:schema]
if config.has_key?(:database) if config.has_key?(:database)
database = config[:database] database = config[:database]
else else
raise ArgumentError, "No database specified. Missing argument: database." raise ArgumentError, 'No database specified. Missing argument: database.'
end end
connection = DB2::Connection.new(DB2::Environment.new) connection = DB2::Connection.new(DB2::Environment.new)
connection.connect(database, usr, pwd) connection.connect(database, usr, pwd)
ConnectionAdapters::DB2Adapter.new(connection) ConnectionAdapters::DB2Adapter.new(connection, logger, :schema => schema)
end end
end end
@ -35,7 +36,18 @@ begin
# * <tt>:username</tt> -- Defaults to nothing # * <tt>:username</tt> -- Defaults to nothing
# * <tt>:password</tt> -- Defaults to nothing # * <tt>:password</tt> -- Defaults to nothing
# * <tt>:database</tt> -- The name of the database. No default, must be provided. # * <tt>:database</tt> -- The name of the database. No default, must be provided.
# * <tt>:schema</tt> -- Database schema to be set initially.
class DB2Adapter < AbstractAdapter class DB2Adapter < AbstractAdapter
def initialize(connection, logger, connection_options)
super(connection, logger)
@connection_options = connection_options
if schema = @connection_options[:schema]
with_statement do |stmt|
stmt.exec_direct("SET SCHEMA=#{schema}")
end
end
end
def select_all(sql, name = nil) def select_all(sql, name = nil)
select(sql, name) select(sql, name)
end end
@ -51,14 +63,12 @@ begin
def execute(sql, name = nil) def execute(sql, name = nil)
rows_affected = 0 rows_affected = 0
with_statement do |stmt|
log(sql, name) do log(sql, name) do
stmt = DB2::Statement.new(@connection)
stmt.exec_direct(sql) stmt.exec_direct(sql)
rows_affected = stmt.row_count rows_affected = stmt.row_count
stmt.free
end end
end
rows_affected rows_affected
end end
@ -92,39 +102,44 @@ begin
end end
def add_limit_offset!(sql, options) def add_limit_offset!(sql, options)
if options[:limit] and !options[:limit].nil? if limit = options[:limit]
# "FETCH FIRST 0 ROWS ONLY" is not allowed, so we have offset = options[:offset] || 0
# to use a cheap trick. # The following trick was added by andrea+rails@webcom.it.
if options[:limit] == 0 sql.gsub!(/SELECT/i, 'SELECT B.* FROM (SELECT A.*, row_number() over () AS internal$rownum FROM (SELECT')
if sql =~ /WHERE/i sql << ") A ) B WHERE B.internal$rownum > #{offset} AND B.internal$rownum <= #{limit + offset}"
sql.sub!(/WHERE/i, 'WHERE 1 = 2 AND ')
elsif
sql =~ /ORDER\s+BY/i
sql.sub!(/ORDER\s+BY/i, 'WHERE 1 = 2 ORDER BY')
else
sql << 'WHERE 1 = 2'
end
else
sql << " FETCH FIRST #{options[:limit]} ROWS ONLY"
end
end
if options[:offset] and !options[:offset].nil?
raise ArgumentError, ':offset option is not yet supported!'
end end
end end
def tables(name = nil) def tables(name = nil)
stmt = DB2::Statement.new(@connection)
result = [] result = []
with_statement do |stmt|
stmt.tables.each { |t| result << t[2].downcase } stmt.tables.each { |t| result << t[2].downcase }
stmt.free end
result result
end end
def columns(table_name, name = nil) def indexes(table_name, name = nil)
stmt = DB2::Statement.new(@connection) tmp = {}
result = [] with_statement do |stmt|
stmt.indexes(table_name.upcase).each do |t|
next unless t[5]
next if t[4] == 'SYSIBM' # Skip system indexes.
idx_name = t[5].downcase
col_name = t[8].downcase
if tmp.has_key?(idx_name)
tmp[idx_name].columns << col_name
else
is_unique = t[3] == 0
tmp[idx_name] = IndexDefinition.new(table_name, idx_name, is_unique, [col_name])
end
end
end
tmp.values
end
def columns(table_name, name = nil)
result = []
with_statement do |stmt|
stmt.columns(table_name.upcase).each do |c| stmt.columns(table_name.upcase).each do |c|
c_name = c[3].downcase c_name = c[3].downcase
c_default = c[12] == 'NULL' ? nil : c[12] c_default = c[12] == 'NULL' ? nil : c[12]
@ -132,24 +147,23 @@ begin
c_type += "(#{c[6]})" if !c[6].nil? && c[6] != '' c_type += "(#{c[6]})" if !c[6].nil? && c[6] != ''
result << Column.new(c_name, c_default, c_type) result << Column.new(c_name, c_default, c_type)
end end
end
stmt.free
result result
end end
def native_database_types def native_database_types
{ {
:primary_key => "int generated by default as identity primary key", :primary_key => 'int generated by default as identity primary key',
:string => { :name => "varchar", :limit => 255 }, :string => { :name => 'varchar', :limit => 255 },
:text => { :name => "clob", :limit => 32768 }, :text => { :name => 'clob', :limit => 32768 },
:integer => { :name => "int" }, :integer => { :name => 'int' },
:float => { :name => "float" }, :float => { :name => 'float' },
:datetime => { :name => "timestamp" }, :datetime => { :name => 'timestamp' },
:timestamp => { :name => "timestamp" }, :timestamp => { :name => 'timestamp' },
:time => { :name => "time" }, :time => { :name => 'time' },
:date => { :name => "date" }, :date => { :name => 'date' },
:binary => { :name => "blob", :limit => 32768 }, :binary => { :name => 'blob', :limit => 32768 },
:boolean => { :name => "decimal", :limit => 1 } :boolean => { :name => 'decimal', :limit => 1 }
} }
end end
@ -161,8 +175,24 @@ begin
'0' '0'
end end
def active?
@connection.select_one 'select 1 from ibm.sysdummy1'
true
rescue Exception
false
end
def reconnect!
end
private private
def with_statement
stmt = DB2::Statement.new(@connection)
yield stmt
stmt.free
end
def last_insert_id def last_insert_id
row = select_one(<<-GETID.strip) row = select_one(<<-GETID.strip)
with temp(id) as (values (identity_val_local())) select * from temp with temp(id) as (values (identity_val_local())) select * from temp
@ -171,17 +201,17 @@ begin
end end
def select(sql, name = nil) def select(sql, name = nil)
stmt = nil rows = []
with_statement do |stmt|
log(sql, name) do log(sql, name) do
stmt = DB2::Statement.new(@connection)
stmt.exec_direct("#{sql.gsub(/=\s*null/i, 'IS NULL')} with ur") stmt.exec_direct("#{sql.gsub(/=\s*null/i, 'IS NULL')} with ur")
end end
rows = []
while row = stmt.fetch_as_hash while row = stmt.fetch_as_hash
row.delete('internal$rownum')
rows << row rows << row
end end
stmt.free end
rows rows
end end
end end

View file

@ -110,13 +110,18 @@ module DB2
check_rc(rc) check_rc(rc)
end end
def columns(table_name) def columns(table_name, schema_name = '%')
check_rc(SQLColumns(@handle, "", "%", table_name, "%")) check_rc(SQLColumns(@handle, '', schema_name, table_name, '%'))
fetch_all fetch_all
end end
def tables def tables
check_rc(SQLTables(@handle, "", "%", "%", "TABLE")) check_rc(SQLTables(@handle, '', '%', '%', 'TABLE'))
fetch_all
end
def indexes(table_name)
check_rc(SQLStatistics(@handle, '', '', table_name, SQL_INDEX_ALL, SQL_ENSURE))
fetch_all fetch_all
end end

View file

@ -19,13 +19,14 @@ class AdapterTest < Test::Unit::TestCase
def test_indexes def test_indexes
if @connection.respond_to?(:indexes) if @connection.respond_to?(:indexes)
idx_name = "accounts_idx"
indexes = @connection.indexes("accounts") indexes = @connection.indexes("accounts")
assert indexes.empty? assert indexes.empty?
@connection.add_index :accounts, :firm_id @connection.add_index :accounts, :firm_id, :name => idx_name
indexes = @connection.indexes("accounts") indexes = @connection.indexes("accounts")
assert_equal "accounts", indexes.first.table assert_equal "accounts", indexes.first.table
assert_equal "accounts_firm_id_index", indexes.first.name assert_equal idx_name, indexes.first.name
assert !indexes.first.unique assert !indexes.first.unique
assert_equal ["firm_id"], indexes.first.columns assert_equal ["firm_id"], indexes.first.columns
else else

View file

@ -40,7 +40,7 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
end end
def test_has_many_with_piggyback def test_has_many_with_piggyback
assert_equal "2", categories(:sti_test).authors.first.post_id assert_equal "2", categories(:sti_test).authors.first.post_id.to_s
end end
def test_has_many_find_all def test_has_many_find_all

View file

@ -1,196 +1,196 @@
CREATE TABLE accounts ( CREATE TABLE accounts (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
firm_id int default NULL, firm_id INT DEFAULT NULL,
credit_limit int default NULL, credit_limit INT DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE companies ( CREATE TABLE companies (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
type varchar(50) default NULL, type VARCHAR(50) DEFAULT NULL,
ruby_type varchar(50) default NULL, ruby_type VARCHAR(50) DEFAULT NULL,
firm_id int default NULL, firm_id INT DEFAULT NULL,
name varchar(50) default NULL, name VARCHAR(50) DEFAULT NULL,
client_of int default NULL, client_of INT DEFAULT NULL,
rating int default 1, rating INT DEFAULT 1,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE topics ( CREATE TABLE topics (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
title varchar(255) default NULL, title VARCHAR(255) DEFAULT NULL,
author_name varchar(255) default NULL, author_name VARCHAR(255) DEFAULT NULL,
author_email_address varchar(255) default NULL, author_email_address VARCHAR(255) DEFAULT NULL,
written_on timestamp default NULL, written_on TIMESTAMP DEFAULT NULL,
bonus_time time default NULL, bonus_time TIME DEFAULT NULL,
last_read date default NULL, last_read DATE DEFAULT NULL,
content varchar(3000), content VARCHAR(3000),
approved smallint default 1, approved SMALLINT DEFAULT 1,
replies_count int default 0, replies_count INT DEFAULT 0,
parent_id int default NULL, parent_id INT DEFAULT NULL,
type varchar(50) default NULL, type VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE developers ( CREATE TABLE developers (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(100) default NULL, name VARCHAR(100) DEFAULT NULL,
salary int default 70000, salary INT DEFAULT 70000,
created_at timestamp default NULL, created_at TIMESTAMP DEFAULT NULL,
updated_at timestamp default NULL, updated_at TIMESTAMP DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE projects ( CREATE TABLE projects (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(100) default NULL, name VARCHAR(100) DEFAULT NULL,
type varchar(255) default NULL, type VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE developers_projects ( CREATE TABLE developers_projects (
developer_id int NOT NULL, developer_id INT NOT NULL,
project_id int NOT NULL, project_id INT NOT NULL,
joined_on date default NULL, joined_on DATE DEFAULT NULL,
access_level smallint default 1 access_level SMALLINT DEFAULT 1
); );
CREATE TABLE orders ( CREATE TABLE orders (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(100) default NULL, name VARCHAR(100) DEFAULT NULL,
billing_customer_id int default NULL, billing_customer_id INT DEFAULT NULL,
shipping_customer_id int default NULL, shipping_customer_id INT DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE customers ( CREATE TABLE customers (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(100) default NULL, name VARCHAR(100) DEFAULT NULL,
balance int default 0, balance INT DEFAULT 0,
address_street varchar(100) default NULL, address_street VARCHAR(100) DEFAULT NULL,
address_city varchar(100) default NULL, address_city VARCHAR(100) DEFAULT NULL,
address_country varchar(100) default NULL, address_country VARCHAR(100) DEFAULT NULL,
gps_location varchar(100) default NULL, gps_location VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE movies ( CREATE TABLE movies (
movieid int generated by default as identity (start with +10000), movieid INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(100) default NULL, name VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (movieid) PRIMARY KEY (movieid)
); );
CREATE TABLE subscribers ( CREATE TABLE subscribers (
nick varchar(100) NOT NULL, nick VARCHAR(100) NOT NULL,
name varchar(100) default NULL, name VARCHAR(100) DEFAULT NULL,
PRIMARY KEY (nick) PRIMARY KEY (nick)
); );
CREATE TABLE booleantests ( CREATE TABLE booleantests (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
value int default NULL, value INT DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE auto_id_tests ( CREATE TABLE auto_id_tests (
auto_id int generated by default as identity (start with +10000), auto_id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
value int default NULL, value INT DEFAULT NULL,
PRIMARY KEY (auto_id) PRIMARY KEY (auto_id)
); );
CREATE TABLE entrants ( CREATE TABLE entrants (
id int NOT NULL PRIMARY KEY, id INT NOT NULL PRIMARY KEY,
name varchar(255) NOT NULL, name VARCHAR(255) NOT NULL,
course_id int NOT NULL course_id INT NOT NULL
); );
CREATE TABLE colnametests ( CREATE TABLE colnametests (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
references int NOT NULL, references INT NOT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE mixins ( CREATE TABLE mixins (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
parent_id int default NULL, parent_id INT DEFAULT NULL,
pos int default NULL, pos INT DEFAULT NULL,
created_at timestamp default NULL, created_at TIMESTAMP DEFAULT NULL,
updated_at timestamp default NULL, updated_at TIMESTAMP DEFAULT NULL,
lft int default NULL, lft INT DEFAULT NULL,
rgt int default NULL, rgt INT DEFAULT NULL,
root_id int default NULL, root_id INT DEFAULT NULL,
type varchar(40) default NULL, type VARCHAR(40) DEFAULT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE people ( CREATE TABLE people (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
first_name varchar(40) NOT NULL, first_name VARCHAR(40) NOT NULL,
lock_version int default 0, lock_version INT DEFAULT 0,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE binaries ( CREATE TABLE binaries (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
data blob(50000), data BLOB(50000),
PRIMARY KEY (id) PRIMARY KEY (id)
); );
CREATE TABLE computers ( CREATE TABLE computers (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
developer int NOT NULL, developer INT NOT NULL,
extendedWarranty int NOT NULL extendedWarranty INT NOT NULL
); );
CREATE TABLE posts ( CREATE TABLE posts (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
author_id int default NULL, author_id INT DEFAULT NULL,
title varchar(255) default NULL, title VARCHAR(255) DEFAULT NULL,
type varchar(255) default NULL, type VARCHAR(255) DEFAULT NULL,
body varchar(3000) default NULL body VARCHAR(3000) DEFAULT NULL
); );
CREATE TABLE comments ( CREATE TABLE comments (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
post_id int default NULL, post_id INT DEFAULT NULL,
type varchar(255) default NULL, type VARCHAR(255) DEFAULT NULL,
body varchar(3000) default NULL body VARCHAR(3000) DEFAULT NULL
); );
CREATE TABLE authors ( CREATE TABLE authors (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(255) default NULL name VARCHAR(255) DEFAULT NULL
); );
CREATE TABLE tasks ( CREATE TABLE tasks (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
starting timestamp default NULL, starting TIMESTAMP DEFAULT NULL,
ending timestamp default NULL ending TIMESTAMP DEFAULT NULL
); );
CREATE TABLE categories ( CREATE TABLE categories (
id int generated by default as identity (start with +10000), id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name varchar(255) NOT NULL, name VARCHAR(255) NOT NULL,
type varchar(40) default NULL type VARCHAR(40) DEFAULT NULL
); );
CREATE TABLE categories_posts ( CREATE TABLE categories_posts (
category_id int NOT NULL, category_id INT NOT NULL,
post_id int NOT NULL post_id INT NOT NULL
); );
CREATE TABLE keyboards ( CREATE TABLE keyboards (
key_number int generated by default as identity (start with +10000), key_number INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
name VARCHAR(255) name VARCHAR(255)
); );
CREATE TABLE fk_test_has_pk ( CREATE TABLE fk_test_has_pk (
id INTEGER NOT NULL PRIMARY KEY id INT NOT NULL PRIMARY KEY
); );
CREATE TABLE fk_test_has_fk ( CREATE TABLE fk_test_has_fk (
id INTEGER NOT NULL PRIMARY KEY, id INT NOT NULL PRIMARY KEY,
fk_id INTEGER NOT NULL, fk_id INT NOT NULL,
FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id) FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id)
); );

View file

@ -1,5 +1,5 @@
CREATE TABLE courses ( CREATE TABLE courses (
id int NOT NULL PRIMARY KEY, id INT NOT NULL PRIMARY KEY,
name varchar(255) NOT NULL name VARCHAR(255) NOT NULL
); );