activerecord 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (86) hide show
  1. data/CHANGELOG +34 -0
  2. data/README +0 -0
  3. data/Rakefile +6 -5
  4. data/lib/active_record.rb +8 -10
  5. data/lib/active_record/association_preload.rb +17 -12
  6. data/lib/active_record/associations.rb +45 -27
  7. data/lib/active_record/associations/association_collection.rb +8 -5
  8. data/lib/active_record/associations/association_proxy.rb +2 -6
  9. data/lib/active_record/associations/belongs_to_association.rb +0 -0
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -0
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +2 -3
  12. data/lib/active_record/associations/has_many_association.rb +16 -4
  13. data/lib/active_record/associations/has_many_through_association.rb +1 -1
  14. data/lib/active_record/associations/has_one_association.rb +2 -2
  15. data/lib/active_record/associations/has_one_through_association.rb +4 -0
  16. data/lib/active_record/base.rb +33 -15
  17. data/lib/active_record/calculations.rb +20 -7
  18. data/lib/active_record/callbacks.rb +0 -0
  19. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -6
  20. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +17 -10
  21. data/lib/active_record/connection_adapters/abstract_adapter.rb +0 -0
  22. data/lib/active_record/connection_adapters/mysql_adapter.rb +53 -24
  23. data/lib/active_record/connection_adapters/postgresql_adapter.rb +66 -20
  24. data/lib/active_record/connection_adapters/sqlite_adapter.rb +12 -0
  25. data/lib/active_record/dirty.rb +10 -3
  26. data/lib/active_record/fixtures.rb +0 -0
  27. data/lib/active_record/locking/optimistic.rb +1 -0
  28. data/lib/active_record/migration.rb +35 -8
  29. data/lib/active_record/named_scope.rb +6 -1
  30. data/lib/active_record/observer.rb +7 -5
  31. data/lib/active_record/test_case.rb +13 -2
  32. data/lib/active_record/validations.rb +19 -9
  33. data/lib/active_record/version.rb +1 -1
  34. data/test/cases/active_schema_test_postgresql.rb +2 -2
  35. data/test/cases/adapter_test.rb +1 -1
  36. data/test/cases/associations/belongs_to_associations_test.rb +19 -0
  37. data/test/cases/associations/cascaded_eager_loading_test.rb +13 -1
  38. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  39. data/test/cases/associations/eager_test.rb +25 -1
  40. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +27 -5
  41. data/test/cases/associations/has_many_associations_test.rb +106 -4
  42. data/test/cases/associations/has_many_through_associations_test.rb +10 -0
  43. data/test/cases/associations/has_one_associations_test.rb +22 -0
  44. data/test/cases/associations/has_one_through_associations_test.rb +44 -5
  45. data/test/cases/associations/join_model_test.rb +7 -0
  46. data/test/cases/associations_test.rb +2 -2
  47. data/test/cases/attribute_methods_test.rb +10 -10
  48. data/test/cases/base_test.rb +39 -16
  49. data/test/cases/calculations_test.rb +53 -1
  50. data/test/cases/column_definition_test.rb +36 -0
  51. data/test/cases/database_statements_test.rb +12 -0
  52. data/test/cases/defaults_test.rb +1 -1
  53. data/test/cases/deprecated_finder_test.rb +0 -0
  54. data/test/cases/dirty_test.rb +94 -0
  55. data/test/cases/finder_test.rb +7 -0
  56. data/test/cases/fixtures_test.rb +0 -0
  57. data/test/cases/helper.rb +5 -5
  58. data/test/cases/inheritance_test.rb +9 -2
  59. data/test/cases/lifecycle_test.rb +54 -1
  60. data/test/cases/locking_test.rb +20 -0
  61. data/test/cases/method_scoping_test.rb +11 -1
  62. data/test/cases/migration_test.rb +147 -22
  63. data/test/cases/multiple_db_test.rb +1 -1
  64. data/test/cases/named_scope_test.rb +50 -1
  65. data/test/cases/query_cache_test.rb +4 -3
  66. data/test/cases/readonly_test.rb +0 -0
  67. data/test/cases/reflection_test.rb +3 -3
  68. data/test/cases/schema_dumper_test.rb +46 -0
  69. data/test/cases/unconnected_test.rb +0 -0
  70. data/test/cases/validations_test.rb +30 -5
  71. data/test/debug.log +358 -0
  72. data/test/fixtures/fixture_database.sqlite3 +0 -0
  73. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  74. data/test/models/author.rb +4 -0
  75. data/test/models/category.rb +1 -0
  76. data/test/models/company.rb +10 -1
  77. data/test/models/developer.rb +4 -1
  78. data/test/models/person.rb +1 -1
  79. data/test/models/post.rb +6 -1
  80. data/test/models/project.rb +1 -1
  81. data/test/models/reply.rb +0 -0
  82. data/test/models/topic.rb +1 -0
  83. data/test/schema/mysql_specific_schema.rb +2 -2
  84. data/test/schema/schema.rb +8 -0
  85. metadata +11 -5
  86. data/lib/active_record/vendor/db2.rb +0 -362
