ibm_db 0.4.0 → 0.4.6

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/ext/ruby_ibm_db.h CHANGED
@@ -1,164 +1,164 @@
1
- /*
2
- +----------------------------------------------------------------------+
3
- | Licensed Materials - Property of IBM |
4
- | |
5
- | (C) Copyright IBM Corporation 2007. |
6
- +----------------------------------------------------------------------+
7
- | Authors: Sushant Koduru, Lynh Nguyen, Kanchana Padmanabhan, |
8
- | Dan Scott, Helmut Tessarek, Kellen Bombardier, Sam Ruby |
9
- +----------------------------------------------------------------------+
10
- */
11
-
12
- #ifndef RUBY_IBM_DB_H
13
- #define RUBY_IBM_DB_H
14
-
15
- #include <stdio.h>
16
- #include <string.h>
17
- #include <stdlib.h>
18
- #include <sqlcli1.h>
19
-
20
- #ifndef SQL_XML
21
- #define SQL_XML -370
22
- #endif
23
-
24
- #ifndef SQL_ATTR_REPLACE_QUOTED_LITERALS
25
- #define SQL_ATTR_REPLACE_QUOTED_LITERALS 116
26
- #endif
27
-
28
- #ifdef _WIN32
29
- #define RUBY_IBM_DB_API __declspec(dllexport)
30
- #else
31
- #define RUBY_IBM_DB_API
32
- #endif
33
-
34
- /* strlen(" SQLCODE=") added in */
35
- #define DB2_MAX_ERR_MSG_LEN (SQL_MAX_MESSAGE_LENGTH + SQL_SQLSTATE_SIZE + 10)
36
-
37
- /* Used in _ruby_parse_options */
38
- #define DB2_ERRMSG 1
39
- #define DB2_ERR 2
40
-
41
- /* DB2 instance environment variable */
42
- #define DB2_VAR_INSTANCE "DB2INSTANCE="
43
-
44
- /******** Makes code compatible with the options used by the user */
45
- #define BINARY 1
46
- #define CONVERT 2
47
- #define PASSTHRU 3
48
- #define PARAM_FILE 11
49
-
50
- #ifdef PASE
51
- #define SQL_IS_INTEGER 0
52
- #define SQL_BEST_ROWID 0
53
- #define SQLLEN long
54
- #define SQLFLOAT double
55
- #endif
56
-
57
- /*fetch*/
58
- #define FETCH_INDEX 0x01
59
- #define FETCH_ASSOC 0x02
60
- #define FETCH_BOTH 0x03
61
-
62
- /* Change column case */
63
- #define ATTR_CASE 3271982
64
- #define CASE_NATURAL 0
65
- #define CASE_LOWER 1
66
- #define CASE_UPPER 2
67
-
68
- /* maximum sizes */
69
- #define USERID_LEN 16
70
- #define ACCTSTR_LEN 200
71
- #define APPLNAME_LEN 32
72
- #define WRKSTNNAME_LEN 18
73
-
74
- void Init_ibm_db();
75
-
76
- VALUE ibm_db_connect(int argc, VALUE *argv, VALUE self);
77
- VALUE ibm_db_commit(int argc, VALUE *argv, VALUE self);
78
- VALUE ibm_db_pconnect(int argc, VALUE *argv, VALUE self);
79
- VALUE ibm_db_autocommit(int argc, VALUE *argv, VALUE self);
80
- VALUE ibm_db_bind_param(int argc, VALUE *argv, VALUE self);
81
- VALUE ibm_db_close(int argc, VALUE *argv, VALUE self);
82
- VALUE ibm_db_columnprivileges(int argc, VALUE *argv, VALUE self);
83
- VALUE ibm_db_column_privileges(int argc, VALUE *argv, VALUE self);
84
- VALUE ibm_db_columns(int argc, VALUE *argv, VALUE self);
85
- VALUE ibm_db_foreignkeys(int argc, VALUE *argv, VALUE self);
86
- VALUE ibm_db_foreign_keys(int argc, VALUE *argv, VALUE self);
87
- VALUE ibm_db_primarykeys(int argc, VALUE *argv, VALUE self);
88
- VALUE ibm_db_primary_keys(int argc, VALUE *argv, VALUE self);
89
- VALUE ibm_db_procedure_columns(int argc, VALUE *argv, VALUE self);
90
- VALUE ibm_db_procedures(int argc, VALUE *argv, VALUE self);
91
- VALUE ibm_db_specialcolumns(int argc, VALUE *argv, VALUE self);
92
- VALUE ibm_db_special_columns(int argc, VALUE *argv, VALUE self);
93
- VALUE ibm_db_statistics(int argc, VALUE *argv, VALUE self);
94
- VALUE ibm_db_tableprivileges(int argc, VALUE *argv, VALUE self);
95
- VALUE ibm_db_table_privileges(int argc, VALUE *argv, VALUE self);
96
- VALUE ibm_db_tables(int argc, VALUE *argv, VALUE self);
97
- VALUE ibm_db_commit(int argc, VALUE *argv, VALUE self);
98
- VALUE ibm_db_exec(int argc, VALUE *argv, VALUE self);
99
- VALUE ibm_db_prepare(int argc, VALUE *argv, VALUE self);
100
- VALUE ibm_db_execute(int argc, VALUE *argv, VALUE self);
101
- VALUE ibm_db_conn_errormsg(int argc, VALUE *argv, VALUE self);
102
- VALUE ibm_db_stmt_errormsg(int argc, VALUE *argv, VALUE self);
103
- VALUE ibm_db_conn_error(int argc, VALUE *argv, VALUE self);
104
- VALUE ibm_db_stmt_error(int argc, VALUE *argv, VALUE self);
105
- VALUE ibm_db_next_result(int argc, VALUE *argv, VALUE self);
106
- VALUE ibm_db_num_fields(int argc, VALUE *argv, VALUE self);
107
- VALUE ibm_db_num_rows(int argc, VALUE *argv, VALUE self);
108
- VALUE ibm_db_field_name(int argc, VALUE *argv, VALUE self);
109
- VALUE ibm_db_field_display_size(int argc, VALUE *argv, VALUE self);
110
- VALUE ibm_db_field_num(int argc, VALUE *argv, VALUE self);
111
- VALUE ibm_db_field_precision(int argc, VALUE *argv, VALUE self);
112
- VALUE ibm_db_field_scale(int argc, VALUE *argv, VALUE self);
113
- VALUE ibm_db_field_type(int argc, VALUE *argv, VALUE self);
114
- VALUE ibm_db_field_width(int argc, VALUE *argv, VALUE self);
115
- VALUE ibm_db_cursor_type(int argc, VALUE *argv, VALUE self);
116
- VALUE ibm_db_rollback(int argc, VALUE *argv, VALUE self);
117
- VALUE ibm_db_free_stmt(int argc, VALUE *argv, VALUE self);
118
- VALUE ibm_db_result(int argc, VALUE *argv, VALUE self);
119
- VALUE ibm_db_fetch_row(int argc, VALUE *argv, VALUE self);
120
- VALUE ibm_db_fetch_assoc(int argc, VALUE *argv, VALUE self);
121
- VALUE ibm_db_fetch_array(int argc, VALUE *argv, VALUE self);
122
- VALUE ibm_db_fetch_both(int argc, VALUE *argv, VALUE self);
123
- VALUE ibm_db_result_all(int argc, VALUE *argv, VALUE self);
124
- VALUE ibm_db_free_result(int argc, VALUE *argv, VALUE self);
125
- VALUE ibm_db_set_option(int argc, VALUE *argv, VALUE self);
126
- VALUE ibm_db_setoption(int argc, VALUE *argv, VALUE self);
127
- VALUE ibm_db_get_option(int argc, VALUE *argv, VALUE self);
128
- VALUE ibm_db_getoption(int argc, VALUE *argv, VALUE self);
129
- VALUE ibm_db_fetch_object(int argc, VALUE *argv, VALUE self);
130
- VALUE ibm_db_server_info(int argc, VALUE *argv, VALUE self);
131
- VALUE ibm_db_client_info(int argc, VALUE *argv, VALUE self);
132
- VALUE ibm_db_active(int argc, VALUE *argv, VALUE self);
133
-
134
- /*
135
- Declare any global variables you may need between the BEGIN
136
- and END macros here:
137
- */
138
- struct _ibm_db_globals {
139
- int bin_mode;
140
- char __ruby_conn_err_msg[DB2_MAX_ERR_MSG_LEN];
141
- char __ruby_conn_err_state[SQL_SQLSTATE_SIZE + 1];
142
- char __ruby_stmt_err_msg[DB2_MAX_ERR_MSG_LEN];
143
- char __ruby_stmt_err_state[SQL_SQLSTATE_SIZE + 1];
144
- #ifdef PASE /* i5/OS ease of use turn off commit */
145
- long i5_allow_commit;
146
- #endif /* PASE */
147
- };
148
-
149
- /*
150
- TODO: make this threadsafe
151
- */
152
-
153
- #define IBM_DB_G(v) (ibm_db_globals->v)
154
-
155
- #endif /* RUBY_IBM_DB_H */
156
-
157
-
158
- /*
159
- * Local variables:
160
- * tab-width: 4
161
- * c-basic-offset: 4
162
- * indent-tabs-mode: t
163
- * End:
164
- */
1
+ /*
2
+ +----------------------------------------------------------------------+
3
+ | Licensed Materials - Property of IBM |
4
+ | |
5
+ | (C) Copyright IBM Corporation 2006, 2007. |
6
+ +----------------------------------------------------------------------+
7
+ | Authors: Sushant Koduru, Lynh Nguyen, Kanchana Padmanabhan, |
8
+ | Dan Scott, Helmut Tessarek, Kellen Bombardier, Sam Ruby |
9
+ +----------------------------------------------------------------------+
10
+ */
11
+
12
+ #ifndef RUBY_IBM_DB_H
13
+ #define RUBY_IBM_DB_H
14
+
15
+ #include <stdio.h>
16
+ #include <string.h>
17
+ #include <stdlib.h>
18
+ #include <sqlcli1.h>
19
+
20
+ #ifndef SQL_XML
21
+ #define SQL_XML -370
22
+ #endif
23
+
24
+ #ifndef SQL_ATTR_REPLACE_QUOTED_LITERALS
25
+ #define SQL_ATTR_REPLACE_QUOTED_LITERALS 116
26
+ #endif
27
+
28
+ #ifdef _WIN32
29
+ #define RUBY_IBM_DB_API __declspec(dllexport)
30
+ #else
31
+ #define RUBY_IBM_DB_API
32
+ #endif
33
+
34
+ /* strlen(" SQLCODE=") added in */
35
+ #define DB2_MAX_ERR_MSG_LEN (SQL_MAX_MESSAGE_LENGTH + SQL_SQLSTATE_SIZE + 10)
36
+
37
+ /* Used in _ruby_parse_options */
38
+ #define DB2_ERRMSG 1
39
+ #define DB2_ERR 2
40
+
41
+ /* DB2 instance environment variable */
42
+ #define DB2_VAR_INSTANCE "DB2INSTANCE="
43
+
44
+ /******** Makes code compatible with the options used by the user */
45
+ #define BINARY 1
46
+ #define CONVERT 2
47
+ #define PASSTHRU 3
48
+ #define PARAM_FILE 11
49
+
50
+ #ifdef PASE
51
+ #define SQL_IS_INTEGER 0
52
+ #define SQL_BEST_ROWID 0
53
+ #define SQLLEN long
54
+ #define SQLFLOAT double
55
+ #endif
56
+
57
+ /*fetch*/
58
+ #define FETCH_INDEX 0x01
59
+ #define FETCH_ASSOC 0x02
60
+ #define FETCH_BOTH 0x03
61
+
62
+ /* Change column case */
63
+ #define ATTR_CASE 3271982
64
+ #define CASE_NATURAL 0
65
+ #define CASE_LOWER 1
66
+ #define CASE_UPPER 2
67
+
68
+ /* maximum sizes */
69
+ #define USERID_LEN 16
70
+ #define ACCTSTR_LEN 200
71
+ #define APPLNAME_LEN 32
72
+ #define WRKSTNNAME_LEN 18
73
+
74
+ void Init_ibm_db();
75
+
76
+ VALUE ibm_db_connect(int argc, VALUE *argv, VALUE self);
77
+ VALUE ibm_db_commit(int argc, VALUE *argv, VALUE self);
78
+ VALUE ibm_db_pconnect(int argc, VALUE *argv, VALUE self);
79
+ VALUE ibm_db_autocommit(int argc, VALUE *argv, VALUE self);
80
+ VALUE ibm_db_bind_param(int argc, VALUE *argv, VALUE self);
81
+ VALUE ibm_db_close(int argc, VALUE *argv, VALUE self);
82
+ VALUE ibm_db_columnprivileges(int argc, VALUE *argv, VALUE self);
83
+ VALUE ibm_db_column_privileges(int argc, VALUE *argv, VALUE self);
84
+ VALUE ibm_db_columns(int argc, VALUE *argv, VALUE self);
85
+ VALUE ibm_db_foreignkeys(int argc, VALUE *argv, VALUE self);
86
+ VALUE ibm_db_foreign_keys(int argc, VALUE *argv, VALUE self);
87
+ VALUE ibm_db_primarykeys(int argc, VALUE *argv, VALUE self);
88
+ VALUE ibm_db_primary_keys(int argc, VALUE *argv, VALUE self);
89
+ VALUE ibm_db_procedure_columns(int argc, VALUE *argv, VALUE self);
90
+ VALUE ibm_db_procedures(int argc, VALUE *argv, VALUE self);
91
+ VALUE ibm_db_specialcolumns(int argc, VALUE *argv, VALUE self);
92
+ VALUE ibm_db_special_columns(int argc, VALUE *argv, VALUE self);
93
+ VALUE ibm_db_statistics(int argc, VALUE *argv, VALUE self);
94
+ VALUE ibm_db_tableprivileges(int argc, VALUE *argv, VALUE self);
95
+ VALUE ibm_db_table_privileges(int argc, VALUE *argv, VALUE self);
96
+ VALUE ibm_db_tables(int argc, VALUE *argv, VALUE self);
97
+ VALUE ibm_db_commit(int argc, VALUE *argv, VALUE self);
98
+ VALUE ibm_db_exec(int argc, VALUE *argv, VALUE self);
99
+ VALUE ibm_db_prepare(int argc, VALUE *argv, VALUE self);
100
+ VALUE ibm_db_execute(int argc, VALUE *argv, VALUE self);
101
+ VALUE ibm_db_conn_errormsg(int argc, VALUE *argv, VALUE self);
102
+ VALUE ibm_db_stmt_errormsg(int argc, VALUE *argv, VALUE self);
103
+ VALUE ibm_db_conn_error(int argc, VALUE *argv, VALUE self);
104
+ VALUE ibm_db_stmt_error(int argc, VALUE *argv, VALUE self);
105
+ VALUE ibm_db_next_result(int argc, VALUE *argv, VALUE self);
106
+ VALUE ibm_db_num_fields(int argc, VALUE *argv, VALUE self);
107
+ VALUE ibm_db_num_rows(int argc, VALUE *argv, VALUE self);
108
+ VALUE ibm_db_field_name(int argc, VALUE *argv, VALUE self);
109
+ VALUE ibm_db_field_display_size(int argc, VALUE *argv, VALUE self);
110
+ VALUE ibm_db_field_num(int argc, VALUE *argv, VALUE self);
111
+ VALUE ibm_db_field_precision(int argc, VALUE *argv, VALUE self);
112
+ VALUE ibm_db_field_scale(int argc, VALUE *argv, VALUE self);
113
+ VALUE ibm_db_field_type(int argc, VALUE *argv, VALUE self);
114
+ VALUE ibm_db_field_width(int argc, VALUE *argv, VALUE self);
115
+ VALUE ibm_db_cursor_type(int argc, VALUE *argv, VALUE self);
116
+ VALUE ibm_db_rollback(int argc, VALUE *argv, VALUE self);
117
+ VALUE ibm_db_free_stmt(int argc, VALUE *argv, VALUE self);
118
+ VALUE ibm_db_result(int argc, VALUE *argv, VALUE self);
119
+ VALUE ibm_db_fetch_row(int argc, VALUE *argv, VALUE self);
120
+ VALUE ibm_db_fetch_assoc(int argc, VALUE *argv, VALUE self);
121
+ VALUE ibm_db_fetch_array(int argc, VALUE *argv, VALUE self);
122
+ VALUE ibm_db_fetch_both(int argc, VALUE *argv, VALUE self);
123
+ VALUE ibm_db_result_all(int argc, VALUE *argv, VALUE self);
124
+ VALUE ibm_db_free_result(int argc, VALUE *argv, VALUE self);
125
+ VALUE ibm_db_set_option(int argc, VALUE *argv, VALUE self);
126
+ VALUE ibm_db_setoption(int argc, VALUE *argv, VALUE self);
127
+ VALUE ibm_db_get_option(int argc, VALUE *argv, VALUE self);
128
+ VALUE ibm_db_getoption(int argc, VALUE *argv, VALUE self);
129
+ VALUE ibm_db_fetch_object(int argc, VALUE *argv, VALUE self);
130
+ VALUE ibm_db_server_info(int argc, VALUE *argv, VALUE self);
131
+ VALUE ibm_db_client_info(int argc, VALUE *argv, VALUE self);
132
+ VALUE ibm_db_active(int argc, VALUE *argv, VALUE self);
133
+
134
+ /*
135
+ Declare any global variables you may need between the BEGIN
136
+ and END macros here:
137
+ */
138
+ struct _ibm_db_globals {
139
+ int bin_mode;
140
+ char __ruby_conn_err_msg[DB2_MAX_ERR_MSG_LEN];
141
+ char __ruby_conn_err_state[SQL_SQLSTATE_SIZE + 1];
142
+ char __ruby_stmt_err_msg[DB2_MAX_ERR_MSG_LEN];
143
+ char __ruby_stmt_err_state[SQL_SQLSTATE_SIZE + 1];
144
+ #ifdef PASE /* i5/OS ease of use turn off commit */
145
+ long i5_allow_commit;
146
+ #endif /* PASE */
147
+ };
148
+
149
+ /*
150
+ TODO: make this threadsafe
151
+ */
152
+
153
+ #define IBM_DB_G(v) (ibm_db_globals->v)
154
+
155
+ #endif /* RUBY_IBM_DB_H */
156
+
157
+
158
+ /*
159
+ * Local variables:
160
+ * tab-width: 4
161
+ * c-basic-offset: 4
162
+ * indent-tabs-mode: t
163
+ * End:
164
+ */
@@ -42,7 +42,7 @@ module ActiveRecord
42
42
  end
