ibm_db 0.9.4 → 0.9.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +15 -0
- data/README +11 -4
- data/ext/ibm_db.c +16 -15
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +268 -73
- data/test/adapter_test.rb +26 -8
- data/test/associations/eager_test.rb +63 -58
- data/test/associations_test.rb +584 -272
- data/test/base_test.rb +312 -130
- data/test/fixtures/db_definitions/i5/ibm_db.drop.sql +1 -0
- data/test/fixtures/db_definitions/i5/ibm_db.sql +5 -1
- data/test/fixtures/db_definitions/ids/ibm_db.drop.sql +1 -0
- data/test/fixtures/db_definitions/ids/ibm_db.sql +3 -0
- data/test/fixtures/db_definitions/luw/ibm_db.drop.sql +1 -0
- data/test/fixtures/db_definitions/luw/ibm_db.sql +5 -1
- data/test/fixtures/db_definitions/schema.rb +361 -0
- data/test/fixtures/db_definitions/zOS/ibm_db.drop.sql +1 -0
- data/test/fixtures/db_definitions/zOS/ibm_db.sql +5 -1
- data/test/locking_test.rb +95 -3
- data/test/migration_test.rb +308 -142
- metadata +3 -2
data/CHANGES
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
Change Log
|
2
2
|
==============
|
3
|
+
2008/06/24 (IBM_DB adapter 0.9.5, driver 0.9.5):
|
4
|
+
- Fixed Bug [#19222] --> Fixed fixture insertion of LOB columns for DB2
|
5
|
+
- Fixed Bug [#19970] --> Fixed Table schema dumper also dump views
|
6
|
+
- Fixed Bug [#20053] --> Fixed CLOB data with special chars contains null characters upon retrieval
|
7
|
+
- Fixed Bug [#20762] --> IBM_DB adapter with Rails 2.1 fails on rake db:migrate
|
8
|
+
- Cleaned up fix for Bug [#19223] and [#19224], indexes are now dumped as array without schema qualified name.
|
9
|
+
- Support for Rails-2.0.2
|
10
|
+
- Support for Rails-2.1.0
|
11
|
+
Rails-2.1.0 contains changes that generates Non-standard SQL in 2 noticed cases which won't work with SQL compliant databases like DB2
|
12
|
+
a. Handling Nullable columns in Table creation. [http://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/398-non-standard-sql-generated-in-column-definition-for-nullable-columns-in-create-table-ddl-rails-2-1#ticket-398-2]
|
13
|
+
A workaround for this problem is provided from within ibm_db adapter.
|
14
|
+
b. Handling has_and_belongs_to_many association. [http://rails.lighthouseapp.com/projects/8994/tickets/394-patch-fixed-non-standard-sql-generated-by-preloading-has_and_belongs_to_many-associations].
|
15
|
+
It is not possible to provide a workaround for this from within the ibm_db adapter.
|
16
|
+
To workaround this problem please patch ActiveRecord-2.1.0 with the patch available at [http://rails.lighthouseapp.com/attachments/26975/association_preloading.diff]
|
17
|
+
|
3
18
|
2008/04/28 (IBM_DB adapter 0.9.4, driver 0.9.4):
|
4
19
|
- Fixed bug [#19679]--> invalid values being returned for blank or null in fetch_assoc
|
5
20
|
- Fixed bug [#19223] and [#19224]--> handling of composite and unique indexes incorrect
|
data/README
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
=====================================================================
|
2
|
-
README for the IBM_DB Adapter 0.9.
|
3
|
-
For ActiveRecord Version 1.15.5 (and Rails 1.2.5)
|
2
|
+
README for the IBM_DB Adapter 0.9.5 and Driver 0.9.5 (2008/06/24)
|
3
|
+
For ActiveRecord Version >= 1.15.5 (and Rails >= 1.2.5)
|
4
4
|
=====================================================================
|
5
5
|
|
6
6
|
Supported Operating Systems
|
@@ -108,7 +108,7 @@ Ruby environment, including Rails, to interact with IBM data servers.
|
|
108
108
|
$ ls -al vendor/plugins/
|
109
109
|
$ irb
|
110
110
|
irb(main):001:0> gem 'ibm_db'
|
111
|
-
irb(main):002:0> require 'ibm_db' // notice the library path (different on win32)
|
111
|
+
irb(main):002:0> require 'ibm_db' // notice the library path (different on win32, use require 'mswin32/ibm_db')
|
112
112
|
irb(main):003:0> IBM_DB::connect 'sample', 'db2admin', 'secret'
|
113
113
|
$ ./script/console
|
114
114
|
|
@@ -286,7 +286,14 @@ Limitations and known problems
|
|
286
286
|
The IBM_DB adapter relies on IBM_DB driver (C extension) and the IBM Driver for ODBC and
|
287
287
|
CLI to access databases on IBM data servers. Alternatively, you can either use the regular C
|
288
288
|
implementation of Ruby, or use ActiveRecord-JDBC adapter to access databases.
|
289
|
-
|
289
|
+
- Query caching feature of ActiveRecord-2.0 not supported
|
290
|
+
- When using ActiveRecord-2.1.0 it requires that ActiveRecord be patched, with the patch in the link below:
|
291
|
+
http://rails.lighthouseapp.com/attachments/26975/association_preloading.diff
|
292
|
+
The patch is required because, ActiveRecord 2.1.0 generates a non-standard SQL identifier,while preloading has_and_belongs_to_many associations,
|
293
|
+
which standard compliant databases like DB2 do not support. The bug report, against ActiveRecord, can be found in the link below
|
294
|
+
http://rails.lighthouseapp.com/projects/8994/tickets/394-patch-fixed-non-standard-sql-generated-by-preloading-has_and_belongs_to_many-associations
|
295
|
+
- ActiveRecord-2.1.0 test suite changes appropriate for DB2/IDS will be updated in the next release of the gem.
|
296
|
+
|
290
297
|
To Do
|
291
298
|
====
|
292
299
|
- Support ActiveRecord remove_column method for DB2 zOS version 9
|
data/ext/ibm_db.c
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
+----------------------------------------------------------------------+
|
11
11
|
*/
|
12
12
|
|
13
|
-
#define MODULE_RELEASE "0.9.
|
13
|
+
#define MODULE_RELEASE "0.9.5"
|
14
14
|
|
15
15
|
#ifdef HAVE_CONFIG_H
|
16
16
|
#include "config.h"
|
@@ -3750,7 +3750,8 @@ VALUE ibm_db_conn_errormsg(int argc, VALUE *argv, VALUE self)
|
|
3750
3750
|
rb_throw("Connection is not active", Qnil);
|
3751
3751
|
}
|
3752
3752
|
|
3753
|
-
return_str = ALLOC_N(char,
|
3753
|
+
return_str = ALLOC_N(char, DB2_MAX_ERR_MSG_LEN);
|
3754
|
+
memset(return_str, 0, DB2_MAX_ERR_MSG_LEN);
|
3754
3755
|
|
3755
3756
|
_ruby_ibm_db_check_sql_errors(conn_res->hdbc, SQL_HANDLE_DBC, -1, 0, return_str, DB2_ERRMSG, conn_res->errormsg_recno_tracker);
|
3756
3757
|
if(conn_res->errormsg_recno_tracker - conn_res->error_recno_tracker >= 1)
|
@@ -4680,7 +4681,7 @@ static RETCODE _ruby_ibm_db_get_length(stmt_handle* stmt_res, SQLUSMALLINT col_n
|
|
4680
4681
|
/* }}} */
|
4681
4682
|
|
4682
4683
|
/* {{{ static RETCODE _ruby_ibm_db_get_data2(stmt_handle *stmt_res, int col_num, short ctype, void *buff, int in_length, SQLINTEGER *out_length) */
|
4683
|
-
static RETCODE _ruby_ibm_db_get_data2(stmt_handle *stmt_res, SQLUSMALLINT col_num, SQLSMALLINT ctype, SQLPOINTER buff, SQLLEN
|
4684
|
+
static RETCODE _ruby_ibm_db_get_data2(stmt_handle *stmt_res, SQLUSMALLINT col_num, SQLSMALLINT ctype, SQLPOINTER buff, SQLLEN read_length, SQLLEN buff_length, SQLINTEGER *out_length)
|
4684
4685
|
{
|
4685
4686
|
RETCODE rc=SQL_SUCCESS;
|
4686
4687
|
SQLHANDLE new_hstmt;
|
@@ -4692,9 +4693,9 @@ static RETCODE _ruby_ibm_db_get_data2(stmt_handle *stmt_res, SQLUSMALLINT col_nu
|
|
4692
4693
|
return SQL_ERROR;
|
4693
4694
|
}
|
4694
4695
|
|
4695
|
-
|
4696
|
-
stmt_res->column_info[col_num-1].lob_loc, 1,
|
4697
|
-
buff,
|
4696
|
+
rc = SQLGetSubString((SQLHSTMT)new_hstmt, stmt_res->column_info[col_num-1].loc_type,
|
4697
|
+
stmt_res->column_info[col_num-1].lob_loc, 1, read_length, targetCType,
|
4698
|
+
buff, buff_length, out_length, &stmt_res->column_info[col_num-1].loc_ind);
|
4698
4699
|
if ( rc == SQL_ERROR ) {
|
4699
4700
|
_ruby_ibm_db_check_sql_errors((SQLHSTMT)new_hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
|
4700
4701
|
}
|
@@ -4860,7 +4861,7 @@ VALUE ibm_db_result(int argc, VALUE *argv, VALUE self)
|
|
4860
4861
|
rb_throw("Failed to Allocate Memory for LOB Data", Qnil);
|
4861
4862
|
return Qfalse;
|
4862
4863
|
}
|
4863
|
-
rc = _ruby_ibm_db_get_data2(stmt_res, col_num+1, SQL_C_CHAR, (void*)out_char_ptr, in_length+1, &out_length);
|
4864
|
+
rc = _ruby_ibm_db_get_data2(stmt_res, col_num+1, SQL_C_CHAR, (void*)out_char_ptr, in_length, in_length+1, &out_length);
|
4864
4865
|
if (rc == SQL_ERROR) {
|
4865
4866
|
return Qfalse;
|
4866
4867
|
}
|
@@ -4900,7 +4901,7 @@ VALUE ibm_db_result(int argc, VALUE *argv, VALUE self)
|
|
4900
4901
|
rb_throw("Failed to Allocate Memory for LOB Data", Qnil);
|
4901
4902
|
return Qfalse;
|
4902
4903
|
}
|
4903
|
-
rc = _ruby_ibm_db_get_data2(stmt_res, col_num+1, lob_bind_type, (char *)out_ptr, in_length, &out_length);
|
4904
|
+
rc = _ruby_ibm_db_get_data2(stmt_res, col_num+1, lob_bind_type, (char *)out_ptr, in_length, in_length, &out_length);
|
4904
4905
|
if (rc == SQL_ERROR) {
|
4905
4906
|
return Qfalse;
|
4906
4907
|
}
|
@@ -4924,7 +4925,7 @@ VALUE ibm_db_result(int argc, VALUE *argv, VALUE self)
|
|
4924
4925
|
rb_throw("Failed to Allocate Memory for XML Data", Qnil);
|
4925
4926
|
return Qfalse;
|
4926
4927
|
}
|
4927
|
-
rc = _ruby_ibm_db_get_data2(stmt_res, col_num+1, SQL_C_BINARY, (SQLPOINTER)out_ptr, in_length, &out_length);
|
4928
|
+
rc = _ruby_ibm_db_get_data2(stmt_res, col_num+1, SQL_C_BINARY, (SQLPOINTER)out_ptr, in_length, in_length, &out_length);
|
4928
4929
|
if (rc == SQL_ERROR) {
|
4929
4930
|
return Qfalse;
|
4930
4931
|
}
|
@@ -5214,7 +5215,7 @@ static VALUE _ruby_ibm_db_bind_fetch_helper(int argc, VALUE *argv, int op)
|
|
5214
5215
|
case BINARY:
|
5215
5216
|
out_ptr = (SQLPOINTER)ALLOC_N(char, tmp_length);
|
5216
5217
|
|
5217
|
-
rc = _ruby_ibm_db_get_data2(stmt_res, i+1, lob_bind_type, (char *)out_ptr, tmp_length, &out_length);
|
5218
|
+
rc = _ruby_ibm_db_get_data2(stmt_res, i+1, lob_bind_type, (char *)out_ptr, tmp_length, tmp_length, &out_length);
|
5218
5219
|
if (rc == SQL_ERROR) {
|
5219
5220
|
ruby_xfree(out_ptr);
|
5220
5221
|
out_length = 0;
|
@@ -5314,21 +5315,21 @@ static VALUE _ruby_ibm_db_bind_fetch_helper(int argc, VALUE *argv, int op)
|
|
5314
5315
|
return Qfalse;
|
5315
5316
|
}
|
5316
5317
|
|
5317
|
-
rc = _ruby_ibm_db_get_data2(stmt_res, i+1, SQL_C_CHAR, out_ptr, tmp_length+1, &out_length);
|
5318
|
+
rc = _ruby_ibm_db_get_data2(stmt_res, i+1, SQL_C_CHAR, out_ptr, tmp_length, tmp_length+1, &out_length);
|
5318
5319
|
if (rc == SQL_ERROR) {
|
5319
5320
|
ruby_xfree(out_ptr);
|
5320
|
-
|
5321
|
+
out_length = 0;
|
5321
5322
|
} else {
|
5322
5323
|
out_ptr[tmp_length] = '\0';
|
5323
5324
|
}
|
5324
5325
|
|
5325
5326
|
if ( op & FETCH_ASSOC ) {
|
5326
|
-
rb_hash_aset(return_value, rb_str_new2((char*)stmt_res->column_info[i].name), rb_str_new((char*)out_ptr,
|
5327
|
+
rb_hash_aset(return_value, rb_str_new2((char*)stmt_res->column_info[i].name), rb_str_new((char*)out_ptr, out_length));
|
5327
5328
|
}
|
5328
5329
|
if ( op == FETCH_INDEX ) {
|
5329
|
-
rb_ary_store(return_value, i, rb_str_new((char*)out_ptr,
|
5330
|
+
rb_ary_store(return_value, i, rb_str_new((char*)out_ptr, out_length));
|
5330
5331
|
} else if ( op == FETCH_BOTH ) {
|
5331
|
-
rb_hash_aset(return_value, INT2NUM(i), rb_str_new((char*)out_ptr,
|
5332
|
+
rb_hash_aset(return_value, INT2NUM(i), rb_str_new((char*)out_ptr, out_length));
|
5332
5333
|
}
|
5333
5334
|
}
|
5334
5335
|
break;
|
@@ -479,11 +479,20 @@ requires credentials: username and password"
|
|
479
479
|
def create_table(name, options = {})
|
480
480
|
@servertype.setup_for_lob_table
|
481
481
|
super
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
482
|
+
|
483
|
+
#Table definition is complete only when a unique index is created on the primarykey column for DB2 V8 on zOS
|
484
|
+
|
485
|
+
#create index on id column if options[:id] is nil or id ==true
|
486
|
+
#else check if options[:primary_key]is not nil then create an unique index on that column
|
487
|
+
if !options[:id].nil? || !options[:primary_key].nil?
|
488
|
+
if (!options[:id].nil? && options[:id] == true)
|
489
|
+
@servertype.create_index_after_table(name,"id")
|
490
|
+
elsif !options[:primary_key].nil?
|
491
|
+
@servertype.create_index_after_table(name,options[:primary_key].to_s)
|
492
|
+
end
|
493
|
+
else
|
494
|
+
@servertype.create_index_after_table(name,"id")
|
495
|
+
end
|
487
496
|
end
|
488
497
|
|
489
498
|
# Returns an array of hashes with the column names as keys and
|
@@ -508,6 +517,28 @@ requires credentials: username and password"
|
|
508
517
|
results
|
509
518
|
end
|
510
519
|
|
520
|
+
#Returns an array of arrays containing the field values.
|
521
|
+
#This is an implementation for the abstract method
|
522
|
+
#+sql+ is the select query and +name+ is an optional description for logging
|
523
|
+
def select_rows(sql, name = nil)
|
524
|
+
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
525
|
+
sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
|
526
|
+
|
527
|
+
results = []
|
528
|
+
# Invokes the method +execute+ in order to log and execute the SQL
|
529
|
+
# IBM_DB::Statement is returned from which results can be fetched
|
530
|
+
if stmt = execute(sql, name)
|
531
|
+
begin
|
532
|
+
@servertype.select_rows(sql, name, stmt, results)
|
533
|
+
ensure
|
534
|
+
# Ensures to free the resources associated with the statement
|
535
|
+
IBM_DB::free_result stmt
|
536
|
+
end
|
537
|
+
end
|
538
|
+
# The array of record hashes is returned
|
539
|
+
results
|
540
|
+
end
|
541
|
+
|
511
542
|
# Returns a record hash with the column names as keys and column values
|
512
543
|
# as values.
|
513
544
|
def select_one(sql, name = nil)
|
@@ -516,6 +547,64 @@ requires credentials: username and password"
|
|
516
547
|
select_all(sql,name).first
|
517
548
|
end
|
518
549
|
|
550
|
+
#inserts values from fixtures
|
551
|
+
#overridden to handle LOB's fixture insertion, as, in normal inserts callbacks are triggered but during fixture insertion callbacks are not triggered
|
552
|
+
#hence only markers like @@@IBMBINARY@@@ will be inserted and are not updated to actual data
|
553
|
+
def insert_fixture(fixture, table_name)
|
554
|
+
insert_query = "INSERT INTO #{quote_table_name(table_name)} ( #{fixture.key_list})"
|
555
|
+
insert_values = []
|
556
|
+
params = []
|
557
|
+
if @servertype.instance_of? IBM_IDS
|
558
|
+
super
|
559
|
+
return
|
560
|
+
end
|
561
|
+
column_list = columns(table_name)
|
562
|
+
fixture.each do |item|
|
563
|
+
col = nil
|
564
|
+
column_list.each do |col|
|
565
|
+
if col.name == item.at(0)
|
566
|
+
break
|
567
|
+
end
|
568
|
+
end
|
569
|
+
if item.at(1).nil? ||
|
570
|
+
item.at(1) == {} ||
|
571
|
+
(item.at(1) == '' && !(col.type.to_sym == :text))
|
572
|
+
|
573
|
+
params << 'NULL'
|
574
|
+
|
575
|
+
elsif col.type.to_sym == :xml ||
|
576
|
+
col.type.to_sym == :text ||
|
577
|
+
col.type.to_sym == :binary
|
578
|
+
# Add a '?' for the parameter or a NULL if the value is nil or empty
|
579
|
+
# (except for a CLOB field where '' can be a value)
|
580
|
+
insert_values << item.at(1)
|
581
|
+
params << '?'
|
582
|
+
else
|
583
|
+
insert_values << quote(item.at(1),col)
|
584
|
+
params << '?'
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
insert_query << " VALUES ("+ params.join(',') + ")"
|
589
|
+
unless stmt = IBM_DB::prepare(@connection, insert_query)
|
590
|
+
error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
|
591
|
+
if error_msg && !error_msg.empty?
|
592
|
+
raise "Failed to prepare statement due to : #{error_msg}"
|
593
|
+
else
|
594
|
+
raise StandardError('Unexpected error during insert')
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
#log_query(insert_query,'fixture insert')
|
599
|
+
log(insert_query,'fixture insert') do
|
600
|
+
unless IBM_DB::execute(stmt, insert_values)
|
601
|
+
raise "Failed to insert due to: #{IBM_DB::stmt_errormsg(stmt)}"
|
602
|
+
else
|
603
|
+
IBM_DB::free_result stmt
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
519
608
|
# Perform an insert and returns the last ID generated.
|
520
609
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
521
610
|
# and retrieved by the +last_generated_id+ method.
|
@@ -644,37 +733,45 @@ requires credentials: username and password"
|
|
644
733
|
# (IBM_DB doesn't accept quotes on numeric types)
|
645
734
|
when Numeric
|
646
735
|
# If the column type is text or string, return the quote value
|
647
|
-
if column && column.type == :text || column && column.type == :string
|
648
|
-
|
736
|
+
if column && column.type.to_sym == :text || column && column.type.to_sym == :string
|
737
|
+
unless caller[0] =~ /insert_fixture/i
|
738
|
+
"'#{value}'"
|
739
|
+
else
|
740
|
+
"#{value}"
|
741
|
+
end
|
649
742
|
else
|
650
743
|
# value is Numeric, column.type is not a string,
|
651
744
|
# therefore it converts the number to string without quoting it
|
652
745
|
value.to_s
|
653
746
|
end
|
654
747
|
when String, ActiveSupport::Multibyte::Chars
|
655
|
-
if column && column.type == :binary
|
748
|
+
if column && column.type.to_sym == :binary
|
656
749
|
# If quoting is required for the insert/update of a BLOB
|
657
|
-
|
658
|
-
|
750
|
+
unless caller[0] =~ /add_column_options/i
|
751
|
+
# Invokes a convertion from string to binary
|
659
752
|
@servertype.set_binary_value
|
660
|
-
|
661
|
-
|
753
|
+
else
|
754
|
+
# Quoting required for the default value of a column
|
662
755
|
@servertype.set_binary_default(value)
|
663
756
|
end
|
664
|
-
elsif column && column.type == :text
|
757
|
+
elsif column && column.type.to_sym == :text
|
665
758
|
unless caller[0] =~ /add_column_options/i
|
666
759
|
"'@@@IBMTEXT@@@'"
|
667
760
|
else
|
668
|
-
@servertype.set_text_default(value)
|
761
|
+
@servertype.set_text_default(quote_string(value))
|
669
762
|
end
|
670
|
-
elsif column && column.type == :xml
|
763
|
+
elsif column && column.type.to_sym == :xml
|
671
764
|
unless caller[0] =~ /add_column_options/i
|
672
765
|
"'<ibm>@@@IBMXML@@@</ibm>'"
|
673
766
|
else
|
674
767
|
"#{value}"
|
675
768
|
end
|
676
769
|
else
|
677
|
-
|
770
|
+
unless caller[0] =~ /insert_fixture/i
|
771
|
+
"'#{quote_string(value)}'"
|
772
|
+
else
|
773
|
+
"#{value}"
|
774
|
+
end
|
678
775
|
end
|
679
776
|
when TrueClass then quoted_true # return '1' for true
|
680
777
|
when FalseClass then quoted_false # return '0' for false
|
@@ -770,7 +867,9 @@ requires credentials: username and password"
|
|
770
867
|
# Fetches all the records available
|
771
868
|
while tab = IBM_DB::fetch_assoc(stmt)
|
772
869
|
# Adds the lowercase table name to the array
|
773
|
-
|
870
|
+
if(tab["table_type"]== 'TABLE') #check, so that only tables are dumped,IBM_DB::tables also returns views,alias etc in the schema
|
871
|
+
tables << tab["table_name"].downcase
|
872
|
+
end
|
774
873
|
end
|
775
874
|
ensure
|
776
875
|
IBM_DB::free_result(stmt) # Free resources associated with the statement
|
@@ -795,9 +894,7 @@ requires credentials: username and password"
|
|
795
894
|
# If so it returns an empty array of columns.
|
796
895
|
return [] if table_name.strip.empty?
|
797
896
|
|
798
|
-
# +index_array+ will contain the resulting array
|
799
897
|
indexes = []
|
800
|
-
index_array = []
|
801
898
|
pk_index = nil
|
802
899
|
index_schema = []
|
803
900
|
|
@@ -809,18 +906,19 @@ requires credentials: username and password"
|
|
809
906
|
if stmt = IBM_DB::primary_keys( @connection, nil,
|
810
907
|
@servertype.set_case(@schema),
|
811
908
|
@servertype.set_case(table_name))
|
812
|
-
|
909
|
+
begin
|
813
910
|
while ( pk_index_row = IBM_DB::fetch_array(stmt) )
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
911
|
+
if pk_index_row[5]
|
912
|
+
pk_index_name = pk_index_row[5].downcase
|
913
|
+
pk_index_columns = pk_index_row[3].map{|c| c.downcase} # COLUMN_NAME
|
914
|
+
if pk_index
|
915
|
+
pk_index.columns = pk_index.columns + pk_index_columns
|
916
|
+
else
|
917
|
+
pk_index = IndexDefinition.new(table_name, pk_index_name, true, pk_index_columns)
|
821
918
|
end
|
919
|
+
end
|
822
920
|
end
|
823
|
-
|
921
|
+
ensure # Free resources associated with the statement
|
824
922
|
IBM_DB::free_result(stmt) if stmt
|
825
923
|
end
|
826
924
|
else # Handle driver execution errors
|
@@ -838,58 +936,56 @@ requires credentials: username and password"
|
|
838
936
|
# "NON_UNIQUE: #{index_stats[3]}"
|
839
937
|
# "INDEX_NAME: #{index_stats[5]}"
|
840
938
|
# "COLUMN_NAME: #{index_stats[8]}"
|
841
|
-
|
939
|
+
if stmt = IBM_DB::statistics( @connection, nil,
|
842
940
|
@servertype.set_case(@schema),
|
843
941
|
@servertype.set_case(table_name), 1 )
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
942
|
+
begin
|
943
|
+
while ( index_stats = IBM_DB::fetch_array(stmt) )
|
944
|
+
is_composite = false
|
945
|
+
if index_stats[5] # INDEX_NAME
|
946
|
+
index_name = index_stats[5].downcase
|
947
|
+
index_unique = (index_stats[3] == 0)
|
948
|
+
index_columns = index_stats[8].map{|c| c.downcase} # COLUMN_NAME
|
949
|
+
index_qualifier = index_stats[4].downcase #Index_Qualifier
|
950
|
+
# Create an IndexDefinition object and add to the indexes array
|
951
|
+
i = 0;
|
952
|
+
indexes.each do |index|
|
953
|
+
if index.name == index_name && index_schema[i] == index_qualifier
|
954
|
+
index.columns = index.columns + index_columns
|
955
|
+
is_composite = true
|
956
|
+
end
|
957
|
+
i = i+1
|
958
|
+
end
|
959
|
+
|
960
|
+
unless is_composite
|
961
|
+
indexes << IndexDefinition.new(table_name, index_name, index_unique, index_columns)
|
962
|
+
index_schema << index_qualifier
|
858
963
|
end
|
859
|
-
i = i+1
|
860
964
|
end
|
861
|
-
|
862
|
-
unless is_composite
|
863
|
-
indexes << IndexDefinition.new(table_name, index_name, index_unique, index_columns)
|
864
|
-
index_schema << index_qualifier.downcase
|
865
|
-
end
|
866
|
-
|
867
965
|
end
|
966
|
+
ensure # Free resources associated with the statement
|
967
|
+
IBM_DB::free_result(stmt) if stmt
|
868
968
|
end
|
869
|
-
ensure # Free resources associated with the statement
|
870
|
-
IBM_DB::free_result(stmt) if stmt
|
871
|
-
end
|
872
969
|
else # Handle driver execution errors
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
970
|
+
error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
|
971
|
+
if error_msg && !error_msg.empty?
|
972
|
+
raise "Failed to retrieve index metadata due to error: #{error_msg}"
|
973
|
+
else
|
974
|
+
raise StandardError('Unexpected error during index retrieval')
|
975
|
+
end
|
879
976
|
end
|
880
977
|
|
881
|
-
|
978
|
+
# remove the primary key index entry.... should not be dumped by the dumper
|
882
979
|
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
end
|
980
|
+
i = 0
|
981
|
+
indexes.each do |index|
|
982
|
+
if pk_index && index.columns == pk_index.columns
|
983
|
+
indexes.delete_at(i)
|
984
|
+
end
|
889
985
|
i = i+1
|
890
|
-
|
986
|
+
end
|
891
987
|
# Returns the indexes array
|
892
|
-
return
|
988
|
+
return indexes
|
893
989
|
end
|
894
990
|
|
895
991
|
# Returns an array of Column objects for the table specified by +table_name+
|
@@ -1004,6 +1100,29 @@ requires credentials: username and password"
|
|
1004
1100
|
@servertype.change_column(table_name, column_name, type, options)
|
1005
1101
|
end
|
1006
1102
|
|
1103
|
+
#overrides the abstract adapter method to generate proper sql
|
1104
|
+
#specifying the column options, like default value and nullability clause
|
1105
|
+
def add_column_options!(sql,options={})
|
1106
|
+
#add default null option only if :default option is not specified and
|
1107
|
+
#:null option is not specified or is true
|
1108
|
+
if (options[:default].nil? && (options[:null].nil? || options[:null] == true))
|
1109
|
+
sql << " DEFAULT NULL"
|
1110
|
+
else
|
1111
|
+
if( !options[:default].nil?)
|
1112
|
+
#check, :column option is passed only in case of create_table but not in case of add_column
|
1113
|
+
if (!options[:column].nil?)
|
1114
|
+
sql << " DEFAULT #{quote(options[:default],options[:column])}"
|
1115
|
+
else
|
1116
|
+
sql << " DEFAULT #{quote(options[:default])}"
|
1117
|
+
end
|
1118
|
+
end
|
1119
|
+
#append NOT NULL to sql only---
|
1120
|
+
#---if options[:null] is not nil and is equal to false
|
1121
|
+
unless options[:null] == nil
|
1122
|
+
sql << " NOT NULL" if (options[:null] == false)
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
end
|
1007
1126
|
# Sets a new default value for a column. This does not set the default
|
1008
1127
|
# value to +NULL+, instead, it needs DatabaseStatements#execute which
|
1009
1128
|
# can execute the appropriate SQL statement for setting the value.
|
@@ -1042,7 +1161,7 @@ requires credentials: username and password"
|
|
1042
1161
|
def last_generated_id(stmt)
|
1043
1162
|
end
|
1044
1163
|
|
1045
|
-
def create_index_after_table (table_name)
|
1164
|
+
def create_index_after_table (table_name,cloumn_name)
|
1046
1165
|
end
|
1047
1166
|
|
1048
1167
|
def setup_for_lob_table ()
|
@@ -1083,6 +1202,16 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
1083
1202
|
end
|
1084
1203
|
end
|
1085
1204
|
|
1205
|
+
def select_rows(sql, name, stmt, results)
|
1206
|
+
# Fetches all the results available. IBM_DB::fetch_array(stmt) returns
|
1207
|
+
# an array representing a row in a result set.
|
1208
|
+
# The loop stops when there aren't any more valid records to fetch
|
1209
|
+
while single_array = IBM_DB::fetch_array(stmt)
|
1210
|
+
#Add the array to results array
|
1211
|
+
results << single_array
|
1212
|
+
end
|
1213
|
+
end
|
1214
|
+
|
1086
1215
|
def execute(sql, name = nil)
|
1087
1216
|
begin
|
1088
1217
|
if stmt = IBM_DB::exec(@adapter.connection, sql)
|
@@ -1177,9 +1306,13 @@ The column datatype change to [#{data_type}] is not supported by this data serve
|
|
1177
1306
|
end
|
1178
1307
|
end
|
1179
1308
|
reorg_table(table_name)
|
1309
|
+
if !options[:null].nil? && !options[:null]
|
1310
|
+
execute "ALTER TABLE #{table_name} ALTER #{column_name} SET NOT NULL"
|
1311
|
+
end
|
1180
1312
|
if !options[:default].nil?
|
1181
1313
|
change_column_default(table_name, column_name, options[:default])
|
1182
1314
|
end
|
1315
|
+
reorg_table(table_name)
|
1183
1316
|
end
|
1184
1317
|
|
1185
1318
|
# DB2 specific ALTER TABLE statement to add a default clause
|
@@ -1262,6 +1395,64 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
1262
1395
|
@limit = nil
|
1263
1396
|
end
|
1264
1397
|
|
1398
|
+
# Fetches all the results available. IBM_DB::fetch_array(stmt) returns
|
1399
|
+
# an array for each single record.
|
1400
|
+
# The loop stops when there aren't any more valid records to fetch
|
1401
|
+
def select_rows(sql, name, stmt, results)
|
1402
|
+
if (!@offset.nil? && @offset >= 0) || (!@limit.nil? && @limit > 0)
|
1403
|
+
# We know at this point that there is an offset and/or a limit
|
1404
|
+
# Check if the cursor type is set correctly
|
1405
|
+
cursor_type = IBM_DB::get_option stmt, IBM_DB::SQL_ATTR_CURSOR_TYPE, 0
|
1406
|
+
@offset = 0 if @offset.nil?
|
1407
|
+
if (cursor_type == IBM_DB::SQL_CURSOR_STATIC)
|
1408
|
+
index = 0
|
1409
|
+
# Get @limit rows starting at @offset
|
1410
|
+
while (index < @limit)
|
1411
|
+
# We increment the offset by 1 because for DB2 the offset of the initial row is 1 instead of 0
|
1412
|
+
if single_array = IBM_DB::fetch_array(stmt, @offset + index + 1)
|
1413
|
+
# Add the array to the +results+ array
|
1414
|
+
results << single_array
|
1415
|
+
index = index + 1
|
1416
|
+
else
|
1417
|
+
# break from the while loop
|
1418
|
+
break
|
1419
|
+
end
|
1420
|
+
end
|
1421
|
+
else # cursor != IBM_DB::SQL_CURSOR_STATIC
|
1422
|
+
# If the result set contains a LOB, the cursor type will never be SQL_CURSOR_STATIC
|
1423
|
+
# because DB2 does not allow this. We can't use the offset mechanism because the cursor
|
1424
|
+
# is not scrollable. In this case, ignore first @offset rows and return rows starting
|
1425
|
+
# at @offset to @offset + @limit
|
1426
|
+
index = 0
|
1427
|
+
while (index < @offset + @limit)
|
1428
|
+
if single_array = IBM_DB::fetch_array(stmt)
|
1429
|
+
# Add the array to the +results+ array only from row @offset to @offset + @limit
|
1430
|
+
if (index >= @offset)
|
1431
|
+
results << single_array
|
1432
|
+
end
|
1433
|
+
index = index + 1
|
1434
|
+
else
|
1435
|
+
# break from the while loop
|
1436
|
+
break
|
1437
|
+
end
|
1438
|
+
end
|
1439
|
+
end
|
1440
|
+
# This is the case where limit is set to zero
|
1441
|
+
# Simply return an empty +results+
|
1442
|
+
elsif (!@limit.nil? && @limit == 0)
|
1443
|
+
results
|
1444
|
+
# No limits or offsets specified
|
1445
|
+
else
|
1446
|
+
while single_array = IBM_DB::fetch_array(stmt)
|
1447
|
+
# Add the array to the +results+ array
|
1448
|
+
results << single_array
|
1449
|
+
end
|
1450
|
+
end
|
1451
|
+
# Assign the instance variables to nil. We will not be using them again
|
1452
|
+
@offset = nil
|
1453
|
+
@limit = nil
|
1454
|
+
end
|
1455
|
+
|
1265
1456
|
def execute(sql, name = nil)
|
1266
1457
|
# Check if there is a limit and/or an offset
|
1267
1458
|
# If so then make sure and use a static cursor type
|
@@ -1322,7 +1513,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
1322
1513
|
# This method generates the default clob value specified for
|
1323
1514
|
# DB2 Dataservers
|
1324
1515
|
def set_text_default(value)
|
1325
|
-
"#{value}"
|
1516
|
+
"'#{value}'"
|
1326
1517
|
end
|
1327
1518
|
|
1328
1519
|
# For DB2 Dataservers , the arguments to the meta-data functions
|
@@ -1375,8 +1566,8 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
1375
1566
|
|
1376
1567
|
class IBM_DB2_ZOS < IBM_DB2
|
1377
1568
|
# since v9 doesn't need, suggest putting it in HostedDataServer?
|
1378
|
-
def create_index_after_table(table_name)
|
1379
|
-
@adapter.add_index(table_name,
|
1569
|
+
def create_index_after_table(table_name,column_name)
|
1570
|
+
@adapter.add_index(table_name, column_name, :unique => true)
|
1380
1571
|
end
|
1381
1572
|
|
1382
1573
|
def remove_column(table_name, column_name)
|
@@ -1440,7 +1631,11 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
1440
1631
|
end
|
1441
1632
|
|
1442
1633
|
def change_column(table_name, column_name, type, options)
|
1443
|
-
|
1634
|
+
if !options[:null].nil? && !options[:null]
|
1635
|
+
execute "ALTER TABLE #{table_name} MODIFY #{column_name} #{@adapter.type_to_sql(type, options[:limit], options[:precision], options[:scale])} NOT NULL"
|
1636
|
+
else
|
1637
|
+
execute "ALTER TABLE #{table_name} MODIFY #{column_name} #{@adapter.type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
1638
|
+
end
|
1444
1639
|
if !options[:default].nil?
|
1445
1640
|
change_column_default(table_name, column_name, options[:default])
|
1446
1641
|
end
|