@@ -1,6 +1,7 @@
1
1
  class Author < ActiveRecord::Base
2
2
  has_many :posts
3
3
  has_many :posts_with_comments, :include => :comments, :class_name => "Post"
4
+ has_many :posts_with_comments_sorted_by_comment_id, :include => :comments, :class_name => "Post", :order => 'comments.id'
4
5
  has_many :posts_with_categories, :include => :categories, :class_name => "Post"
5
6
  has_many :posts_with_comments_and_categories, :include => [ :comments, :categories ], :order => "posts.id", :class_name => "Post"
6
7
  has_many :posts_containing_the_letter_a, :class_name => "Post"
@@ -31,6 +32,9 @@ class Author < ActiveRecord::Base
31
32
  has_many :special_posts
32
33
  has_many :special_post_comments, :through => :special_posts, :source => :comments
33
34
 
35
+ has_many :sti_posts, :class_name => 'StiPost'
36
+ has_many :sti_post_comments, :through => :sti_posts, :source => :comments
37
+
34
38
  has_many :special_nonexistant_posts, :class_name => "SpecialPost", :conditions => "posts.body = 'nonexistant'"
35
39
  has_many :special_nonexistant_post_comments, :through => :special_nonexistant_posts, :source => :comments, :conditions => "comments.post_id = 0"
36
40
  has_many :nonexistant_comments, :through => :posts
@@ -2,6 +2,7 @@ class Category < ActiveRecord::Base
2
2
  has_and_belongs_to_many :posts
3
3
  has_and_belongs_to_many :special_posts, :class_name => "Post"
4
4
  has_and_belongs_to_many :other_posts, :class_name => "Post"
5
+ has_and_belongs_to_many :posts_with_authors_sorted_by_author_id, :class_name => "Post", :include => :authors, :order => "authors.id"
5
6
 
