ibm_db 2.5.5 → 2.5.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/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