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 +5 -0
- data/README +4 -2
- data/ext/ibm_db.c +144 -12
- data/ext/ruby_ibm_db_cli.h +1 -0
- data/lib/IBM_DB.rb +1 -1
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +62 -1
- data/test/cases/adapter_test.rb +41 -19
- data/test/cases/associations/belongs_to_associations_test.rb +486 -0
- data/test/cases/associations/cascaded_eager_loading_test.rb +53 -3
- data/test/cases/associations/eager_test.rb +42 -22
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +114 -71
- data/test/cases/associations/has_many_through_associations_test.rb +214 -34
- data/test/cases/associations/join_model_test.rb +26 -34
- data/test/cases/attribute_methods_test.rb +387 -78
- data/test/cases/base_test.rb +555 -1183
- data/test/cases/calculations_test.rb +55 -43
- data/test/cases/finder_test.rb +218 -222
- data/test/cases/fixtures_test.rb +44 -20
- data/test/cases/migration_test.rb +638 -242
- data/test/cases/schema_dumper_test.rb +38 -3
- data/test/cases/validations/uniqueness_validation_test.rb +283 -0
- data/test/schema/i5/ibm_db_specific_schema.rb +1 -0
- data/test/schema/ids/ibm_db_specific_schema.rb +1 -0
- data/test/schema/luw/ibm_db_specific_schema.rb +2 -1
- data/test/schema/schema.rb +157 -10
- data/test/schema/zOS/ibm_db_specific_schema.rb +1 -0
- metadata +5 -5
- data/test/cases/helper.rb +0 -75
- data/test/cases/validations_test.rb +0 -1604
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) (
|
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.
|
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));
|
data/ext/ruby_ibm_db_cli.h
CHANGED
@@ -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
|
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
|
data/test/cases/adapter_test.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
160
|
-
|
161
|
-
|
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
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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
|