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 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.2 and Driver 0.9.1 (2007/11/30)
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.4"
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, SQL_SQLSTATE_SIZE + 1);
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 in_length, SQLINTEGER *out_length)
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
- rc = SQLGetSubString((SQLHSTMT)new_hstmt, stmt_res->column_info[col_num-1].loc_type,
4696
- stmt_res->column_info[col_num-1].lob_loc, 1, in_length, targetCType,
4697
- buff, in_length, out_length, &stmt_res->column_info[col_num-1].loc_ind);
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
- tmp_length = 0;
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, tmp_length));
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, tmp_length));
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, tmp_length));
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
- # force implicit id column (primary key) unless :id => false
483
- unless !options[:id].nil? and
484
- !options[:id]
485
- @servertype.create_index_after_table(name)
486
- end
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
- "'#{value}'"
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
- unless caller[0] =~ /add_column_options/i
658
- # Invokes a convertion from string to binary
750
+ unless caller[0] =~ /add_column_options/i
751
+ # Invokes a convertion from string to binary
659
752
  @servertype.set_binary_value
660
- else
661
- # Quoting required for the default value of a column
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
- "'#{quote_string(value)}'"
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
- tables << tab["table_name"].downcase
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
- begin
909
+ begin
813
910
  while ( pk_index_row = IBM_DB::fetch_array(stmt) )
814
- pk_index_name = pk_index_row[5].downcase
815
- pk_index_columns = pk_index_row[3].map{|c| c.downcase} # COLUMN_NAME
816
- if pk_index
817
- pk_index.columns = "#{pk_index.columns} , #{pk_index_columns}"
818
- else
819
- pk_index = IndexDefinition.new(table_name, pk_index_name, true, pk_index_columns)
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
- ensure # Free resources associated with the statement
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
- if stmt = IBM_DB::statistics( @connection, nil,
939
+ if stmt = IBM_DB::statistics( @connection, nil,
842
940
  @servertype.set_case(@schema),
843
941
  @servertype.set_case(table_name), 1 )
844
- begin
845
- while ( index_stats = IBM_DB::fetch_array(stmt) )
846
- is_composite = false
847
- if index_stats[5] # INDEX_NAME
848
- index_name = index_stats[5].downcase
849
- index_unique = (index_stats[3] == 0)
850
- index_columns = index_stats[8].map{|c| c.downcase} # COLUMN_NAME
851
- index_qualifier = index_stats[4] #Index_Qualifier
852
- # Create an IndexDefinition object and add to the indexes array
853
- i = 0;
854
- indexes.each do |index|
855
- if index.name == index_name && index_schema[i] == index_qualifier
856
- index.columns = "#{index.columns} , #{index_columns}"
857
- is_composite = true
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
- error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
874
- if error_msg && !error_msg.empty?
875
- raise "Failed to retrieve index metadata due to error: #{error_msg}"
876
- else
877
- raise StandardError('Unexpected error during index retrieval')
878
- end
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
- # remove the primary key index entry.... shouldnt be dumped by the dumper
978
+ # remove the primary key index entry.... should not be dumped by the dumper
882
979
 
883
- i = 0
884
- indexes.each do |index|
885
- unless index.columns == pk_index.columns
886
- index.name = "#{index_schema[i]}.#{index.name}"
887
- index_array << index
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
- end
986
+ end
891
987
  # Returns the indexes array
892
- return index_array
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, "id", :unique => true)
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
- execute "ALTER TABLE #{table_name} MODIFY #{column_name} #{@adapter.type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
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