43
43
 
44
44
  update_query << ") = "
45
- # IBM DB accepts 'SET (column) = NULL' but not (NULL),
45
+ # IBM_DB accepts 'SET (column) = NULL' but not (NULL),
46
46
  # therefore the sql needs to be changed for a single NULL field.
47
47
  if params.size==1 && params[0] == 'NULL'
48
48
  update_query << "NULL"
@@ -72,7 +72,7 @@ module ActiveRecord
72
72
  begin
73
73
  require 'ibm_db' unless defined? IBM_DB
74
74
  rescue LoadError
75
- raise LoadError, "Failed to load IBM DB Ruby driver."
75
+ raise LoadError, "Failed to load IBM_DB Ruby driver."
76
76
  end
77
77
 
78
78
  # Converts all +config+ keys to symbols
@@ -104,7 +104,7 @@ module ActiveRecord
104
104
  # Retrieve database objects fields in lowercase
105
105
  conn_options = {IBM_DB::ATTR_CASE => IBM_DB::CASE_LOWER}
106
106
  # Set connection's user info
107
- conn_options[:user] = config[:user].to_s if config.has_key?(:user)
107
+ conn_options[:app_user] = config[:app_user].to_s if config.has_key?(:app_user)
108
108
  # Set connection's account info
109
109
  conn_options[:account] = config[:account].to_s if config.has_key?(:account)