6
7
  has_and_belongs_to_many(:select_testing_posts,
7
8
  :class_name => 'Post',
@@ -18,6 +18,13 @@ end
18
18
  module Namespaced
19
19
  class Company < ::Company
20
20
  end
21
+
22
+ class Firm < ::Company
23
+ has_many :clients, :class_name => 'Namespaced::Client'
24
+ end
25
+
26
+ class Client < ::Company
27
+ end
21
28
  end
22
29
 
23
30
  class Firm < Company
@@ -26,6 +33,7 @@ class Firm < Company
26
33
  "AND (#{QUOTED_TYPE} = 'Client' OR #{QUOTED_TYPE} = 'SpecialClient' OR #{QUOTED_TYPE} = 'VerySpecialClient' )"
27
34
  has_many :clients_sorted_desc, :class_name => "Client", :order => "id DESC"
28
35
  has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id"
36
+ has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false
29
37
  has_many :dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :destroy
30
38
  has_many :exclusively_dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all
31
39
  has_many :limited_clients, :class_name => "Client", :order => "id", :limit => 1
@@ -46,7 +54,8 @@ class Firm < Company
46
54
  has_many :plain_clients, :class_name => 'Client'
47
55
  has_many :readonly_clients, :class_name => 'Client', :readonly => true
48
56
 
49
- has_one :account, :foreign_key => "firm_id", :dependent => :destroy
57
+ has_one :account, :foreign_key => "firm_id", :dependent => :destroy, :validate => true
58
+ has_one :unvalidated_account, :foreign_key => "firm_id", :class_name => 'Account', :validate => false
50
59
  has_one :account_with_select, :foreign_key => "firm_id", :select => "id, firm_id", :class_name=>'Account'
51
60
  has_one :readonly_account, :foreign_key => "firm_id", :class_name => "Account", :readonly => true
52
61
  end
@@ -43,6 +43,8 @@ class Developer < ActiveRecord::Base
43
43
 
44
44
  has_many :audit_logs
45
45
 
46
+ named_scope :jamises, :conditions => {:name => 'Jamis'}
47
+
46
48
  validates_inclusion_of :salary, :in => 50000..200000
47
49
  validates_length_of :name, :within => 3..20
48
50
 
@@ -56,7 +58,8 @@ class Developer < ActiveRecord::Base
56
58
  end
57
59
 
58
60
  class AuditLog < ActiveRecord::Base
59
- belongs_to :developer
61
+ belongs_to :developer, :validate => true
62
+ belongs_to :unvalidated_developer, :class_name => 'Developer'
60
63
  end
61
64
 
62
65
  DeveloperSalary = Struct.new(:amount)
@@ -6,5 +6,5 @@ class Person < ActiveRecord::Base
6
6
  has_many :references
7
7
  has_many :jobs, :through => :references
8
8
  has_one :favourite_reference, :class_name => 'Reference', :conditions => ['favourite=?', true]
9
-
9
+ has_many :posts_with_comments_sorted_by_comment_id, :through => :readers, :source => :post, :include => :comments, :order => 'comments.id'
10
10
  end
@@ -1,6 +1,11 @@
1
1
  class Post < ActiveRecord::Base
2
2
  named_scope :containing_the_letter_a, :conditions => "body LIKE '%a%'"
3
-
3
+ named_scope :with_authors_at_address, lambda { |address| {
4
+ :conditions => [ 'authors.author_address_id = ?', address.id ],
5
+ :joins => 'JOIN authors ON authors.id = posts.author_id'
6
+ }
7
+ }
8
+
4
9
  belongs_to :author do
5
10
  def greeting
6
11
  "hello"
@@ -7,7 +7,7 @@ class Project < ActiveRecord::Base
7
7
  has_and_belongs_to_many :developers_named_david, :class_name => "Developer", :conditions => "name = 'David'", :uniq => true
8
8
  has_and_belongs_to_many :developers_named_david_with_hash_conditions, :class_name => "Developer", :conditions => { :name => 'David' }, :uniq => true
9
9
  has_and_belongs_to_many :salaried_developers, :class_name => "Developer", :conditions => "salary > 0"
10
- has_and_belongs_to_many :developers_with_finder_sql, :class_name => "Developer", :finder_sql => 'SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id}'
10
+ has_and_belongs_to_many :developers_with_finder_sql, :class_name => "Developer", :finder_sql => 'SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id} ORDER BY t.id'
11
11
  has_and_belongs_to_many :developers_by_sql, :class_name => "Developer", :delete_sql => "DELETE FROM developers_projects WHERE project_id = \#{id} AND developer_id = \#{record.id}"
12
12
  has_and_belongs_to_many :developers_with_callbacks, :class_name => "Developer", :before_add => Proc.new {|o, r| o.developers_log << "before_adding#{r.id || '<new>'}"},
13
13
  :after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || '<new>'}"},
File without changes
@@ -4,6 +4,7 @@ class Topic < ActiveRecord::Base
4
4
  { :conditions => ['written_on < ?', time] }
5
5
  }
6
6
  named_scope :approved, :conditions => {:approved => true}
7
+ named_scope 'approved_as_string', :conditions => {:approved => true}
7
8
  named_scope :replied, :conditions => ['replies_count > 0']
