ibm_db 2.5.5 → 2.5.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,10 @@
1
1
  Change Log
2
2
  ==============
3
+ 2011/02/07 (IBM_DB adapter 2.5.6, driver 2.5.6) :
4
+ - Fixed Bug #28622, #28881
5
+ - Decimal datatypes will now be returned as BigDecimal type from the driver
6
+ - Changes to rollback any active transaction in the connection destructor method if connection is not explicitly closed
7
+ - Changes to have a single gem file for ruby 1.8 and ruby 1.9
3
8
  2010/07/15 (IBM_DB adapter 2.5.5, driver 2.5.5) :
4
9
  - Support for datatype Graphic and Vargraphic in driver and adapter [27965]
5
10
  - Support for Bigint datatype in adapter.
data/README CHANGED
@@ -1,5 +1,5 @@
1
1
  =====================================================================
2
- README for the IBM_DB Adapter (2.5.5) and Driver (2.5.5) (2010/07/15)
2
+ README for the IBM_DB Adapter (2.5.5) and Driver (2.5.5) (2011/02/07)
3
3
  For ActiveRecord Version >= 1.15.5 (and Rails >= 1.2.5)
4
4
  =====================================================================
5
5
 
@@ -259,7 +259,9 @@ Limitations and known problems
259
259
  - test_add_table_with_decimals
260
260
  - test_native_types
261
261
  - test_schema_dump_includes_decimal_options
262
-
262
+ - Usage with Rails-3.0.3/Rails-3.0.4
263
+ - To use with Rails-3.0.3/4 patch latest Arel with the patch available at https://gist.github.com/814491
264
+
263
265
  Unicode Support
264
266
  ===============
265
267
  - Available only with Ruby version 1.9 and above
data/ext/ibm_db.c CHANGED
@@ -12,7 +12,7 @@
12
12
  +----------------------------------------------------------------------+
13
13
  */
14
14
 
15
- #define MODULE_RELEASE "2.5.5"
15
+ #define MODULE_RELEASE "2.5.6"
16
16
 
17
17
  #ifdef HAVE_CONFIG_H
18
18
  #include "config.h"
