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 +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
|