8
9
  named_scope :anonymous_extension do
9
10
  def one
@@ -1,5 +1,5 @@
1
1
  ActiveRecord::Schema.define do
2
- create_table :binary_fields, :force => true do |t|
2
+ create_table :binary_fields, :force => true, :options => 'CHARACTER SET latin1' do |t|
3
3
  t.binary :tiny_blob, :limit => 255
4
4
  t.binary :normal_blob, :limit => 65535
5
5
  t.binary :medium_blob, :limit => 16777215
@@ -9,4 +9,4 @@ ActiveRecord::Schema.define do
9
9
  t.text :medium_text, :limit => 16777215
10
10
  t.text :long_text, :limit => 2147483647
11
11
  end
12
- end
12
+ end
@@ -66,6 +66,7 @@ ActiveRecord::Schema.define do
66
66
  create_table :categories, :force => true do |t|
67
67
  t.string :name, :null => false
68
68
  t.string :type
69
+ t.integer :categorizations_count
69
70
  end
70
71
 
71
72
  create_table :categories_posts, :force => true, :id => false do |t|
@@ -407,6 +408,13 @@ ActiveRecord::Schema.define do
407
408
  t.column :key, :string
408
409
  end
409
410
 
411
+ create_table :integer_limits, :force => true do |t|
412
+ t.integer :"c_int_without_limit"
413
+ (1..8).each do |i|
414
+ t.integer :"c_int_#{i}", :limit => i
415
+ end
416
+ end
417
+
410
418
  except 'SQLite' do
411
419
  # fk_test_has_fk should be before fk_test_has_pk
412
420
  create_table :fk_test_has_fk, :force => true do |t|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
@@ -9,17 +9,18 @@ autorequire: active_record
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-31 00:00:00 -07:00
12
+ date: 2008-09-04 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
20
21
  - - "="
21
22
  - !ruby/object:Gem::Version
22
- version: 2.1.0
23
+ version: 2.1.1
23
24
  version:
24
25
  description: Implements the ActiveRecord pattern (Fowler, PoEAA) for ORM. It ties database tables and classes together for business objects, like Customer or Subscription, that can find, save, and destroy themselves without resorting to manual SQL.
25
26
  email: david@loudthinking.com
@@ -87,7 +88,6 @@ files:
87
88
  - lib/active_record/transactions.rb
88
89
  - lib/active_record/validations.rb
89
90
  - lib/active_record/vendor
90
- - lib/active_record/vendor/db2.rb
91
91
  - lib/active_record/vendor/mysql.rb
92
92
  - lib/active_record/version.rb
93
93
  - lib/active_record.rb
@@ -107,6 +107,7 @@ files:
107
107
  - test/cases/associations/belongs_to_associations_test.rb
108
108
  - test/cases/associations/callbacks_test.rb
109
109
  - test/cases/associations/cascaded_eager_loading_test.rb
110
+ - test/cases/associations/eager_load_includes_full_sti_class_test.rb
110
111
  - test/cases/associations/eager_load_nested_include_test.rb
111
112
  - test/cases/associations/eager_singularization_test.rb
112
113
  - test/cases/associations/eager_test.rb
@@ -126,9 +127,11 @@ files:
126
127
  - test/cases/callbacks_test.rb
127
128
  - test/cases/class_inheritable_attributes_test.rb
128
129
  - test/cases/column_alias_test.rb
130
+ - test/cases/column_definition_test.rb
129
131
  - test/cases/connection_test_firebird.rb
130
132
  - test/cases/connection_test_mysql.rb
131
133
  - test/cases/copy_table_test_sqlite.rb
134
+ - test/cases/database_statements_test.rb
132
135
  - test/cases/datatype_test_postgresql.rb
133
136
  - test/cases/date_time_test.rb
134
137
  - test/cases/default_test_firebird.rb
@@ -190,6 +193,7 @@ files:
190
193
  - test/connections/native_sqlite3/in_memory_connection.rb
191
194
  - test/connections/native_sybase
192
195
  - test/connections/native_sybase/connection.rb