@@ -321,6 +321,11 @@ void Init_ibm_db(void) {
321
321
  #define INI_STR(name) NULL
322
322
  /* }}} */
323
323
 
324
+ /*Load necessary libraries*/
325
+ static void ruby_ibm_db_load_necessary_libs() {
326
+ rb_eval_string("require \'bigdecimal\'");
327
+ }
328
+
324
329
  static void ruby_ibm_db_init_globals(struct _ibm_db_globals *ibm_db_globals)
325
330
  {
326
331
  /* env handle */
@@ -415,10 +420,25 @@ static void _ruby_ibm_db_mark_conn_struct(conn_handle *handle)
415
420
  static void _ruby_ibm_db_free_conn_struct(conn_handle *handle)
416
421
  {
417
422
  int rc;
418
-
423
+ end_tran_args *end_X_args;
424
+
419
425
  if ( handle != NULL ) {
420
426
  /* Disconnect from DB. If stmt is allocated, it is freed automatically*/
421
427
  if ( handle->handle_active ) {
428
+ if( handle->transaction_active == 1 && handle->auto_commit == 0 ) {
429
+ handle->transaction_active = 0;
430
+ end_X_args = ALLOC( end_tran_args );
431
+ memset(end_X_args,'\0',sizeof(struct _ibm_db_end_tran_args_struct));
432
+
433
+ end_X_args->hdbc = &(handle->hdbc);
434
+ end_X_args->handleType = SQL_HANDLE_DBC;
435
+ end_X_args->completionType = SQL_ROLLBACK; /*Note we are rolling back the transaction*/
436
+
437
+ _ruby_ibm_db_SQLEndTran( end_X_args );
438
+
439
+ ruby_xfree( end_X_args );
440
+
441
+ }
422
442
  rc = _ruby_ibm_db_SQLDisconnect_helper( &(handle->hdbc) );
423
443
  rc = SQLFreeHandle(SQL_HANDLE_DBC, handle->hdbc );
424
444
  rc = SQLFreeHandle(SQL_HANDLE_ENV, handle->henv );
@@ -826,6 +846,8 @@ void ruby_init_ibm_db()
826
846
  rb_attr(le_server_info, rb_intern("MAX_STATEMENT_LEN"), 1, 0, 0);
827
847
  rb_attr(le_server_info, rb_intern("MAX_TABLE_NAME_LEN"), 1, 0, 0);
828
848
  rb_attr(le_server_info, rb_intern("NON_NULLABLE_COLUMNS"), 1, 0, 0);
849
+
850
+ ruby_ibm_db_load_necessary_libs();
829
851
  }
830
852
  /* */
831
853
 
@@ -1387,11 +1409,6 @@ static VALUE _ruby_ibm_db_assign_options( void *handle, int type, long opt_key,
1387
1409
  }
1388
1410
  } else {
1389
1411
  option_num = NUM2LONG(data);
1390
- if (opt_key == SQL_ATTR_AUTOCOMMIT && option_num == SQL_AUTOCOMMIT_OFF) {
1391
- ((conn_handle*)handle)->auto_commit = 0;
1392
- } else if (opt_key == SQL_ATTR_AUTOCOMMIT && option_num == SQL_AUTOCOMMIT_ON) {
1393
- ((conn_handle*)handle)->auto_commit = 1;
1394
- }
1395
1412
  #ifdef PASE
1396
1413
  handleAttr_args->valuePtr = (SQLPOINTER)&option_num;
1397
1414
  #else
@@ -1422,6 +1439,13 @@ static VALUE _ruby_ibm_db_assign_options( void *handle, int type, long opt_key,
1422
1439
  #endif
1423
1440
  }
1424
1441
  return Qfalse;
1442
+ } else {
1443
+ if (opt_key == SQL_ATTR_AUTOCOMMIT && option_num == SQL_AUTOCOMMIT_OFF) {
1444
+ ((conn_handle*)handle)->auto_commit = 0;
1445
+ } else if (opt_key == SQL_ATTR_AUTOCOMMIT && option_num == SQL_AUTOCOMMIT_ON) {
1446
+ ((conn_handle*)handle)->auto_commit = 1;
1447
+ ((conn_handle*)handle)->transaction_active = 0; /* Setting Autocommit to ON commits any open transaction*/
1448
+ }
1425
1449
  }
1426
1450
  }
1427
1451
  } else {
@@ -2087,6 +2111,8 @@ static VALUE _ruby_ibm_db_connect_helper2( connect_helper_args *data ) {
2087
2111
 
2088
2112
  conn_res->errorType = 1;
2089
2113
 
2114
+ conn_res->transaction_active = 0; /*No transaction is active*/
2115
+
2090
2116
  /* Set Options */
2091
2117
  if ( !NIL_P(*options) ) {
2092
2118
  rc = _ruby_ibm_db_parse_options( *options, SQL_HANDLE_DBC, conn_res, error );
@@ -2127,8 +2153,50 @@ static VALUE _ruby_ibm_db_connect_helper2( connect_helper_args *data ) {
2127
2153
  handleAttr_args = NULL;
2128
2154
  _ruby_ibm_db_free_conn_struct( conn_res );
2129
2155
  return Qnil;
2130
- break;
2131
2156
  }
2157
+
2158
+ /* Get the AUTOCOMMIT state from the CLI driver as cli driver could have changed autocommit status based on it's precedence */
2159
+ get_handleAttr_args = ALLOC( get_handle_attr_args );
2160
+ memset(get_handleAttr_args,'\0',sizeof(struct _ibm_db_get_handle_attr_struct));
2161
+
2162
+ get_handleAttr_args->handle = &( conn_res->hdbc );
2163
+ get_handleAttr_args->attribute = SQL_ATTR_AUTOCOMMIT;
2164
+ get_handleAttr_args->valuePtr = (SQLPOINTER)(&conn_res->auto_commit);
2165
+ get_handleAttr_args->buff_length = 0;
2166
+ get_handleAttr_args->out_length = NULL;
2167
+
2168
+ rc = _ruby_ibm_db_SQLGetConnectAttr_helper( get_handleAttr_args );
2169
+
2170
+ ruby_xfree( get_handleAttr_args );
2171
+ get_handleAttr_args = NULL;
2172
+
2173
+ if ( rc == SQL_ERROR ) {
2174
+ _ruby_ibm_db_check_sql_errors( conn_res, DB_CONN, conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, NULL, -1, 1, 0 );
2175
+ rc = _ruby_ibm_db_SQLDisconnect_helper( &(conn_res->hdbc) );
2176
+ SQLFreeHandle( SQL_HANDLE_DBC, conn_res->hdbc );
2177
+ SQLFreeHandle( SQL_HANDLE_ENV, conn_res->henv );
2178
+ if( conn_res != NULL && conn_res->ruby_error_msg != NULL ) {
2179
+
2180
+ #ifdef UNICODE_SUPPORT_VERSION
2181
+ *error = rb_str_concat( _ruby_ibm_db_export_char_to_utf8_rstr("Failed to retrieve autocommit status during connection: "),
2182
+ _ruby_ibm_db_export_sqlwchar_to_utf8_rstr(conn_res->ruby_error_msg, conn_res->ruby_error_msg_len));
2183
+ #else
2184
+ *error = rb_str_cat2(rb_str_new2("Connection failed: "),conn_res->ruby_error_msg);
2185
+ #endif
2186
+ } else {
2187
+ #ifdef UNICODE_SUPPORT_VERSION
2188
+ *error = _ruby_ibm_db_export_char_to_utf8_rstr("Failed to retrieve autocommit status during connection: <error message could not be retrieved>");
2189
+ #else
2190
+ *error = rb_str_new2("Connection failed: <error message could not be retrieved>");
2191
+ #endif
2192
+ }
2193
+ ruby_xfree( handleAttr_args );
2194
+ handleAttr_args = NULL;
2195
+ _ruby_ibm_db_free_conn_struct( conn_res );
2196
+ return Qnil;
2197
+
2198
+ }
2199
+
2132
2200
  #ifdef CLI_DBC_SERVER_TYPE_DB2LUW
2133
2201
  #ifdef SQL_ATTR_DECFLOAT_ROUNDING_MODE
2134
2202
 
@@ -2786,8 +2854,15 @@ VALUE ibm_db_autocommit(int argc, VALUE *argv, VALUE self)
2786
2854
 
2787
2855
  if ( rc == SQL_ERROR ) {
2788
2856
  _ruby_ibm_db_check_sql_errors( conn_res, DB_CONN, conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, NULL, -1, 1, 1 );
2857
+ } else {
2858
+ conn_res->auto_commit = autocommit;
2859
+
2860
+ /* If autocommit is requested to be turned ON and there is a transaction in progress, the trasaction is committed.
2861
+ * Hence set flag_transaction to 0 indicating no transaction is in progress */
2862
+ if( autocommit == SQL_AUTOCOMMIT_ON ) {
2863
+ conn_res->transaction_active = 0;
2864
+ }
2789
2865
  }
2790
- conn_res->auto_commit = autocommit;
2791
2866
  }
2792
2867
  ruby_xfree( handleAttr_args );
2793
2868
  handleAttr_args = NULL;
@@ -3099,7 +3174,12 @@ VALUE ibm_db_bind_param(int argc, VALUE *argv, VALUE self)
3099
3174
  rb_scan_args(argc, argv, "35", &stmt, &r_param_no, &r_varname,
3100
3175
  &r_param_type, &r_data_type, &r_precision, &r_scale, &r_size);
3101
3176
 
3177
+ #ifdef UNICODE_SUPPORT_VERSION
3178
+ varname = RSTRING_PTR(r_varname);
3179
+ varname_len = RSTRING_LEN(r_varname);
3180
+ #else
3102
3181
  varname = rb_str2cstr(r_varname, &varname_len);
3182
+ #endif
3103
3183
 
3104
3184
  if (!NIL_P(r_param_type)) {
3105
3185
  param_type = NUM2LONG(r_param_type);
@@ -5046,6 +5126,7 @@ VALUE ibm_db_commit(int argc, VALUE *argv, VALUE self)
5046
5126
  _ruby_ibm_db_check_sql_errors( conn_res, DB_CONN, conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, NULL, -1, 1, 1 );
5047
5127
  return Qfalse;
5048
5128
  } else {
5129
+ conn_res->transaction_active = 0;
5049
5130
  return Qtrue;
5050
5131
  }
5051
5132
  }
@@ -5242,6 +5323,8 @@ VALUE ibm_db_exec(int argc, VALUE *argv, VALUE self)
5242
5323
  }
5243
5324
  }