110
110
  # Set connection's application info
@@ -136,7 +136,7 @@ module ActiveRecord
136
136
  ConnectionAdapters::IBM_DBAdapter.new(connection, logger, config, conn_options)
137
137
  else
138
138
  # If the connection failed, it raises a Runtime error
139
- raise "Failed to connect to the #{database} due to: #{IBM_DB::conn_errormsg}"
139
+ raise "Failed to connect to the [#{database}] due to: #{IBM_DB::conn_errormsg}"
140
140
  end
141
141
  end # method self.ibm_db_connection
142
142
  end # class Base
@@ -159,7 +159,7 @@ module ActiveRecord
159
159
  end
160
160
 
161
161
  private
162
- # Mapping IBM DB SQL datatypes to Ruby data types
162
+ # Mapping IBM data servers SQL datatypes to Ruby data types
163
163
  def simplified_type(field_type)
164
164
  case field_type
165
165
  # if +field_type+ contains 'for bit data' handle it as a binary
@@ -189,40 +189,37 @@ module ActiveRecord
189
189
  :string
190
190
  when /boolean/i
191
191
  :boolean
192
+ when /rowid/i # rowid is a supported datatype on z/OS and i/5
193
+ :rowid
192
194
  end
193
-
194
195
  end # method simplified_type
