ibm_db 0.4.0 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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