5244
5325
 
5326
+ conn_res->transaction_active = 1; /*A transaction begins with prepare of exec*/
5327
+
5245
5328
  exec_direct_args->stmt_res = stmt_res;
5246
5329
 
5247
5330
  #ifdef GIL_RELEASE_VERSION
@@ -5432,6 +5515,8 @@ VALUE ibm_db_prepare(int argc, VALUE *argv, VALUE self)
5432
5515
 
5433
5516
  stmt_res = _ibm_db_new_stmt_struct(conn_res);
5434
5517
 
5518
+ conn_res->transaction_active = 1; /*A transaction begins with prepare of exec*/
5519
+
5435
5520
  /* Allocates the stmt handle */
5436
5521
  /* Prepares the statement */
5437
5522
  /* returns the stat_handle back to the calling function */
@@ -5515,6 +5600,7 @@ static int _ruby_ibm_db_bind_parameter_helper(stmt_handle *stmt_res, param_node
5515
5600
 
5516
5601
  #ifdef UNICODE_SUPPORT_VERSION
5517
5602
  VALUE bindData_utf16;
5603
+ VALUE tmpBuff;
5518
5604
  #endif
5519
5605
 
5520
5606
  SQLSMALLINT valueType;
@@ -5534,7 +5620,13 @@ static int _ruby_ibm_db_bind_parameter_helper(stmt_handle *stmt_res, param_node
5534
5620
 
5535
5621
  switch(TYPE(*bind_data)) {
5536
5622
  case T_BIGNUM:
5623
+ #ifdef UNICODE_SUPPORT_VERSION
5624
+ tmpBuff = rb_big2str(*bind_data,10);
5625
+ tmp_str = (SQLCHAR *) RSTRING_PTR(tmpBuff);
5626
+ curr->ivalue = RSTRING_LEN(tmpBuff);
5627
+ #else
5537
5628
  tmp_str = (SQLCHAR *) rb_str2cstr( rb_big2str(*bind_data,10), (long*)&curr->ivalue );
5629
+ #endif
5538
5630
 
5539
5631
  curr->svalue = (SQLCHAR *) ALLOC_N(char, curr->ivalue+1);
5540
5632
  memset(curr->svalue, '\0', curr->ivalue+1);
@@ -5842,7 +5934,13 @@ static int _ruby_ibm_db_bind_data( stmt_handle *stmt_res, param_node *curr, VALU
5842
5934
  return SQL_ERROR;
5843
5935
  }
5844
5936
  curr->bind_indicator = 0;
5937
+
5938
+ #ifdef UNICODE_SUPPORT_VERSION
5939
+ curr->svalue = (SQLCHAR *) RSTRING_PTR(*bind_data);
5940
+ curr->ivalue = RSTRING_LEN(*bind_data);
5941
+ #else
5845
5942
  curr->svalue = (SQLCHAR *) rb_str2cstr(*bind_data, (long*) &curr->ivalue);
5943
+ #endif
5846
5944
 
5847
5945
  /* Bind file name string */
5848
5946
  rc = _ruby_ibm_db_SQLBindFileToParam_helper(stmt_res, curr);
@@ -6054,7 +6152,13 @@ void var_assign(char *name, VALUE value) {
6054
6152
  inspect = rb_intern("inspect");
6055
6153
  value = rb_funcall(value, inspect, 0);
6056
6154
 
6155
+ #ifdef UNICODE_SUPPORT_VERSION
6156
+ expr = RSTRING_PTR(value);
6157
+ expr_len = RSTRING_LEN(value);
6158
+ #else
6057
6159
  expr = rb_str2cstr(value, &expr_len);
6160
+ #endif
6161
+
6058
6162
  statement = ALLOC_N(char, strlen(name)+1+expr_len+1);
6059
6163
  strcpy(statement, name);
6060
6164
  strcat(statement, "=");
@@ -8017,6 +8121,7 @@ VALUE ibm_db_rollback(int argc, VALUE *argv, VALUE self)
8017
8121
  _ruby_ibm_db_check_sql_errors( conn_res, DB_CONN, conn_res->hdbc, SQL_HANDLE_DBC, rc, 1, NULL, NULL, -1, 1, 1 );
8018
8122
  return Qfalse;
8019
8123
  } else {
8124
+ conn_res->transaction_active = 0;
8020
8125
  return Qtrue;
8021
8126
  }
8022
8127
  }
@@ -8623,6 +8728,8 @@ static VALUE _ruby_ibm_db_bind_fetch_helper(ibm_db_fetch_helper_args *data)
8623
8728
  SQLINTEGER out_length, tmp_length;
8624
8729
  SQLPOINTER out_ptr;
8625
8730
 
8731
+ char *tmpStr = NULL;
8732
+
8626
8733
  VALUE return_value = Qnil;
8627
8734
  VALUE colName = Qnil;
8628
8735
 
@@ -8887,9 +8994,6 @@ static VALUE _ruby_ibm_db_bind_fetch_helper(ibm_db_fetch_helper_args *data)
8887
8994
  case SQL_TYPE_TIME:
8888
8995
  case SQL_TYPE_TIMESTAMP:
8889
8996
  case SQL_BIGINT:
8890
- case SQL_DECIMAL:
8891
- case SQL_NUMERIC:
8892
- case SQL_DECFLOAT:
8893
8997
 
8894
8998
  if ( op & FETCH_ASSOC ) {
8895
8999
  rb_hash_aset(return_value, colName, rb_str_new2((char *)row_data->str_val));
@@ -8900,6 +9004,34 @@ static VALUE _ruby_ibm_db_bind_fetch_helper(ibm_db_fetch_helper_args *data)
8900
9004
  rb_hash_aset(return_value, INT2NUM(i), rb_str_new2((char *)row_data->str_val));
8901
9005
  }
8902
9006
  break;
9007
+
9008
+ case SQL_DECIMAL:
9009
+ case SQL_NUMERIC:
9010
+ case SQL_DECFLOAT:
9011
+ tmpStr = ALLOC_N(char, strlen(row_data->str_val) + 19);
9012
+
9013
+ if(tmpStr == NULL ){
9014
+ rb_warn( "Failed to Allocate Memory for Decimal Data" );
9015
+ return Qnil;
9016
+ }
9017
+
9018
+ strcpy(tmpStr, "BigDecimal.new(\'");
9019
+ strcat(tmpStr, row_data->str_val);
9020
+ strcat(tmpStr, "\')");
9021
+
9022
+ if ( op & FETCH_ASSOC ) {
9023
+ rb_hash_aset(return_value, colName, rb_eval_string(tmpStr));
9024
+ }
9025
+ if ( op == FETCH_INDEX ) {
9026
+ rb_ary_store(return_value, i, rb_eval_string(tmpStr) );
9027
+ } else if ( op == FETCH_BOTH ) {
9028
+ rb_hash_aset( return_value, INT2NUM(i), rb_eval_string( tmpStr ) );
9029
+ }
9030
+
9031
+ ruby_xfree(tmpStr);
9032
+ tmpStr = NULL;
9033
+
9034
+ break;
8903
9035
  case SQL_SMALLINT:
8904
9036
  if ( op & FETCH_ASSOC ) {
8905
9037
  rb_hash_aset(return_value, colName, INT2NUM(row_data->s_val));
@@ -43,6 +43,7 @@ typedef struct _conn_handle_struct {
43
43
  long c_case_mode;
44
44
  long c_cursor_type;
45
45
  int handle_active;
46
+ int transaction_active;
46
47
  SQLSMALLINT error_recno_tracker;
47
48
  SQLSMALLINT errormsg_recno_tracker;
48
49
  int flag_pconnect; /* Indicates that this connection is persistent */
data/lib/IBM_DB.rb CHANGED
@@ -1,2 +1,2 @@
1
- require (RUBY_PLATFORM =~ /mswin32/ || RUBY_PLATFORM =~ /mingw32/ ) ? 'mswin32/ibm_db.so' : 'ibm_db.so'
1
+ require (RUBY_PLATFORM =~ /mswin32/ || RUBY_PLATFORM =~ /mingw32/ ) ? 'mswin32/ibm_db' : 'ibm_db.so'
2
2
  require 'active_record/connection_adapters/ibm_db_adapter'
@@ -189,6 +189,67 @@ module ActiveRecord
189
189
 
190
190
  class << self
191
191
 
192
+ def validates_uniqueness_of(*attr_names)
193
+ configuration = { :case_sensitive => true }
194
+ configuration.update(attr_names.extract_options!)
195
+
196
+ validates_each(attr_names,configuration) do |record, attr_name, value|
197
+ # The check for an existing value should be run from a class that
198
+ # isn't abstract. This means working down from the current class
199
+ # (self), to the first non-abstract class. Since classes don't know
200
+ # their subclasses, we have to build the hierarchy between self and
201
+ # the record's class.
202
+ class_hierarchy = [record.class]
203
+ while class_hierarchy.first != self
204
+ class_hierarchy.insert(0, class_hierarchy.first.superclass)
205
+ end
206
+
207
+ # Now we can work our way down the tree to the first non-abstract
208
+ # class (which has a database table to query from).
209
+ finder_class = class_hierarchy.detect { |klass| !klass.abstract_class? }
210
+
211
+ column = finder_class.columns_hash[attr_name.to_s]
212
+
213
+ if value.nil?
214
+ comparison_operator = "IS NULL"
215
+ elsif column.text?
216
+ comparison_operator = "#{connection.case_sensitive_equality_operator} ?"
217
+ value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s
218
+ else
219
+ comparison_operator = "= ?"
220
+ end
221
+
222
+ sql_attribute = "#{record.class.quoted_table_name}.#{connection.quote_column_name(attr_name)}"
223
+
224
+ if value.nil? || (configuration[:case_sensitive] || !column.text?)
225
+ condition_sql = "#{sql_attribute} #{comparison_operator}"
226
+ condition_params = [value] if(!value.nil?) #Add the value only if not nil, because in case of nil comparison op is IS NULL
227
+ else
228
+ condition_sql = "LOWER(#{sql_attribute}) #{comparison_operator}"
229
+ condition_params = [value.mb_chars.downcase]
230
+ end
231
+
232
+ if scope = configuration[:scope]
233
+ Array(scope).map do |scope_item|
234
+ scope_value = record.send(scope_item)
235
+ condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value)
236
+ condition_params << scope_value
237
+ end
238
+ end
239
+
240
+ unless record.new_record?
241
+ condition_sql << " AND #{record.class.quoted_table_name}.#{record.class.primary_key} <> ?"
242
+ condition_params << record.send(:id)
243
+ end
244
+
245
+ finder_class.with_exclusive_scope do
246
+ if finder_class.exists?([condition_sql, *condition_params])
247
+ record.errors.add(attr_name, :taken, :default => configuration[:message], :value => value)
248
+ end
249
+ end
250
+ end
251
+ end
252
+
192
253
  def find_one(id, options)
193
254
  param_array = [quote_value(id,columns_hash[primary_key])]
194
255
  if options[:conditions]
@@ -1901,4 +1962,4 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
1901
1962
  pstmt = @connection.prepare "DELETE FROM #{@connection.quote_table_name(table_name)}", 'Fixture Delete'
1902
1963
  @connection.prepared_delete(pstmt, nil)
1903
1964
  end
1904
- end
1965
+ end
@@ -107,6 +107,17 @@ class AdapterTest < ActiveRecord::TestCase
107
107
  def test_show_nonexistent_variable_returns_nil
108
108
  assert_nil @connection.show_variable('foo_bar_baz')
109
109
  end
110
+
111
+ def test_not_specifying_database_name_for_cross_database_selects
112
+ begin
113
+ assert_nothing_raised do
114
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
115
+ ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
116
+ end
117
+ ensure
118
+ ActiveRecord::Base.establish_connection 'arunit'
119
+ end
120
+ end
110
121
  end
111
122
 
112
123
  if current_adapter?(:PostgreSQLAdapter)
@@ -154,27 +165,38 @@ class AdapterTest < ActiveRecord::TestCase
154
165
  end
155
166
  end
156
167
 
157
- unless current_adapter?(:IBM_DBAdapter)
168
+ def test_uniqueness_violations_are_translated_to_specific_exception
169
+ @connection.execute "INSERT INTO subscribers(nick) VALUES('me')"
170
+ assert_raises(ActiveRecord::RecordNotUnique) do
171
+ @connection.execute "INSERT INTO subscribers(nick) VALUES('me')"
172
+ end
173
+ end
174
+
175
+ def test_foreign_key_violations_are_translated_to_specific_exception
176
+ unless @connection.adapter_name == 'SQLite'
177
+ assert_raises(ActiveRecord::InvalidForeignKey) do
178
+ # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
179
+ if @connection.prefetch_primary_key?
180
+ id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
181
+ @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
182
+ else
183
+ @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+ unless current_adapter?(:IBM_DBAdapter)
158
190
  def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas
159
- sql_inject = "1 select * from schema"
160
- assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit=>sql_inject)
161
- if current_adapter?(:MysqlAdapter)
162
- assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
163
- else
164
- assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
165
- end
191
+ sql_inject = "1 select * from schema"
192
+ assert_no_match(/schema/, @connection.add_limit_offset!("", :limit=>sql_inject))
193
+ assert_no_match(/schema/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7))
166
194
  end
167
195
 
168
196
  def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas
169
- sql_inject = "1, 7 procedure help()"
170
- if current_adapter?(:MysqlAdapter)
171
- assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject)
172
- assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
173
- else
174
- assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit=>sql_inject)
175
- assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
176
- end
177
- end
178
- end
179
-
197
+ sql_inject = "1, 7 procedure help()"
198
+ assert_no_match(/procedure/, @connection.add_limit_offset!("", :limit=>sql_inject))
199
+ assert_no_match(/procedure/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7))
200
+ end
201
+ end
180
202
  end