195
196
  end #class IBM_DBColumn
196
197
 
197
198
 
198
- # The IBM_DB Adapter requires the native Ruby Driver for IBM Databases (ibm_db.so).
199
- # +config+ is a hash passed as an argument to the class initializer.
200
- # Connection parameters can be specified in 2 different ways:
201
- # Local connection (through a database catalog alias):
202
- # ==== Example
203
- # adapter: ibm_db
204
- # database: SAMPLE
205
- # username: user
206
- # password: pass
207
- # schema: myschema
208
- #
209
- # Remote TCP/IP connection:
210
- # ==== Example
211
- # adapter: ibm_db
212
- # database: SAMPLE
213
- # username: user
214
- # password: pass
215
- # schema: myschema
216
- # host: my_hostname_or_address
217
- # port: 50000
218
- #
219
- # 'SAMPLE' is the database alias as it appears in the local IBM DB catalog
220
- # Once you pick the type of connection you want to use, you need to fill-in all the fields above, as shown in the example.
221
- # The current version allows you to set only one schema. If you don't specify a schema, the username is used as a schema.
199
+ # The IBM_DB Adapter requires the native Ruby driver (ibm_db)
200
+ # for IBM data servers (ibm_db.so).
201
+ # +config+ the hash passed as an initializer argument content:
202
+ # == mandatory parameters
203
+ # adapter: 'ibm_db' // IBM_DB Adapter name
204
+ # username: 'db2user' // data server (database) user
205
+ # password: 'secret' // data server (database) password
206
+ # database: 'ARUNIT' // remote database name (or catalog entry alias)
207
+ # == optional (highly recommended for data server auditing and monitoring purposes)
208
+ # schema: 'rails123' // name space qualifier
209
+ # account: 'tester' // OS account (client workstation)
210
+ # app_user: 'test11' // authenticated application user
211
+ # application: 'rtests' // application name
212
+ # workstation: 'plato' // client workstation name
213
+ # == remote TCP/IP connection (required when no local database catalog entry available)
214
+ # host: 'socrates' // fully qualified hostname or IP address
215
+ # port: '50000' // data server TCP/IP port number
216
+ #
217
+ # When schema is not specified, the username value is used instead.
218
+ #
222
219
  class IBM_DBAdapter < AbstractAdapter
223
220
  attr_reader :connection
224
221
  attr_accessor :sql
225
- attr_reader :schema, :user, :account, :application, :workstation
222
+ attr_reader :schema, :app_user, :account, :application, :workstation
226
223
 
227
224
  # Name of the adapter
228
225
  def adapter_name
@@ -231,6 +228,8 @@ module ActiveRecord
231
228
 
232
229
  def initialize(connection, logger, config, conn_options)
