ibm_db 0.9.4 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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