196
+ - test/debug.log
193
197
  - test/fixtures
194
198
  - test/fixtures/accounts.yml
195
199
  - test/fixtures/all
@@ -219,6 +223,8 @@ files:
219
223
  - test/fixtures/developers_projects.yml
220
224
  - test/fixtures/edges.yml
221
225
  - test/fixtures/entrants.yml
226
+ - test/fixtures/fixture_database.sqlite3
227
+ - test/fixtures/fixture_database_2.sqlite3
222
228
  - test/fixtures/fk_test_has_fk.yml
223
229
  - test/fixtures/fk_test_has_pk.yml
224
230
  - test/fixtures/funny_jokes.yml
@@ -385,7 +391,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
385
391
  requirements: []
386
392
 
387
393
  rubyforge_project: activerecord
388
- rubygems_version: 1.0.1
394
+ rubygems_version: 1.2.0
389
395
  signing_key:
390
396
  specification_version: 2
391
397
  summary: Implements the ActiveRecord pattern for ORM.
@@ -1,362 +0,0 @@
1
- require 'db2/db2cli.rb'
2
-
3
- module DB2
4
- module DB2Util
5
- include DB2CLI
6
-
7
- def free() SQLFreeHandle(@handle_type, @handle); end
8
- def handle() @handle; end
9
-
10
- def check_rc(rc)
11
- if ![SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA_FOUND].include?(rc)
12
- rec = 1
13
- msg = ''
14
- loop do
15
- a = SQLGetDiagRec(@handle_type, @handle, rec, 500)
16
- break if a[0] != SQL_SUCCESS
17
- msg << a[3] if !a[3].nil? and a[3] != '' # Create message.
18
- rec += 1
19
- end
20
- raise "DB2 error: #{msg}"
21
- end
22
- end
23
- end
24
-
25
- class Environment
26
- include DB2Util
27
-
28
- def initialize
29
- @handle_type = SQL_HANDLE_ENV
30
- rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE)
31
- check_rc(rc)
32
- end
33
-
34
- def data_sources(buffer_length = 1024)
35
- retval = []
36
- max_buffer_length = buffer_length
37
-
38
- a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length)
39
- retval << [a[1], a[3]]
40
- max_buffer_length = [max_buffer_length, a[4]].max
41
-
42
- loop do
43
- a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length)
44
- break if a[0] == SQL_NO_DATA_FOUND
45
-
46
- retval << [a[1], a[3]]
47
- max_buffer_length = [max_buffer_length, a[4]].max
48
- end
49
-
50
- if max_buffer_length > buffer_length
51
- get_data_sources(max_buffer_length)
52
- else
53
- retval
54
- end
55
- end
56
- end
57
-
58
- class Connection
59
- include DB2Util
60
-
61
- def initialize(environment)
62
- @env = environment
63
- @handle_type = SQL_HANDLE_DBC
64
- rc, @handle = SQLAllocHandle(@handle_type, @env.handle)
65
- check_rc(rc)
66
- end
67
-
68
- def connect(server_name, user_name = '', auth = '')
69
- check_rc(SQLConnect(@handle, server_name, user_name.to_s, auth.to_s))
70
- end
71
-
72
- def set_connect_attr(attr, value)
73
- value += "\0" if value.class == String
74
- check_rc(SQLSetConnectAttr(@handle, attr, value))
75
- end
76
-
77
- def set_auto_commit_on
78
- set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
79
- end
80
-
81
- def set_auto_commit_off
82
- set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF)
83
- end
84
-
85
- def disconnect
86
- check_rc(SQLDisconnect(@handle))
87
- end
88
-
89
- def rollback
90
- check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK))
91
- end
92
-
93
- def commit
94
- check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT))
95
- end
96
- end
97
-
98
- class Statement
99
- include DB2Util
100
-
101
- def initialize(connection)
102
- @conn = connection
103
- @handle_type = SQL_HANDLE_STMT
104
- @parms = [] #yun
105
- @sql = '' #yun
106
- @numParms = 0 #yun
107
- @prepared = false #yun
108
- @parmArray = [] #yun. attributes of the parameter markers
109
- rc, @handle = SQLAllocHandle(@handle_type, @conn.handle)
110
- check_rc(rc)
111
- end
112
-
113
- def columns(table_name, schema_name = '%')
114
- check_rc(SQLColumns(@handle, '', schema_name.upcase, table_name.upcase, '%'))
115
- fetch_all
116
- end
117
-
118
- def tables(schema_name = '%')
119
- check_rc(SQLTables(@handle, '', schema_name.upcase, '%', 'TABLE'))
120
- fetch_all
121
- end
122
-
123
- def indexes(table_name, schema_name = '')
124
- check_rc(SQLStatistics(@handle, '', schema_name.upcase, table_name.upcase, SQL_INDEX_ALL, SQL_ENSURE))
125
- fetch_all
126
- end
127
-
128
- def prepare(sql)
129
- @sql = sql
130
- check_rc(SQLPrepare(@handle, sql))
131
- rc, @numParms = SQLNumParams(@handle) #number of question marks
132
- check_rc(rc)
133
- #--------------------------------------------------------------------------
134
- # parameter attributes are stored in instance variable @parmArray so that
135
- # they are available when execute method is called.
136
- #--------------------------------------------------------------------------
137
- if @numParms > 0 # get parameter marker attributes
138
- 1.upto(@numParms) do |i| # parameter number starts from 1
139
- rc, type, size, decimalDigits = SQLDescribeParam(@handle, i)
140
- check_rc(rc)
141
- @parmArray << Parameter.new(type, size, decimalDigits)
142
- end
143
- end
144
- @prepared = true
145
- self
146
- end
147
-
148
- def execute(*parms)
149
- raise "The statement was not prepared" if @prepared == false
150
-
151
- if parms.size == 1 and parms[0].class == Array
152
- parms = parms[0]
153
- end
154
-
155
- if @numParms != parms.size
156
- raise "Number of parameters supplied does not match with the SQL statement"
157
- end
158
-
159
- if @numParms > 0 #need to bind parameters
160
- #--------------------------------------------------------------------
161
- #calling bindParms may not be safe. Look comment below.
162
- #--------------------------------------------------------------------
163
- #bindParms(parms)
164
-
165
- valueArray = []
166
- 1.upto(@numParms) do |i| # parameter number starts from 1
167
- type = @parmArray[i - 1].class
168
- size = @parmArray[i - 1].size
169
- decimalDigits = @parmArray[i - 1].decimalDigits
170
-
171
- if parms[i - 1].class == String
172
- valueArray << parms[i - 1]
173
- else
174
- valueArray << parms[i - 1].to_s
175
- end
176
-
177
- rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1])
178
- check_rc(rc)
179
- end
180
- end
181
-
182
- check_rc(SQLExecute(@handle))
183
-
184
- if @numParms != 0
185
- check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters
186
- end
187
-
188
- self
189
- end
190
-
191
- #-------------------------------------------------------------------------------
192
- # The last argument(value) to SQLBindParameter is a deferred argument, that is,
193
- # it should be available when SQLExecute is called. Even though "value" is
194
- # local to bindParms method, it seems that it is available when SQLExecute
195
- # is called. I am not sure whether it would still work if garbage collection
196
- # is done between bindParms call and SQLExecute call inside the execute method
197
- # above.
198
- #-------------------------------------------------------------------------------
199
- def bindParms(parms) # This is the real thing. It uses SQLBindParms
200
- 1.upto(@numParms) do |i| # parameter number starts from 1
201
- rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i)
202
- check_rc(rc)
203
- if parms[i - 1].class == String
204
- value = parms[i - 1]
205
- else
206
- value = parms[i - 1].to_s
207
- end
208
- rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value)
209
- check_rc(rc)
210
- end
211
- end
212
-
213
- #------------------------------------------------------------------------------
214
- # bind method does not use DB2's SQLBindParams, but replaces "?" in the
215
- # SQL statement with the value before passing the SQL statement to DB2.
216
- # It is not efficient and can handle only strings since it puts everything in
217
- # quotes.
218
- #------------------------------------------------------------------------------
219
- def bind(sql, args) #does not use SQLBindParams
220
- arg_index = 0
221
- result = ""
222
- tokens(sql).each do |part|
223
- case part
224
- when '?'
225
- result << "'" + (args[arg_index]) + "'" #put it into quotes
226
- arg_index += 1
227
- when '??'
228
- result << "?"
229
- else
230
- result << part
231
- end
232
- end
233
- if arg_index < args.size
234
- raise "Too many SQL parameters"
235
- elsif arg_index > args.size
236
- raise "Not enough SQL parameters"
237
- end
238
- result
239
- end
240
-
241
- ## Break the sql string into parts.
242
- #
243
- # This is NOT a full lexer for SQL. It just breaks up the SQL
244
- # string enough so that question marks, double question marks and
245
- # quoted strings are separated. This is used when binding
246
- # arguments to "?" in the SQL string. Note: comments are not
247
- # handled.
248
- #
249
- def tokens(sql)
250
- toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/)
251
- toks.collect { |t| t[0] }
252
- end
253
-
254
- def exec_direct(sql)
255
- check_rc(SQLExecDirect(@handle, sql))
256
- self
257
- end
258
-
259
- def set_cursor_name(name)
260
- check_rc(SQLSetCursorName(@handle, name))
261
- self
262
- end
263
-
264
- def get_cursor_name
265
- rc, name = SQLGetCursorName(@handle)
266
- check_rc(rc)
267
- name
268
- end
269
-
270
- def row_count
271
- rc, rowcount = SQLRowCount(@handle)
272
- check_rc(rc)
273
- rowcount
274
- end
275
-
276
- def num_result_cols
277
- rc, cols = SQLNumResultCols(@handle)
278
- check_rc(rc)
279
- cols
280
- end
281
-
282
- def fetch_all
283
- if block_given?
284
- while row = fetch do
285
- yield row
286
- end
287
- else
288
- res = []
289
- while row = fetch do
290
- res << row
291
- end
292
- res
293
- end
294
- end
295
-
296
- def fetch
297
- cols = get_col_desc
298
- rc = SQLFetch(@handle)
299
- if rc == SQL_NO_DATA_FOUND
300
- SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
301
- SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
302
- return nil
303
- end
304
- raise "ERROR" unless rc == SQL_SUCCESS
305
-
306
- retval = []
307
- cols.each_with_index do |c, i|
308
- rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
309
- retval << adjust_content(content)
310
- end
311
- retval
312
- end
313
-
314
- def fetch_as_hash
315
- cols = get_col_desc
316
- rc = SQLFetch(@handle)
317
- if rc == SQL_NO_DATA_FOUND
318
- SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
319
- SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
320
- return nil
321
- end
322
- raise "ERROR" unless rc == SQL_SUCCESS
323
-
324
- retval = {}
325
- cols.each_with_index do |c, i|
326
- rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
327
- retval[c[0]] = adjust_content(content)
328
- end
329
- retval
330
- end
331
-
332
- def get_col_desc
333
- rc, nr_cols = SQLNumResultCols(@handle)
334
- cols = (1..nr_cols).collect do |c|
335
- rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024)
336
- [name.downcase, type, col_sz]
337
- end
338
- end
339
-
340
- def adjust_content(c)
341
- case c.class.to_s
342
- when 'DB2CLI::NullClass'
343
- return nil
344
- when 'DB2CLI::Time'
345
- "%02d:%02d:%02d" % [c.hour, c.minute, c.second]
346
- when 'DB2CLI::Date'
347
- "%04d-%02d-%02d" % [c.year, c.month, c.day]
348
- when 'DB2CLI::Timestamp'
349
- "%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second]
350
- else
351
- return c
352
- end
353
- end
354
- end
355
-
356
- class Parameter
357
- attr_reader :type, :size, :decimalDigits
358
- def initialize(type, size, decimalDigits)
359
- @type, @size, @decimalDigits = type, size, decimalDigits
360
- end
361
- end
362
- end