233
230
  # Caching database connection configuration (+connect+ or +reconnect+ support)
231
+ @connection = connection
232
+ @conn_options = conn_options
234
233
  @database = config[:database]
235
234
  @username = config[:username]
236
235
  @password = config[:password]
@@ -241,14 +240,14 @@ module ActiveRecord
241
240
  @schema = config[:schema]
242
241
 
243
242
  # Caching database connection options (auditing and billing support)
244
- @user = conn_options[:user] if conn_options.has_key?(:user)
243
+ @app_user = conn_options[:app_user] if conn_options.has_key?(:app_user)
245
244
  @account = conn_options[:account] if conn_options.has_key?(:account)
246
245
  @application = conn_options[:application] if conn_options.has_key?(:application)
247
246
  @workstation = conn_options[:workstation] if conn_options.has_key?(:workstation)
248
247
 
249
248
  # Calls the parent class +ConnectionAdapters+' initializer
250
249
  # which sets @connection, @logger, @runtime and @last_verification
251
- super(connection, logger)
250
+ super(@connection, logger)
252
251
 
253
252
  if @connection
254
253
  server_info = IBM_DB::server_info( @connection )
@@ -274,27 +273,29 @@ module ActiveRecord
274
273
  @servertype = IBM_DB2_I5.new(@connection, self)
275
274
  end
276
275
  end
277
-
278
276
  # Executes the +set schema+ statement using the schema identifier provided
279
- stmt = execute("SET SCHEMA #{@schema}") if @schema && @schema != @username
277
+ @servertype.set_schema(@schema) if @schema && @schema != @username
280
278
  end
281
279
 
280
+ # Optional connection attribute: database name space qualifier
282
281
  def schema=(name)
283
282
  unless name == @schema
284
283
  @schema = name
285
- stmt = execute("SET SCHEMA #{@schema}")
284
+ @servertype.set_schema(@schema)
286
285
  end
287
286
  end
288
287
 
289
- def user=(name)
290
- unless name == @user
288
+ # Optional connection attribute: authenticated application user
289
+ def app_user=(name)
290
+ unless name == @app_user
291
291
  option = {IBM_DB::SQL_ATTR_INFO_USERID => "#{name}"}
292
292
  if IBM_DB::set_option( @connection, option, 1 )
293
- @user = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_USERID )
293
+ @app_user = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_USERID )
294
294
  end
295
295
  end
296
296
  end
297
297
 
298
+ # Optional connection attribute: OS account (client workstation)
298
299
  def account=(name)
299
300
  unless name == @account
300
301
  option = {IBM_DB::SQL_ATTR_INFO_ACCTSTR => "#{name}"}
@@ -304,6 +305,7 @@ module ActiveRecord
304
305
  end
305
306
  end
306
307
 
308
+ # Optional connection attribute: application name
307
309
  def application=(name)
308
310
  unless name == @application
309
311
  option = {IBM_DB::SQL_ATTR_INFO_APPLNAME => "#{name}"}
@@ -313,6 +315,7 @@ module ActiveRecord
313
315
  end
314
316
  end
315
317
 
318
+ # Optional connection attribute: client workstation name
316
319
  def workstation=(name)
317
320
  unless name == @workstation
318
321
  option = {IBM_DB::SQL_ATTR_INFO_WRKSTNNAME => "#{name}"}
@@ -322,9 +325,9 @@ module ActiveRecord
322
325
  end
323
326
  end
324
327
 
325
- # This adapter supports migrations
326
- # Some limits applies, for example +remove_column+ and +change_column+
327
- # are not currently implemented
328
+ # This adapter supports migrations.
329
+ # Current limitations: +remove_column+ is not currently supported
330
+ # while DB2 for zOS does not support +rename_column+
328
331
  def supports_migrations?
329
332
  true
330
333
  end
@@ -341,6 +344,8 @@ module ActiveRecord
341
344
  # Tests the connection status
342
345
  def active?
343
346
  IBM_DB::active @connection
347
+ rescue
348
+ false
344
349
  end
345
350
 
346
351
  # Private method used by +reconnect!+.
@@ -358,7 +363,7 @@ module ActiveRecord
358
363
  end
359
364
  # Sets the schema if different from default (username)
360
365
  if @schema && @schema != @username
361
- execute("SET SCHEMA #{@schema}")
366
+ @servertype.set_schema(@schema)
362
367
  end
363
368
  end
364
369
  private :connect
@@ -388,45 +393,28 @@ module ActiveRecord
388
393
  @servertype.create_index_after_table(name, self)
389
394
  end
390
395
 
391
- # DB2 throws an error SQL0214N An expression in the ORDER BY
392
- # clause in the following position, or starting with "UPPER..."
393
- # in the "ORDER BY" clause is not valid. Reason code = "2".
394
- # SQLSTATE=42822
395
- # If the order_by columns do not match the select columns, we change
396
- # the select columns.
397
- def distinct(columns, order_by)
398
- if !order_by.nil? && !order_by.empty?
399
- order_by_columns = order_by.upcase.split(',').collect! { |e| (e.split).first }
400
- distinct_sql = (columns.upcase.split(',') + order_by_columns).uniq
401
- distinct_sql.collect! {|e| e + ", " }
402
- return "DISTINCT #{distinct_sql.to_s.strip.chop}"
403
- else
404
- return "DISTINCT #{columns}"
405
- end
406
- end
407
-
408
396
  # Returns an array of hashes with the column names as keys and
409
397
  # column values as values. +sql+ is the select query, and +name+ is an optional description for logging
410
398
  def select_all(sql, name = nil)
411
- # Replaces {"= NULL" with "IS NULL"} OR {"IN (NULL)" with "IS NULL"}
412
- sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, "IS NULL" )
413
-
399
+ # Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
400
+ sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
401
+
414
402
  results = []
415
403
  # Invokes the method +execute+ in order to log and execute the sql instructions
416
404
  # and get a IBM_DB::Statement from which is possible to fetch the results
417
405
  if stmt = execute(sql, name)
418
406
  begin
419
- # Fetches all the results available. IBM_DB::fetch_assoc(stmt) returns
420
- # an hash for each single record.
421
- # The loop stops when there aren't any more valid records to fetch
422
- while single_hash = IBM_DB::fetch_assoc(stmt)
407
+ # Fetches all the results available. IBM_DB::fetch_assoc(stmt) returns
408
+ # an hash for each single record.
409
+ # The loop stops when there aren't any more valid records to fetch
410
+ while single_hash = IBM_DB::fetch_assoc(stmt)
423
411
  # Add the record to the +results+ array
424
412
  results << single_hash
425
- end
413
+ end
426
414
  ensure
427
- # Ensures to free the resources associated with the statement
428
- IBM_DB::free_result stmt
429
- end
415
+ # Ensures to free the resources associated with the statement
416
+ IBM_DB::free_result stmt
417
+ end
430
418
  end
431
419
  # The array of record hashes is returned
432
420
  results
@@ -450,30 +438,41 @@ module ActiveRecord
450
438
  return id_value || @servertype.last_generated_id
451
439
  # Ensures to free the resources associated with the statement
452
440
  ensure
453
- IBM_DB::free_result(stmt)
441
+ IBM_DB::free_result(stmt)
454
442
  end
455
443
  end
456
444
  end
457
445
 
458
- # Executes and logs a +sql+ commands and
446
+ # Executes and logs +sql+ commands and
459
447
  # returns a +IBM_DB::Statement+ object.
460
448
  def execute(sql, name = nil)
449
+ sql.gsub!( /(\s*xml DEFAULT NULL)/i, " xml NOT NULL" )
461
450
  # Logs and execute the sql instructions.
462
451
  # The +log+ method is defined in the parent class +AbstractAdapter+
463
452
  log(sql, name) do
464
- if stmt = IBM_DB::exec(@connection, sql)
465
- stmt # Return the statement object
466
- else
467
- raise StatementInvalid, IBM_DB::stmt_errormsg
453
+ begin
454
+ if stmt = IBM_DB::exec(@connection, sql)
455
+ stmt # Return the statement object
456
+ else
457
+ raise IBM_DB::stmt_errormsg
458
+ end
459
+ rescue StandardError
460
+ error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
461
+ if error_msg && !error_msg.empty?
462
+ raise "Failed to execute statement due to error: #{error_msg}"
463
+ else
464
+ raise
465
+ end
468
466
  end
469
467
  end
470
468
  end
471
469
 
470
+ # Executes an "UPDATE" SQL statement
472
471
  def update(sql, name = nil)
473
472
  # Make sure the WHERE clause handles NULL's correctly
474
473
  sqlarray = sql.split(/\s*WHERE\s*/)
475
474
  if !sqlarray[1].nil?
476
- sqlarray[1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, "IS NULL" )
475
+ sqlarray[1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
477
476
  sql = sqlarray[0] + " WHERE " + sqlarray[1]
478
477
  end
479
478
 
@@ -501,7 +500,7 @@ module ActiveRecord
501
500
  IBM_DB::autocommit(@connection, IBM_DB::SQL_AUTOCOMMIT_OFF)
502
501
  end
503
502
 
504
- # Commits the transaction (and turns on auto-committing)
503
+ # Commits the transaction and turns on auto-committing
505
504
  def commit_db_transaction
506
505
  # Commits the transaction
507
506
  IBM_DB::commit @connection rescue nil
@@ -509,7 +508,7 @@ module ActiveRecord
509
508
  IBM_DB::autocommit @connection, IBM_DB::SQL_AUTOCOMMIT_ON
510
509
  end
511
510
 
512
- # Rolls back the transaction (and turns on auto-committing). Must be
511
+ # Rolls back the transaction and turns on auto-committing. Must be
513
512
  # done if the transaction block raises an exception or returns false
514
513
  def rollback_db_transaction
515
514
  # ROLLBACK the transaction
@@ -522,9 +521,9 @@ module ActiveRecord
522
521
  # Modifies a sql statement in order to implement a LIMIT and an OFFSET.
523
522
  # A LIMIT defines the number of rows that should be fetched, while
524
523
  # an OFFSET defines from what row the records must be fetched.
525
- # IBM DB SQL implements a LIMIT with the instructions:
524
+ # IBM data servers implement a LIMIT in SQL statements through:
526
525
  # FETCH FIRST n ROWS ONLY, where n is the number of rows required.
527
- # The implementation of OFFSET is more elaborate, and require the usage of
526
+ # The implementation of OFFSET is more elaborate, and requires the usage of
528
527
  # subqueries and the ROW_NUMBER() command in order to add row numbering
529
528
  # as an additional column to a copy of the existing table.
530
529
  # ==== Examples
@@ -557,15 +556,15 @@ module ActiveRecord
557
556
  # sql query given an offset and a limit
558
557
  def query_offset_limit(sql, offset, limit)
559
558
  # Defines what will be the last record
560
- last_record = offset + limit
561
- # Transforms the SELECT query in order to retrieve/fetch only
562
- # a number of records after the specified offset.
563
- # 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
564
- # to select with the condition of this column being between offset+1 and the offset+limit
565
- sql.gsub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
566
- # The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
567
- # and retrieve only a LIMIT number of records starting from the OFFSET+1
568
- sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
559
+ last_record = offset + limit
560
+ # Transforms the SELECT query in order to retrieve/fetch only
561
+ # a number of records after the specified offset.
562
+ # 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
563
+ # to select with the condition of this column being between offset+1 and the offset+limit
564
+ sql.gsub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
565
+ # The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
566
+ # and retrieve only a LIMIT number of records starting from the OFFSET+1
567
+ sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
569
568
  end
570
569
  private :query_offset_limit
571
570
 
@@ -583,7 +582,7 @@ module ActiveRecord
583
582
  def quote(value, column = nil)
584
583
  case value
585
584
  # If it's a numeric value and the column type is not a string, it shouldn't be quoted
586
- # (IBM DB doesn't accept quotes on numeric types)
585
+ # (IBM_DB doesn't accept quotes on numeric types)
587
586
  when Numeric
588
587
  # If the column type is text or string, return the quote value
589
588
  if column && column.type == :text || column && column.type == :string
@@ -594,30 +593,30 @@ module ActiveRecord
594
593
  value.to_s
595
594
  end
596
595
  when String, ActiveSupport::Multibyte::Chars
597
- if column && column.type == :binary
598
- # If quoting is required for the insert/update of a BLOB
599
- unless caller[0] =~ /add_column_options/i
600
- # Invokes a convertion from string to binary
601
- "BLOB('?')"
602
- else
603
- # Quoting required for the default value of a column
604
- "BLOB('#{value}')"
605
- end
606
- elsif column && column.type == :text
596
+ if column && column.type == :binary
597
+ # If quoting is required for the insert/update of a BLOB
607
598
  unless caller[0] =~ /add_column_options/i
608
- "'@@@IBMTEXT@@@'"
599
+ # Invokes a convertion from string to binary
600
+ "BLOB('?')"
609
601
  else
610
- "#{value}"
602
+ # Quoting required for the default value of a column
603
+ "BLOB('#{value}')"
611
604
  end
612
- elsif column && column.type == :xml
613
- unless caller[0] =~ /add_column_options/i
614
- "'<ibm>@@@IBMXML@@@</ibm>'"
615
- else
616
- "#{value}"
617
- end
618
- else
619
- "'#{quote_string(value)}'"
620
- end
605
+ elsif column && column.type == :text
606
+ unless caller[0] =~ /add_column_options/i
607
+ "'@@@IBMTEXT@@@'"
608
+ else
609
+ "#{value}"
610
+ end
611
+ elsif column && column.type == :xml
612
+ unless caller[0] =~ /add_column_options/i
613
+ "'<ibm>@@@IBMXML@@@</ibm>'"
614
+ else
615
+ "#{value}"
616
+ end
617
+ else
618
+ "'#{quote_string(value)}'"
619
+ end
621
620
  when TrueClass then quoted_true # return '1' for true
622
621
  when FalseClass then quoted_false # return '0' for false
623
622
  when NilClass
@@ -669,12 +668,13 @@ module ActiveRecord
669
668
  :date => { :name => "date" },
670
669
  :binary => { :name => "blob" },
671
670
 
672
- # IBM DB doesn't have a native boolean type.
671
+ # IBM data servers don't have a native boolean type.
673
672
  # A boolean can be represented by a smallint,
674
673
  # adopting the convention that False is 0 and True is 1
675
674
  :boolean => { :name => "smallint"},
676
675
  :xml => { :name => "xml"},
677
- :decimal => { :name => "decimal" }
676
+ :decimal => { :name => "decimal" },
677
+ :rowid => { :name => "rowid" } # rowid is a supported datatype on z/OS and i/5
678
678
  }
679
679
  end
680
680
 
@@ -682,16 +682,16 @@ module ActiveRecord
682
682
  # unlike MySQL. It does support limits on float and decimal/numeric
683
683
  def type_to_sql(type, limit = nil, precision = nil, scale = nil)
684
684
  if type == :integer && (!limit.nil? && limit > 0)
685
- return 'integer'
685
+ return 'integer'
686
686
  elsif type == :double && (!limit.nil? && limit > 0)
687
- return 'double'
687
+ return 'double'
688
688
  else
689
- return super
689
+ return super
690
690
  end
691
691
  end
692
692
 
693
693
  # Returns the maximum length a table alias identifier can be.
694
- # IBM DB (cross-platform) table limit is 128 characters
694
+ # IBM data servers (cross-platform) table limit is 128 characters
695
695
  def table_alias_length
696
696
  128
697
697
  end
@@ -759,8 +759,8 @@ module ActiveRecord
759
759
  # Statement required to access all the columns information
760
760
  if stmt = IBM_DB::columns(@connection, nil, @schema.upcase, table_name.upcase)
761
761
  begin
762
- # Fetches all the columns and assigns them to col.
763
- # +col+ is an hash with keys/value pairs for a column
762
+ # Fetches all the columns and assigns them to col.
763
+ # +col+ is an hash with keys/value pairs for a column
764
764
  while col = IBM_DB::fetch_assoc(stmt)
765
765
  column_name = col["column_name"].downcase
766
766
  # Assigns the column default value.
@@ -779,7 +779,7 @@ module ActiveRecord
779
779
  # it appends the (column_length) string on the supported data types
780
780
  unless column_length.nil? || column_length == '' || column_type.sub!(/ \(\) for bit data/i,"(#{column_length}) FOR BIT DATA") || !column_type =~ /char|lob|graphic/i
781
781
  if column_type =~ /decimal/i
782
- column_type << "(#{column_length},#{column_scale})"
782
+ column_type << "(#{column_length},#{column_scale})"
783
783
  else
784
784
  column_type << "(#{column_length})"
785
785
  end
@@ -793,8 +793,13 @@ module ActiveRecord
793
793
  columns << IBM_DBColumn.new(column_name, column_default_value, column_type, column_nullable)
794
794
  end
795
795
  end
796
- rescue
797
- raise "Failed to retrieve column metadata due to error: #{IBM_DB::conn_errormsg} ... #{IBM_DB::stmt_errormsg}"
796
+ rescue StandardError
797
+ error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
798
+ if error_msg && !error_msg.empty?
799
+ raise "Failed to retrieve column metadata due to driver error: #{error_msg}"
800
+ else
801
+ raise
802
+ end
798
803
  end
799
804
  end
800
805
  # Returns the columns array
@@ -804,7 +809,7 @@ module ActiveRecord
804
809
  # Renames a table.
805
810
  # ==== Example
806
811
  # rename_table('octopuses', 'octopi')
807
- # Overriden to satisfy IBM DB syntax
812
+ # Overriden to satisfy IBM data servers syntax
808
813
  def rename_table(name, new_name)
809
814
  # SQL rename table statement
810
815
  rename_table_sql = "RENAME TABLE #{name} TO #{new_name}"
@@ -818,14 +823,14 @@ module ActiveRecord
818
823
  # ===== Example
819
824
  # rename_column(:suppliers, :description, :name)
820
825
  def rename_column(table_name, column_name, new_column_name)
821
- @servertype.rename_column(table_name, column_name, new_column_name)
826
+ @servertype.rename_column(table_name, column_name, new_column_name)
822
827
  end
823
828
 
824
829
  # Removes the column from the table definition.
825
830
  # ===== Examples
826
831
  # remove_column(:suppliers, :qualification)
827
832
  def remove_column(table_name, column_name)
828
- @servertype.remove_column(table_name, column_name)
833
+ @servertype.remove_column(table_name, column_name)
829
834
  end
830
835
 
831
836
  # Changes the column's definition according to the new options.
@@ -834,18 +839,18 @@ module ActiveRecord
834
839
  # change_column(:suppliers, :name, :string, :limit => 80)
835
840
  # change_column(:accounts, :description, :text)
836
841
  def change_column(table_name, column_name, type, options = {})
837
- @servertype.change_column(table_name, column_name, type, options)
842
+ @servertype.change_column(table_name, column_name, type, options)
838
843
  end
839
844
 
840
- # Sets a new default value for a column. You can't set the default
841
- # value to +NULL+, In that case, you need to
842
- # DatabaseStatements#execute the apppropriate SQL statement.
845
+ # Sets a new default value for a column. This does not set the default
846
+ # value to +NULL+, instead, it needs DatabaseStatements#execute which
847
+ # can execute the appropriate SQL statement for setting the value.
843
848
  # ==== Examples
844
849
  # change_column_default(:suppliers, :qualification, 'new')
845
850
  # change_column_default(:accounts, :authorized, 1)
846
- # Method overriden to satisfy IBM DB syntax.
851
+ # Method overriden to satisfy IBM data servers syntax.
847
852
  def change_column_default(table_name, column_name, default)
848
- # SQL statement which alters column's default value
853
+ # SQL statement which alters column's default value
849
854
  change_column_sql = "ALTER TABLE #{table_name} ALTER COLUMN #{column_name} SET WITH DEFAULT #{quote(default)}"
850
855
  stmt = execute(change_column_sql)
851
856
  # Ensures to free the resources associated with the statement
@@ -902,20 +907,20 @@ module ActiveRecord
902
907
  # You can remove an index on multiple columns by specifying the first column.
903
908
  # add_index :accounts, [:username, :password]
904
909
  # remove_index :accounts, :username
905
- # Overriden to use the IBM DB SQL syntax.
910
+ # Overriden to use the IBM data servers SQL syntax.
906
911
  def remove_index(table_name, options = {})
907
912
  execute("DROP INDEX #{index_name(table_name, options)}")
908
913
  end
909
914
 
910
915
  # Builds an index name from a table_name and column. If an index name has been passed,
911
- # the method returns it. Overrides the default method to respect the IBM DB (cross-platform)
916
+ # the method returns it. Overrides the default method to respect the IBM data servers (cross-platform)
912
917
  # limit on indexes (max of 18 characters)
913
918
  def index_name(table_name, options)
914
919
  if Hash === options and options[:name]
915
920
  # legacy support
916
- # If a name has been specified, this is returned
917
- options[:name]
918
- else
921
+ # If a name has been specified, this is returned
922
+ options[:name]
923
+ else
919
924
  # We reverse the table name to reduce the chance of hitting duplicate
920
925
  # index name errors. For e.g. indexes on table names like accounts,
921
926
  # accounts_favorites
@@ -960,11 +965,15 @@ module ActiveRecord
960
965
  reorg_table(table_name)
961
966
  end
962
967
 
968
+ def set_schema(schema)
969
+ @caller.execute("SET SCHEMA #{schema}")
970
+ end
971
+
963
972
  end # class IBM_DataServer
964
973
 
965
974
  class IBM_DB2 < IBM_DataServer
966
975
  def rename_column(table_name, column_name, new_column_name)
967
- raise NotImplementedError, "rename_column is not implemented yet in the IBM DB Adapter"
976
+ raise NotImplementedError, "rename_column is not implemented yet in the IBM_DB Adapter"
968
977
  end
969
978
 
970
979
  def primary_key
@@ -985,10 +994,19 @@ module ActiveRecord
985
994
  end
986
995
 
987
996
  def change_column(table_name, column_name, type, options)
988
- @caller.execute "ALTER TABLE #{table_name} ALTER #{column_name} SET DATA TYPE #{@caller.type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
997
+ data_type = @caller.type_to_sql(type, options[:limit], options[:precision], options[:scale])
998
+ begin
999
+ @caller.execute "ALTER TABLE #{table_name} ALTER #{column_name} SET DATA TYPE #{data_type}"
1000
+ rescue StandardError => exec_err
1001
+ if exec_err.message.include?('SQLCODE=-190')
1002
+ raise StatementInvalid, "Please consult documentation for compatible data types while changing column datatype. The column datatype change to [#{data_type}] is not supported by this data server: #{exec_err}"
1003
+ else
1004
+ raise
1005
+ end
1006
+ end
989
1007
  reorg_table(table_name)
990
1008
  if !options[:default].nil?
991
- @caller.change_column_default(table_name, column_name, options[:default])
1009
+ @caller.change_column_default(table_name, column_name, options[:default])
992
1010
  end
993
1011
  end
994
1012
  end # class IBM_DB2
@@ -1035,6 +1053,13 @@ module ActiveRecord
1035
1053
  def remove_column(table_name, column_name)
1036
1054
  raise NotImplementedError, "remove_column is not supported for DB2/zOS server"
1037
1055
  end
1056
+
1057
+ # Setting the SQLID on z/OS will also update the CURRENT SCHEMA
1058
+ # special register, but not vice versa
1059
+ def set_schema(schema)
1060
+ @caller.execute("SET CURRENT SQLID ='#{schema}'")
1061
+ end
1062
+
1038
1063
  end # class IBM_DB2_ZOS
1039
1064
 
1040
1065
  class IBM_DB2_ZOS_8 < IBM_DB2_ZOS
@@ -1050,4 +1075,4 @@ module ActiveRecord
1050
1075
  end # class IBM_DB2_I5
1051
1076
 
1052
1077
  end # module ConnectionAdapters
1053
- end # module ActiveRecord
1078
+ end # module ActiveRecord