db2 2.6.2 → 2.7.0
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 +17 -0
- data/README +79 -141
- data/ext/Makefile.nt32 +3 -3
- data/ext/Makefile.nt32.191 +212 -0
- data/ext/extconf.rb +75 -14
- data/ext/ibm_db.c +504 -47
- data/ext/ruby_ibm_db.h +4 -1
- data/ext/ruby_ibm_db_cli.c +108 -1
- data/ext/ruby_ibm_db_cli.h +54 -1
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +423 -124
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
- data/test/cases/adapter_test.rb +169 -164
- data/test/cases/associations/belongs_to_associations_test.rb +268 -43
- data/test/cases/associations/cascaded_eager_loading_test.rb +31 -33
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +90 -156
- data/test/cases/associations/join_model_test.rb +100 -150
- data/test/cases/attribute_methods_test.rb +259 -58
- data/test/cases/base_test.rb +785 -138
- data/test/cases/calculations_test.rb +128 -8
- data/test/cases/migration_test.rb +680 -286
- data/test/cases/persistence_test.rb +642 -0
- data/test/cases/query_cache_test.rb +257 -0
- data/test/cases/relations_test.rb +1182 -0
- data/test/cases/schema_dumper_test.rb +41 -17
- data/test/cases/transaction_callbacks_test.rb +300 -0
- data/test/cases/validations/uniqueness_validation_test.rb +38 -22
- data/test/cases/xml_serialization_test.rb +408 -0
- data/test/config.yml +154 -0
- data/test/connections/native_ibm_db/connection.rb +2 -0
- data/test/models/warehouse_thing.rb +4 -4
- data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
- data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
- data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
- data/test/schema/schema.rb +196 -92
- data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
- metadata +73 -68
- data/.gitignore +0 -1
- data/test/cases/associations/eager_test.rb +0 -862
- data/test/cases/associations/has_many_through_associations_test.rb +0 -461
- data/test/cases/finder_test.rb +0 -1088
- data/test/cases/fixtures_test.rb +0 -684
data/ext/ruby_ibm_db.h
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
+----------------------------------------------------------------------+
|
3
3
|
| Licensed Materials - Property of IBM |
|
4
4
|
| |
|
5
|
-
| (C) Copyright IBM Corporation 2006, 2007, 2008, 2009, 2010
|
5
|
+
| (C) Copyright IBM Corporation 2006, 2007, 2008, 2009, 2010, 2012 |
|
6
6
|
+----------------------------------------------------------------------+
|
7
7
|
| Authors: Sushant Koduru, Lynh Nguyen, Kanchana Padmanabhan, |
|
8
8
|
| Dan Scott, Helmut Tessarek, Kellen Bombardier, Sam Ruby |
|
@@ -135,6 +135,9 @@ void Init_ibm_db();
|
|
135
135
|
/* Function Declarations */
|
136
136
|
|
137
137
|
VALUE ibm_db_connect(int argc, VALUE *argv, VALUE self);
|
138
|
+
VALUE ibm_db_createDB(int argc, VALUE *argv, VALUE self);
|
139
|
+
VALUE ibm_db_dropDB(int argc, VALUE *argv, VALUE self);
|
140
|
+
VALUE ibm_db_createDBNX(int argc, VALUE *argv, VALUE self);
|
138
141
|
VALUE ibm_db_commit(int argc, VALUE *argv, VALUE self);
|
139
142
|
VALUE ibm_db_pconnect(int argc, VALUE *argv, VALUE self);
|
140
143
|
VALUE ibm_db_autocommit(int argc, VALUE *argv, VALUE self);
|
data/ext/ruby_ibm_db_cli.c
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
+----------------------------------------------------------------------+
|
3
3
|
| Licensed Materials - Property of IBM |
|
4
4
|
| |
|
5
|
-
| (C) Copyright IBM Corporation 2009, 2010
|
5
|
+
| (C) Copyright IBM Corporation 2009, 2010, 2012 |
|
6
6
|
+----------------------------------------------------------------------+
|
7
7
|
| Authors: Praveen Devarao |
|
8
8
|
+----------------------------------------------------------------------+
|
@@ -372,6 +372,113 @@ int _ruby_ibm_db_SQLExecDirect_helper(exec_cum_prepare_args *data) {
|
|
372
372
|
return rc;
|
373
373
|
}
|
374
374
|
|
375
|
+
/*
|
376
|
+
This function calls SQLCreateDb cli call
|
377
|
+
*/
|
378
|
+
int _ruby_ibm_db_SQLCreateDB_helper(create_drop_db_args *data) {
|
379
|
+
int rc = 0;
|
380
|
+
#ifndef UNICODE_SUPPORT_VERSION
|
381
|
+
#ifdef _WIN32
|
382
|
+
HINSTANCE cliLib = NULL;
|
383
|
+
FARPROC sqlcreatedb;
|
384
|
+
cliLib = DLOPEN( LIBDB2 );
|
385
|
+
sqlcreatedb = DLSYM( cliLib, "SQLCreateDb" );
|
386
|
+
#elif _AIX
|
387
|
+
void *cliLib = NULL;
|
388
|
+
typedef int (*sqlcreatedbType)( SQLHDBC, SQLCHAR *, SQLINTEGER, SQLCHAR *, SQLINTEGER, SQLCHAR *, SQLINTEGER );
|
389
|
+
sqlcreatedbType sqlcreatedb;
|
390
|
+
/* On AIX CLI library is in archive. Hence we will need to specify flags in DLOPEN to load a member of the archive*/
|
391
|
+
cliLib = DLOPEN( LIBDB2, RTLD_MEMBER | RTLD_LAZY );
|
392
|
+
sqlcreatedb = (sqlcreatedbType) DLSYM( cliLib, "SQLCreateDb" );
|
393
|
+
#else
|
394
|
+
void *cliLib = NULL;
|
395
|
+
typedef int (*sqlcreatedbType)( SQLHDBC, SQLCHAR *, SQLINTEGER, SQLCHAR *, SQLINTEGER, SQLCHAR *, SQLINTEGER );
|
396
|
+
sqlcreatedbType sqlcreatedb;
|
397
|
+
cliLib = DLOPEN( LIBDB2, RTLD_LAZY );
|
398
|
+
sqlcreatedb = (sqlcreatedbType) DLSYM( cliLib, "SQLCreateDb" );
|
399
|
+
#endif
|
400
|
+
#else
|
401
|
+
#ifdef _WIN32
|
402
|
+
HINSTANCE cliLib = NULL;
|
403
|
+
FARPROC sqlcreatedb;
|
404
|
+
cliLib = DLOPEN( LIBDB2 );
|
405
|
+
sqlcreatedb = DLSYM( cliLib, "SQLCreateDbW" );
|
406
|
+
#elif _AIX
|
407
|
+
void *cliLib = NULL;
|
408
|
+
typedef int (*sqlcreatedbType)( SQLHDBC, SQLWCHAR *, SQLINTEGER, SQLWCHAR *, SQLINTEGER, SQLWCHAR *, SQLINTEGER );
|
409
|
+
sqlcreatedbType sqlcreatedb;
|
410
|
+
/* On AIX CLI library is in archive. Hence we will need to specify flags in DLOPEN to load a member of the archive*/
|
411
|
+
cliLib = DLOPEN( LIBDB2, RTLD_MEMBER | RTLD_LAZY );
|
412
|
+
sqlcreatedb = (sqlcreatedbType) DLSYM( cliLib, "SQLCreateDbW" );
|
413
|
+
#else
|
414
|
+
void *cliLib = NULL;
|
415
|
+
typedef int (*sqlcreatedbType)( SQLHDBC, SQLWCHAR *, SQLINTEGER, SQLWCHAR *, SQLINTEGER, SQLWCHAR *, SQLINTEGER );
|
416
|
+
sqlcreatedbType sqlcreatedb;
|
417
|
+
cliLib = DLOPEN( LIBDB2, RTLD_LAZY );
|
418
|
+
sqlcreatedb = (sqlcreatedbType) DLSYM( cliLib, "SQLCreateDbW" );
|
419
|
+
#endif
|
420
|
+
#endif
|
421
|
+
|
422
|
+
rc = (*sqlcreatedb)( (SQLHSTMT) data->conn_res->hdbc, data->dbName, (SQLINTEGER)data->dbName_string_len,
|
423
|
+
data->codeSet, (SQLINTEGER)data->codeSet_string_len,
|
424
|
+
data->mode, (SQLINTEGER)data->mode_string_len );
|
425
|
+
DLCLOSE( cliLib );
|
426
|
+
return rc;
|
427
|
+
}
|
428
|
+
|
429
|
+
/*
|
430
|
+
This function calls SQLDropDb cli call
|
431
|
+
*/
|
432
|
+
int _ruby_ibm_db_SQLDropDB_helper(create_drop_db_args *data) {
|
433
|
+
int rc = 0;
|
434
|
+
#ifndef UNICODE_SUPPORT_VERSION
|
435
|
+
#ifdef _WIN32
|
436
|
+
HINSTANCE cliLib = NULL;
|
437
|
+
FARPROC sqldropdb;
|
438
|
+
cliLib = DLOPEN( LIBDB2 );
|
439
|
+
sqldropdb = DLSYM( cliLib, "SQLDropDb" );
|
440
|
+
#elif _AIX
|
441
|
+
void *cliLib = NULL;
|
442
|
+
typedef int (*sqldropdbType)( SQLHDBC, SQLCHAR *, SQLINTEGER);
|
443
|
+
sqldropdbType sqldropdb;
|
444
|
+
/* On AIX CLI library is in archive. Hence we will need to specify flags in DLOPEN to load a member of the archive*/
|
445
|
+
cliLib = DLOPEN( LIBDB2, RTLD_MEMBER | RTLD_LAZY );
|
446
|
+
sqldropdb = (sqldropdbType) DLSYM( cliLib, "SQLDropDb" );
|
447
|
+
#else
|
448
|
+
void *cliLib = NULL;
|
449
|
+
typedef int (*sqldropdbType)( SQLHDBC, SQLCHAR *, SQLINTEGER);
|
450
|
+
sqldropdbType sqldropdb;
|
451
|
+
cliLib = DLOPEN( LIBDB2, RTLD_LAZY );
|
452
|
+
sqldropdb = (sqldropdbType) DLSYM( cliLib, "SQLDropDb" );
|
453
|
+
#endif
|
454
|
+
#else
|
455
|
+
#ifdef _WIN32
|
456
|
+
HINSTANCE cliLib = NULL;
|
457
|
+
FARPROC sqldropdb;
|
458
|
+
cliLib = DLOPEN( LIBDB2 );
|
459
|
+
sqldropdb = DLSYM( cliLib, "SQLDropDbW" );
|
460
|
+
#elif _AIX
|
461
|
+
void *cliLib = NULL;
|
462
|
+
typedef int (*sqldropdbType)( SQLHDBC, SQLWCHAR *, SQLINTEGER);
|
463
|
+
sqldropdbType sqldropdb;
|
464
|
+
/* On AIX CLI library is in archive. Hence we will need to specify flags in DLOPEN to load a member of the archive*/
|
465
|
+
cliLib = DLOPEN( LIBDB2, RTLD_MEMBER | RTLD_LAZY );
|
466
|
+
sqldropdb = (sqldropdbType) DLSYM( cliLib, "SQLDropDbW" );
|
467
|
+
#else
|
468
|
+
void *cliLib = NULL;
|
469
|
+
typedef int (*sqldropdbType)( SQLHDBC, SQLWCHAR *, SQLINTEGER);
|
470
|
+
sqldropdbType sqldropdb;
|
471
|
+
cliLib = DLOPEN( LIBDB2, RTLD_LAZY );
|
472
|
+
sqldropdb = (sqldropdbType) DLSYM( cliLib, "SQLDropDbW" );
|
473
|
+
#endif
|
474
|
+
#endif
|
475
|
+
|
476
|
+
rc = (*sqldropdb)( (SQLHSTMT) data->conn_res->hdbc, data->dbName, (SQLINTEGER)data->dbName_string_len );
|
477
|
+
|
478
|
+
DLCLOSE( cliLib );
|
479
|
+
return rc;
|
480
|
+
}
|
481
|
+
|
375
482
|
/*
|
376
483
|
This function calls SQLPrepare cli call to prepare the given statement
|
377
484
|
*/
|
data/ext/ruby_ibm_db_cli.h
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
+----------------------------------------------------------------------+
|
3
3
|
| Licensed Materials - Property of IBM |
|
4
4
|
| |
|
5
|
-
| (C) Copyright IBM Corporation 2009, 2010
|
5
|
+
| (C) Copyright IBM Corporation 2009, 2010, 2012 |
|
6
6
|
+----------------------------------------------------------------------+
|
7
7
|
| Authors: Praveen Devarao |
|
8
8
|
+----------------------------------------------------------------------+
|
@@ -11,6 +11,35 @@
|
|
11
11
|
#ifndef RUBY_IBM_DB_CLI_H
|
12
12
|
#define RUBY_IBM_DB_CLI_H
|
13
13
|
|
14
|
+
#ifdef _WIN32
|
15
|
+
#include <windows.h>
|
16
|
+
#else
|
17
|
+
#include <dlfcn.h>
|
18
|
+
#endif
|
19
|
+
|
20
|
+
#ifdef _WIN32
|
21
|
+
#define DLOPEN LoadLibrary
|
22
|
+
#define DLSYM GetProcAddress
|
23
|
+
#define DLCLOSE FreeLibrary
|
24
|
+
#define LIBDB2 "db2cli.dll"
|
25
|
+
#elif _AIX
|
26
|
+
#define DLOPEN dlopen
|
27
|
+
#define DLSYM dlsym
|
28
|
+
#define DLCLOSE dlclose
|
29
|
+
#ifdef __64BIT__
|
30
|
+
/*64-bit library in the archive libdb2.a*/
|
31
|
+
#define LIBDB2 "libdb2.a(shr_64.o)"
|
32
|
+
#else
|
33
|
+
/*32-bit library in the archive libdb2.a*/
|
34
|
+
#define LIBDB2 "libdb2.a(shr.o)"
|
35
|
+
#endif
|
36
|
+
#else
|
37
|
+
#define DLOPEN dlopen
|
38
|
+
#define DLSYM dlsym
|
39
|
+
#define DLCLOSE dlclose
|
40
|
+
#define LIBDB2 "libdb2.so.1"
|
41
|
+
#endif
|
42
|
+
|
14
43
|
#include <ruby.h>
|
15
44
|
#include <stdio.h>
|
16
45
|
#include <string.h>
|
@@ -54,6 +83,8 @@ typedef struct _conn_handle_struct {
|
|
54
83
|
SQLPOINTER ruby_error_state;
|
55
84
|
SQLSMALLINT ruby_error_msg_len;
|
56
85
|
|
86
|
+
SQLINTEGER sqlcode;
|
87
|
+
|
57
88
|
} conn_handle;
|
58
89
|
|
59
90
|
typedef union {
|
@@ -114,6 +145,7 @@ typedef struct _stmt_handle_struct {
|
|
114
145
|
SQLPOINTER ruby_stmt_err_msg;
|
115
146
|
SQLPOINTER ruby_stmt_err_state;
|
116
147
|
SQLSMALLINT ruby_stmt_err_msg_len;
|
148
|
+
SQLINTEGER sqlcode;
|
117
149
|
} stmt_handle;
|
118
150
|
|
119
151
|
/*
|
@@ -211,6 +243,25 @@ typedef struct _ibm_db_exec_direct_args_struct {
|
|
211
243
|
long stmt_string_len;
|
212
244
|
} exec_cum_prepare_args;
|
213
245
|
|
246
|
+
/*
|
247
|
+
Structure holding the necessary info to be passed to SQLCreateDB and SQLDropDB CLI call
|
248
|
+
*/
|
249
|
+
typedef struct _ibm_db_create_drop_db_args_struct {
|
250
|
+
conn_handle *conn_res;
|
251
|
+
#ifdef UNICODE_SUPPORT_VERSION
|
252
|
+
SQLWCHAR *dbName;
|
253
|
+
SQLWCHAR *codeSet;
|
254
|
+
SQLWCHAR *mode;
|
255
|
+
#else
|
256
|
+
SQLCHAR *dbName;
|
257
|
+
SQLCHAR *codeSet;
|
258
|
+
SQLCHAR *mode;
|
259
|
+
#endif
|
260
|
+
long dbName_string_len;
|
261
|
+
long codeSet_string_len;
|
262
|
+
long mode_string_len;
|
263
|
+
} create_drop_db_args;
|
264
|
+
|
214
265
|
/*
|
215
266
|
Structure holding the necessary info to be passed to SQLParamData and SQLPutData CLI call
|
216
267
|
*/
|
@@ -427,5 +478,7 @@ int _ruby_ibm_db_SQLGetConnectAttr_helper(get_handle_attr_args *data);
|
|
427
478
|
int _ruby_ibm_db_SQLBindFileToParam_helper(stmt_handle *stmt_res, param_node *curr);
|
428
479
|
int _ruby_ibm_db_SQLBindParameter_helper(bind_parameter_args *data);
|
429
480
|
void _ruby_ibm_db_Statement_level_UBF(stmt_handle *stmt_res);
|
481
|
+
int _ruby_ibm_db_SQLCreateDB_helper(create_drop_db_args *data);
|
482
|
+
int _ruby_ibm_db_SQLDropDB_helper(create_drop_db_args *data);
|
430
483
|
|
431
484
|
#endif /* RUBY_IBM_DB_CLI_H */
|
@@ -44,10 +44,15 @@ module ActiveRecord
|
|
44
44
|
# (except for a CLOB field where '' can be a value)
|
45
45
|
if self[col.name].nil? ||
|
46
46
|
self[col.name] == {} ||
|
47
|
+
self[col.name] == [] ||
|
47
48
|
(self[col.name] == '' && col.type != :text)
|
48
49
|
params << 'NULL'
|
49
50
|
else
|
50
|
-
|
51
|
+
if self.class.serialized_attributes[col.name]
|
52
|
+
values << YAML.dump(self[col.name])
|
53
|
+
else
|
54
|
+
values << self[col.name]
|
55
|
+
end
|
51
56
|
params << '?'
|
52
57
|
end
|
53
58
|
counter += 1
|
@@ -117,24 +122,31 @@ module ActiveRecord
|
|
117
122
|
# Flag to decide if quoted literal replcement should take place. By default it is ON. Set it to OFF if using Pstmt
|
118
123
|
set_quoted_literal_replacement = IBM_DB::QUOTED_LITERAL_REPLACEMENT_ON
|
119
124
|
|
120
|
-
# Retrieves the database alias (local catalog name) or remote name
|
121
|
-
# (for remote TCP/IP connections) from the +config+ hash
|
122
|
-
# or raises ArgumentError in case of failure.
|
123
|
-
if config.has_key?(:database)
|
124
|
-
database = config[:database].to_s
|
125
|
-
else
|
126
|
-
raise ArgumentError, "Missing argument: a database name needs to be specified."
|
127
|
-
end
|
128
|
-
|
129
125
|
# Retrieves database user credentials from the +config+ hash
|
130
126
|
# or raises ArgumentError in case of failure.
|
131
127
|
if !config.has_key?(:username) || !config.has_key?(:password)
|
132
128
|
raise ArgumentError, "Missing argument(s): Username/Password for #{config[:database]} is not specified"
|
133
129
|
else
|
130
|
+
if(config[:username].to_s.nil? || config[:password].to_s.nil?)
|
131
|
+
raise ArgumentError, "Username/Password cannot be nil"
|
132
|
+
end
|
134
133
|
username = config[:username].to_s
|
135
134
|
password = config[:password].to_s
|
136
135
|
end
|
137
136
|
|
137
|
+
if(config.has_key?(:dbops) && config[:dbops] == true)
|
138
|
+
return ConnectionAdapters::IBM_DBAdapter.new(nil, logger, config, {})
|
139
|
+
end
|
140
|
+
|
141
|
+
# Retrieves the database alias (local catalog name) or remote name
|
142
|
+
# (for remote TCP/IP connections) from the +config+ hash
|
143
|
+
# or raises ArgumentError in case of failure.
|
144
|
+
if config.has_key?(:database)
|
145
|
+
database = config[:database].to_s
|
146
|
+
else
|
147
|
+
raise ArgumentError, "Missing argument: a database name needs to be specified."
|
148
|
+
end
|
149
|
+
|
138
150
|
# Providing default schema (username) when not specified
|
139
151
|
config[:schema] = config.has_key?(:schema) ? config[:schema].to_s : config[:username].to_s
|
140
152
|
|
@@ -232,8 +244,6 @@ module ActiveRecord
|
|
232
244
|
:binary
|
233
245
|
when /smallint/i
|
234
246
|
:boolean
|
235
|
-
when /bigint/i
|
236
|
-
:bigint
|
237
247
|
when /int|serial/i
|
238
248
|
:integer
|
239
249
|
when /decimal|numeric|decfloat/i
|
@@ -481,7 +491,8 @@ module ActiveRecord
|
|
481
491
|
end
|
482
492
|
when /DB2/i # DB2 for zOS
|
483
493
|
case server_info.DBMS_VER
|
484
|
-
when /09/ # DB2 for zOS version 9
|
494
|
+
when /09/ # DB2 for zOS version 9 and version 10
|
495
|
+
when /10/
|
485
496
|
@servertype = IBM_DB2_ZOS.new(self)
|
486
497
|
when /08/ # DB2 for zOS version 8
|
487
498
|
@servertype = IBM_DB2_ZOS_8.new(self)
|
@@ -513,6 +524,17 @@ module ActiveRecord
|
|
513
524
|
else
|
514
525
|
@start_id = 1
|
515
526
|
end
|
527
|
+
|
528
|
+
#Check Arel version
|
529
|
+
begin
|
530
|
+
@arelVersion = Arel::VERSION.to_i
|
531
|
+
rescue
|
532
|
+
@arelVersion = 0
|
533
|
+
end
|
534
|
+
|
535
|
+
if(@arelVersion >= 3 )
|
536
|
+
@visitor = Arel::Visitors::IBM_DB.new self
|
537
|
+
end
|
516
538
|
end
|
517
539
|
|
518
540
|
# Optional connection attribute: database name space qualifier
|
@@ -563,6 +585,20 @@ module ActiveRecord
|
|
563
585
|
end
|
564
586
|
end
|
565
587
|
|
588
|
+
def self.visitor_for(pool)
|
589
|
+
Arel::Visitors::IBM_DB.new(pool)
|
590
|
+
end
|
591
|
+
|
592
|
+
def to_sql(arel, binds = [])
|
593
|
+
if arel.respond_to?(:ast)
|
594
|
+
visitor.accept(arel.ast) do
|
595
|
+
quote(*binds.shift.reverse)
|
596
|
+
end
|
597
|
+
else
|
598
|
+
arel
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
566
602
|
# This adapter supports migrations.
|
567
603
|
# Current limitations:
|
568
604
|
# +rename_column+ is not currently supported by the IBM data servers
|
@@ -599,6 +635,10 @@ module ActiveRecord
|
|
599
635
|
# It connects to the database with the initially provided credentials
|
600
636
|
def connect
|
601
637
|
# If the type of connection is net based
|
638
|
+
if(@username.nil? || @password.nil?)
|
639
|
+
raise ArgumentError, "Username/Password cannot be nil"
|
640
|
+
end
|
641
|
+
|
602
642
|
begin
|
603
643
|
if @host
|
604
644
|
@conn_string = "DRIVER={IBM DB2 ODBC DRIVER};\
|
@@ -641,6 +681,7 @@ module ActiveRecord
|
|
641
681
|
# * true if succesfull
|
642
682
|
# * false if the connection is already closed
|
643
683
|
# * nil if an error is raised
|
684
|
+
return nil if @connection.nil? || @connection == false
|
644
685
|
IBM_DB.close(@connection) rescue nil
|
645
686
|
end
|
646
687
|
|
@@ -679,7 +720,7 @@ module ActiveRecord
|
|
679
720
|
pstmt = prepare(sql_param_hash["sqlSegment"], name)
|
680
721
|
if(execute_prepared_stmt(pstmt, sql_param_hash["paramArray"]))
|
681
722
|
begin
|
682
|
-
@servertype.select(
|
723
|
+
results = @servertype.select(pstmt)
|
683
724
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
684
725
|
error_msg = IBM_DB.getErrormsg(pstmt, IBM_DB::DB_STMT )
|
685
726
|
if error_msg && !error_msg.empty?
|
@@ -703,14 +744,13 @@ module ActiveRecord
|
|
703
744
|
# and +name+ is an optional description for logging
|
704
745
|
def prepared_select_values(sql_param_hash, name = nil)
|
705
746
|
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
706
|
-
|
707
747
|
results = []
|
708
748
|
# Invokes the method +prepare+ in order prepare the SQL
|
709
749
|
# IBM_DB.Statement is returned from which the statement is executed and results fetched
|
710
750
|
pstmt = prepare(sql_param_hash["sqlSegment"], name)
|
711
751
|
if(execute_prepared_stmt(pstmt, sql_param_hash["paramArray"]))
|
712
752
|
begin
|
713
|
-
@servertype.select_rows(sql_param_hash["sqlSegment"], name, pstmt, results)
|
753
|
+
results = @servertype.select_rows(sql_param_hash["sqlSegment"], name, pstmt, results)
|
714
754
|
if results
|
715
755
|
return results.map { |v| v[0] }
|
716
756
|
else
|
@@ -734,20 +774,11 @@ module ActiveRecord
|
|
734
774
|
results
|
735
775
|
end
|
736
776
|
|
737
|
-
#
|
738
|
-
|
739
|
-
# and +name+ is an optional description for logging
|
740
|
-
def select(sql, name = nil)
|
741
|
-
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
742
|
-
sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
|
743
|
-
|
744
|
-
results = []
|
745
|
-
# Invokes the method +execute+ in order to log and execute the SQL
|
746
|
-
# IBM_DB.Statement is returned from which results can be fetched
|
747
|
-
stmt = execute(sql, name)
|
777
|
+
#Calls the servertype select method to fetch the data
|
778
|
+
def fetch_data(stmt)
|
748
779
|
if(stmt)
|
749
780
|
begin
|
750
|
-
@servertype.select(
|
781
|
+
return @servertype.select(stmt)
|
751
782
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
752
783
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
753
784
|
if error_msg && !error_msg.empty?
|
@@ -758,13 +789,47 @@ module ActiveRecord
|
|
758
789
|
raise error_msg
|
759
790
|
end
|
760
791
|
ensure
|
761
|
-
|
792
|
+
# Ensures to free the resources associated with the statement
|
762
793
|
IBM_DB.free_stmt(stmt) if stmt
|
763
794
|
end
|
764
795
|
end
|
796
|
+
end
|
797
|
+
=begin
|
798
|
+
# Returns an array of hashes with the column names as keys and
|
799
|
+
# column values as values. +sql+ is the select query,
|
800
|
+
# and +name+ is an optional description for logging
|
801
|
+
def select(sql, name = nil)
|
802
|
+
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
803
|
+
sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
|
804
|
+
|
805
|
+
results = []
|
806
|
+
# Invokes the method +execute+ in order to log and execute the SQL
|
807
|
+
# IBM_DB.Statement is returned from which results can be fetched
|
808
|
+
stmt = execute(sql, name)
|
809
|
+
|
810
|
+
results = fetch_data(stmt)
|
765
811
|
# The array of record hashes is returned
|
766
812
|
results
|
767
813
|
end
|
814
|
+
=end
|
815
|
+
def select(sql, name = nil, binds = [])
|
816
|
+
# Replaces {"= NULL" with " IS NULL"} OR {"IN (NULL)" with " IS NULL"}
|
817
|
+
sql.gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" )
|
818
|
+
|
819
|
+
results = []
|
820
|
+
|
821
|
+
if(binds.nil? || binds.empty?)
|
822
|
+
stmt = execute(sql, name)
|
823
|
+
else
|
824
|
+
stmt = exec_query(sql, name, binds)
|
825
|
+
end
|
826
|
+
|
827
|
+
if( stmt )
|
828
|
+
results = fetch_data(stmt)
|
829
|
+
end
|
830
|
+
|
831
|
+
return results
|
832
|
+
end
|
768
833
|
|
769
834
|
#Returns an array of arrays containing the field values.
|
770
835
|
#This is an implementation for the abstract method
|
@@ -779,7 +844,7 @@ module ActiveRecord
|
|
779
844
|
stmt = execute(sql, name)
|
780
845
|
if(stmt)
|
781
846
|
begin
|
782
|
-
@servertype.select_rows(sql, name, stmt, results)
|
847
|
+
results = @servertype.select_rows(sql, name, stmt, results)
|
783
848
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
784
849
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
785
850
|
if error_msg && !error_msg.empty?
|
@@ -810,7 +875,12 @@ module ActiveRecord
|
|
810
875
|
#overridden to handle LOB's fixture insertion, as, in normal inserts callbacks are triggered but during fixture insertion callbacks are not triggered
|
811
876
|
#hence only markers like @@@IBMBINARY@@@ will be inserted and are not updated to actual data
|
812
877
|
def insert_fixture(fixture, table_name)
|
813
|
-
|
878
|
+
if(fixture.respond_to?(:keys))
|
879
|
+
insert_query = "INSERT INTO #{quote_table_name(table_name)} ( #{fixture.keys.join(', ')})"
|
880
|
+
else
|
881
|
+
insert_query = "INSERT INTO #{quote_table_name(table_name)} ( #{fixture.key_list})"
|
882
|
+
end
|
883
|
+
|
814
884
|
insert_values = []
|
815
885
|
params = []
|
816
886
|
if @servertype.instance_of? IBM_IDS
|
@@ -870,7 +940,7 @@ module ActiveRecord
|
|
870
940
|
# Perform an insert and returns the last ID generated.
|
871
941
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
872
942
|
# and retrieved by the +last_generated_id+ method.
|
873
|
-
def
|
943
|
+
def insert_direct(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
874
944
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
875
945
|
@sql = []
|
876
946
|
@handle_lobs_triggered = false
|
@@ -889,11 +959,30 @@ module ActiveRecord
|
|
889
959
|
end
|
890
960
|
end
|
891
961
|
|
962
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [] )
|
963
|
+
sql, binds = [to_sql(arel),binds]
|
964
|
+
|
965
|
+
#unless IBM_DBAdapter.respond_to?(:exec_insert)
|
966
|
+
if binds.nil? || binds.empty?
|
967
|
+
return insert_direct(sql, name, pk, id_value, sequence_name)
|
968
|
+
end
|
969
|
+
|
970
|
+
clear_query_cache if defined? clear_query_cache
|
971
|
+
if stmt = exec_insert(sql, name, binds)
|
972
|
+
begin
|
973
|
+
@sql << sql
|
974
|
+
return id_value || @servertype.last_generated_id(stmt)
|
975
|
+
ensure
|
976
|
+
IBM_DB.free_stmt(stmt) if stmt
|
977
|
+
end
|
978
|
+
end
|
979
|
+
end
|
980
|
+
|
892
981
|
# Praveen
|
893
982
|
# Performs an insert using the prepared statement and returns the last ID generated.
|
894
983
|
# This can be the ID passed to the method or the one auto-generated by the database,
|
895
984
|
# and retrieved by the +last_generated_id+ method.
|
896
|
-
def prepared_insert(pstmt, param_array = nil)
|
985
|
+
def prepared_insert(pstmt, param_array = nil, id_value = nil)
|
897
986
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
898
987
|
@sql = []
|
899
988
|
@sql_parameter_values = []
|
@@ -906,7 +995,7 @@ module ActiveRecord
|
|
906
995
|
if execute_prepared_stmt(pstmt, param_array)
|
907
996
|
@sql << @prepared_sql
|
908
997
|
@sql_parameter_values << param_array
|
909
|
-
return @servertype.last_generated_id(pstmt)
|
998
|
+
return id_value || @servertype.last_generated_id(pstmt)
|
910
999
|
end
|
911
1000
|
rescue StandardError => insert_err
|
912
1001
|
raise insert_err
|
@@ -948,6 +1037,29 @@ module ActiveRecord
|
|
948
1037
|
end
|
949
1038
|
end
|
950
1039
|
|
1040
|
+
# Executes +sql+ statement in the context of this connection using
|
1041
|
+
# +binds+ as the bind substitutes. +name+ is logged along with
|
1042
|
+
# the executed +sql+ statement.
|
1043
|
+
def exec_query(sql, name = 'SQL', binds = [])
|
1044
|
+
begin
|
1045
|
+
param_array = binds.map do |column,value|
|
1046
|
+
quote_value_for_pstmt(value, column)
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
stmt = prepare(sql, name)
|
1050
|
+
|
1051
|
+
if( stmt )
|
1052
|
+
if(execute_prepared_stmt(stmt, param_array))
|
1053
|
+
return stmt
|
1054
|
+
end
|
1055
|
+
else
|
1056
|
+
return false
|
1057
|
+
end
|
1058
|
+
ensure
|
1059
|
+
@offset = @limit = nil
|
1060
|
+
end
|
1061
|
+
end
|
1062
|
+
|
951
1063
|
# Executes and logs +sql+ commands and
|
952
1064
|
# returns a +IBM_DB.Statement+ object.
|
953
1065
|
def execute(sql, name = nil)
|
@@ -959,29 +1071,12 @@ module ActiveRecord
|
|
959
1071
|
end
|
960
1072
|
|
961
1073
|
# Executes an "UPDATE" SQL statement
|
962
|
-
def
|
1074
|
+
def update_direct(sql, name = nil)
|
963
1075
|
if @handle_lobs_triggered #Ensure the array of sql is cleared if they have been handled in the callback
|
964
1076
|
@sql = []
|
965
1077
|
@handle_lobs_triggered = false
|
966
1078
|
end
|
967
1079
|
|
968
|
-
clear_query_cache if defined? clear_query_cache
|
969
|
-
|
970
|
-
# Make sure the WHERE clause handles NULL's correctly
|
971
|
-
sqlarray = sql.split(/\s*WHERE\s*/)
|
972
|
-
size = sqlarray.size
|
973
|
-
if size > 1
|
974
|
-
sql = sqlarray[0] + " WHERE "
|
975
|
-
if size > 2
|
976
|
-
1.upto size-2 do |index|
|
977
|
-
sqlarray[index].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" ) unless sqlarray[index].nil?
|
978
|
-
sql = sql + sqlarray[index] + " WHERE "
|
979
|
-
end
|
980
|
-
end
|
981
|
-
sqlarray[size-1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" ) unless sqlarray[size-1].nil?
|
982
|
-
sql = sql + sqlarray[size-1]
|
983
|
-
end
|
984
|
-
|
985
1080
|
# Logs and execute the given sql query.
|
986
1081
|
if stmt = execute(sql, name)
|
987
1082
|
begin
|
@@ -1022,9 +1117,39 @@ module ActiveRecord
|
|
1022
1117
|
# The delete method executes the delete
|
1023
1118
|
# statement and returns the number of affected rows.
|
1024
1119
|
# The method is an alias for +update+
|
1025
|
-
alias_method :delete, :update
|
1026
1120
|
alias_method :prepared_delete, :prepared_update
|
1027
1121
|
|
1122
|
+
def update(arel, name = nil, binds = [])
|
1123
|
+
sql = to_sql(arel)
|
1124
|
+
|
1125
|
+
# Make sure the WHERE clause handles NULL's correctly
|
1126
|
+
sqlarray = sql.split(/\s*WHERE\s*/)
|
1127
|
+
size = sqlarray.size
|
1128
|
+
if size > 1
|
1129
|
+
sql = sqlarray[0] + " WHERE "
|
1130
|
+
if size > 2
|
1131
|
+
1.upto size-2 do |index|
|
1132
|
+
sqlarray[index].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" ) unless sqlarray[index].nil?
|
1133
|
+
sql = sql + sqlarray[index] + " WHERE "
|
1134
|
+
end
|
1135
|
+
end
|
1136
|
+
sqlarray[size-1].gsub!( /(=\s*NULL|IN\s*\(NULL\))/i, " IS NULL" ) unless sqlarray[size-1].nil?
|
1137
|
+
sql = sql + sqlarray[size-1]
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
clear_query_cache if defined? clear_query_cache
|
1141
|
+
|
1142
|
+
if binds.nil? || binds.empty?
|
1143
|
+
update_direct(sql, name)
|
1144
|
+
else
|
1145
|
+
if stmt = exec_query(sql,name,binds)
|
1146
|
+
IBM_DB.num_rows(stmt)
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
alias_method :delete, :update
|
1152
|
+
|
1028
1153
|
# Begins the transaction (and turns off auto-committing)
|
1029
1154
|
def begin_db_transaction
|
1030
1155
|
# Turns off the auto-commit
|
@@ -1065,27 +1190,26 @@ module ActiveRecord
|
|
1065
1190
|
# generates "SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_rownum
|
1066
1191
|
# FROM (SELECT * FROM staff) AS I) AS O WHERE sys_row_num BETWEEN 31 AND 40"
|
1067
1192
|
def add_limit_offset!(sql, options)
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
sql = @servertype.query_offset_limit(sql, 0, limit)
|
1078
|
-
end
|
1079
|
-
# If there is a non-zero limit
|
1193
|
+
limit = options[:limit]
|
1194
|
+
offset = options[:offset]
|
1195
|
+
|
1196
|
+
# if the limit is zero
|
1197
|
+
if limit && limit == 0
|
1198
|
+
# Returns a query that will always generate zero records
|
1199
|
+
# (e.g. WHERE sys_row_num BETWEEN 1 and 0)
|
1200
|
+
if( @pstmt_support_on )
|
1201
|
+
sql = @servertype.query_offset_limit!(sql, 0, limit, options)
|
1080
1202
|
else
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1203
|
+
sql = @servertype.query_offset_limit(sql, 0, limit)
|
1204
|
+
end
|
1205
|
+
# If there is a non-zero limit
|
1206
|
+
else
|
1207
|
+
# If an offset is specified builds the query with offset and limit,
|
1208
|
+
# otherwise retrieves only the first +limit+ rows
|
1209
|
+
if( @pstmt_support_on )
|
1210
|
+
sql = @servertype.query_offset_limit!(sql, offset, limit, options)
|
1211
|
+
else
|
1212
|
+
sql = @servertype.query_offset_limit(sql, offset, limit)
|
1089
1213
|
end
|
1090
1214
|
end
|
1091
1215
|
# Returns the sql query in any case
|
@@ -1121,6 +1245,7 @@ module ActiveRecord
|
|
1121
1245
|
when Float, Fixnum, Bignum then value
|
1122
1246
|
# BigDecimals need to be output in a non-normalized form and quoted.
|
1123
1247
|
when BigDecimal then value.to_s('F')
|
1248
|
+
when Numeric, Symbol then value.to_s
|
1124
1249
|
else
|
1125
1250
|
if value.acts_like?(:date) || value.acts_like?(:time)
|
1126
1251
|
quoted_date(value)
|
@@ -1133,6 +1258,8 @@ module ActiveRecord
|
|
1133
1258
|
# Properly quotes the various data types.
|
1134
1259
|
# +value+ contains the data, +column+ is optional and contains info on the field
|
1135
1260
|
def quote(value, column = nil)
|
1261
|
+
return value.quoted_id if value.respond_to?(:quoted_id)
|
1262
|
+
|
1136
1263
|
case value
|
1137
1264
|
# If it's a numeric value and the column type is not a string, it shouldn't be quoted
|
1138
1265
|
# (IBM_DB doesn't accept quotes on numeric types)
|
@@ -1173,14 +1300,22 @@ module ActiveRecord
|
|
1173
1300
|
end
|
1174
1301
|
else
|
1175
1302
|
unless caller[0] =~ /insert_fixture/i
|
1176
|
-
|
1303
|
+
super
|
1177
1304
|
else
|
1178
1305
|
"#{value}"
|
1179
1306
|
end
|
1180
1307
|
end
|
1181
1308
|
when TrueClass then quoted_true # return '1' for true
|
1182
1309
|
when FalseClass then quoted_false # return '0' for false
|
1183
|
-
|
1310
|
+
when nil then "NULL"
|
1311
|
+
when Date, Time then "'#{quoted_date(value)}'"
|
1312
|
+
when Symbol then "'#{quote_string(value.to_s)}'"
|
1313
|
+
else
|
1314
|
+
unless caller[0] =~ /insert_fixture/i
|
1315
|
+
"'#{quote_string(YAML.dump(value))}'"
|
1316
|
+
else
|
1317
|
+
"#{quote_string(YAML.dump(value))}"
|
1318
|
+
end
|
1184
1319
|
end
|
1185
1320
|
end
|
1186
1321
|
|
@@ -1240,6 +1375,63 @@ module ActiveRecord
|
|
1240
1375
|
}
|
1241
1376
|
end
|
1242
1377
|
|
1378
|
+
def build_conn_str_for_dbops()
|
1379
|
+
connect_str = "DRIVER={IBM DB2 ODBC DRIVER};ATTACH=true;"
|
1380
|
+
if(!@host.nil?)
|
1381
|
+
connect_str << "HOSTNAME=#{@host};"
|
1382
|
+
connect_str << "PORT=#{@port};"
|
1383
|
+
connect_str << "PROTOCOL=TCPIP;"
|
1384
|
+
end
|
1385
|
+
connect_str << "UID=#{@username};PWD=#{@password};"
|
1386
|
+
return connect_str
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
def drop_database(dbName)
|
1390
|
+
connect_str = build_conn_str_for_dbops()
|
1391
|
+
|
1392
|
+
#Ensure connection is closed before trying to drop a database.
|
1393
|
+
#As a connect call would have been made by call seeing connection in active
|
1394
|
+
disconnect!
|
1395
|
+
|
1396
|
+
begin
|
1397
|
+
dropConn = IBM_DB.connect(connect_str, '', '')
|
1398
|
+
rescue StandardError => connect_err
|
1399
|
+
raise "Failed to connect to server due to: #{connect_err}"
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
if(IBM_DB.dropDB(dropConn,dbName))
|
1403
|
+
IBM_DB.close(dropConn)
|
1404
|
+
return true
|
1405
|
+
else
|
1406
|
+
error = IBM_DB.getErrormsg(dropConn, IBM_DB::DB_CONN)
|
1407
|
+
IBM_DB.close(dropConn)
|
1408
|
+
raise "Could not drop Database due to: #{error}"
|
1409
|
+
end
|
1410
|
+
end
|
1411
|
+
|
1412
|
+
def create_database(dbName, codeSet=nil, mode=nil)
|
1413
|
+
connect_str = build_conn_str_for_dbops()
|
1414
|
+
|
1415
|
+
#Ensure connection is closed before trying to drop a database.
|
1416
|
+
#As a connect call would have been made by call seeing connection in active
|
1417
|
+
disconnect!
|
1418
|
+
|
1419
|
+
begin
|
1420
|
+
createConn = IBM_DB.connect(connect_str, '', '')
|
1421
|
+
rescue StandardError => connect_err
|
1422
|
+
raise "Failed to connect to server due to: #{connect_err}"
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
if(IBM_DB.createDB(createConn,dbName,codeSet,mode))
|
1426
|
+
IBM_DB.close(createConn)
|
1427
|
+
return true
|
1428
|
+
else
|
1429
|
+
error = IBM_DB.getErrormsg(createConn, IBM_DB::DB_CONN)
|
1430
|
+
IBM_DB.close(createConn)
|
1431
|
+
raise "Could not create Database due to: #{error}"
|
1432
|
+
end
|
1433
|
+
end
|
1434
|
+
|
1243
1435
|
# IBM data servers do not support limits on certain data types (unlike MySQL)
|
1244
1436
|
# Limit is supported for the {float, decimal, numeric, varchar, clob, blob, graphic, vargraphic} data types.
|
1245
1437
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
@@ -1272,13 +1464,16 @@ module ActiveRecord
|
|
1272
1464
|
# Initializes the tables array
|
1273
1465
|
tables = []
|
1274
1466
|
# Retrieve table's metadata through IBM_DB driver
|
1275
|
-
stmt = IBM_DB.tables(@connection, nil,
|
1467
|
+
stmt = IBM_DB.tables(@connection, nil,
|
1468
|
+
@servertype.set_case(@schema))
|
1276
1469
|
if(stmt)
|
1277
1470
|
begin
|
1278
1471
|
# Fetches all the records available
|
1279
1472
|
while tab = IBM_DB.fetch_assoc(stmt)
|
1280
1473
|
# Adds the lowercase table name to the array
|
1281
|
-
|
1474
|
+
if(tab["table_type"]== 'TABLE') #check, so that only tables are dumped,IBM_DB.tables also returns views,alias etc in the schema
|
1475
|
+
tables << tab["table_name"].downcase
|
1476
|
+
end
|
1282
1477
|
end
|
1283
1478
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
1284
1479
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
@@ -1482,6 +1677,8 @@ module ActiveRecord
|
|
1482
1677
|
column_default_value = col["column_def"]
|
1483
1678
|
# If there is no default value, it assigns NIL
|
1484
1679
|
column_default_value = nil if (column_default_value && column_default_value.upcase == 'NULL')
|
1680
|
+
# If default value is IDENTITY GENERATED BY DEFAULT (this value is retrieved in case of id columns)
|
1681
|
+
column_default_value = nil if (column_default_value && column_default_value.upcase =~ /IDENTITY GENERATED BY DEFAULT/i)
|
1485
1682
|
# Removes single quotes from the default value
|
1486
1683
|
column_default_value.gsub!(/^'(.*)'$/, '\1') unless column_default_value.nil?
|
1487
1684
|
# Assigns the column type
|
@@ -1600,6 +1797,15 @@ module ActiveRecord
|
|
1600
1797
|
end
|
1601
1798
|
=end
|
1602
1799
|
|
1800
|
+
#Add distinct clause to the sql if there is no order by specified
|
1801
|
+
def distinct(columns, order_by)
|
1802
|
+
if order_by.nil?
|
1803
|
+
"DISTINCT #{columns}"
|
1804
|
+
else
|
1805
|
+
"#{columns}"
|
1806
|
+
end
|
1807
|
+
end
|
1808
|
+
|
1603
1809
|
# Sets a new default value for a column. This does not set the default
|
1604
1810
|
# value to +NULL+, instead, it needs DatabaseStatements#execute which
|
1605
1811
|
# can execute the appropriate SQL statement for setting the value.
|
@@ -1653,7 +1859,7 @@ module ActiveRecord
|
|
1653
1859
|
end
|
1654
1860
|
|
1655
1861
|
def check_reserved_words(col_name)
|
1656
|
-
col_name
|
1862
|
+
col_name.to_s
|
1657
1863
|
end
|
1658
1864
|
|
1659
1865
|
# This is supported by the DB2 for Linux, UNIX, Windows data servers
|
@@ -1674,7 +1880,8 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
1674
1880
|
end
|
1675
1881
|
end
|
1676
1882
|
|
1677
|
-
def select(
|
1883
|
+
def select(stmt)
|
1884
|
+
results = []
|
1678
1885
|
# Fetches all the results available. IBM_DB.fetch_assoc(stmt) returns
|
1679
1886
|
# an hash for each single record.
|
1680
1887
|
# The loop stops when there aren't any more valid records to fetch
|
@@ -1693,6 +1900,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
1693
1900
|
raise error_msg
|
1694
1901
|
end
|
1695
1902
|
end
|
1903
|
+
return results
|
1696
1904
|
end
|
1697
1905
|
|
1698
1906
|
def select_rows(sql, name, stmt, results)
|
@@ -1714,6 +1922,7 @@ To remove the column, the table must be dropped and recreated without the #{colu
|
|
1714
1922
|
raise error_msg
|
1715
1923
|
end
|
1716
1924
|
end
|
1925
|
+
return results
|
1717
1926
|
end
|
1718
1927
|
|
1719
1928
|
# Praveen
|
@@ -1919,11 +2128,14 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
1919
2128
|
def get_double_mapping
|
1920
2129
|
return "double"
|
1921
2130
|
end
|
1922
|
-
|
2131
|
+
=begin
|
2132
|
+
# Commenting this code, as offset handling is now part of sql and we need to handle it in select and also
|
2133
|
+
# need not set cursor type during prepare or execute
|
1923
2134
|
# Fetches all the results available. IBM_DB.fetch_assoc(stmt) returns
|
1924
2135
|
# an hash for each single record.
|
1925
2136
|
# The loop stops when there aren't any more valid records to fetch
|
1926
|
-
def select(
|
2137
|
+
def select(stmt)
|
2138
|
+
results = []
|
1927
2139
|
begin
|
1928
2140
|
if (!@offset.nil? && @offset >= 0) || (!@limit.nil? && @limit > 0)
|
1929
2141
|
# We know at this point that there is an offset and/or a limit
|
@@ -1973,6 +2185,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
1973
2185
|
# Add the record to the +results+ array
|
1974
2186
|
results << single_hash
|
1975
2187
|
end
|
2188
|
+
return results
|
1976
2189
|
end
|
1977
2190
|
rescue StandardError => fetch_error # Handle driver fetch errors
|
1978
2191
|
error_msg = IBM_DB.getErrormsg(stmt, IBM_DB::DB_STMT )
|
@@ -2058,6 +2271,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2058
2271
|
@offset = nil
|
2059
2272
|
@limit = nil
|
2060
2273
|
end
|
2274
|
+
return results
|
2061
2275
|
end
|
2062
2276
|
|
2063
2277
|
# Praveen
|
@@ -2113,22 +2327,62 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2113
2327
|
raise error_msg
|
2114
2328
|
end
|
2115
2329
|
end
|
2116
|
-
|
2330
|
+
=end
|
2117
2331
|
def query_offset_limit(sql, offset, limit)
|
2118
|
-
|
2119
|
-
|
2332
|
+
if(offset.nil? && limit.nil?)
|
2333
|
+
return sql
|
2334
|
+
end
|
2335
|
+
|
2120
2336
|
if (offset.nil?)
|
2121
|
-
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2337
|
+
return sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2338
|
+
end
|
2339
|
+
|
2340
|
+
if(limit.nil?)
|
2341
|
+
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2342
|
+
return sql << ") AS I) AS O WHERE sys_row_num > #{offset}"
|
2122
2343
|
end
|
2344
|
+
|
2345
|
+
# Defines what will be the last record
|
2346
|
+
last_record = offset + limit
|
2347
|
+
# Transforms the SELECT query in order to retrieve/fetch only
|
2348
|
+
# a number of records after the specified offset.
|
2349
|
+
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
2350
|
+
# to select with the condition of this column being between offset+1 and the offset+limit
|
2351
|
+
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2352
|
+
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
2353
|
+
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
2354
|
+
sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
|
2123
2355
|
end
|
2124
2356
|
|
2125
2357
|
def query_offset_limit!(sql, offset, limit, options)
|
2126
|
-
|
2127
|
-
|
2358
|
+
if(offset.nil? && limit.nil?)
|
2359
|
+
options[:paramArray] = []
|
2360
|
+
return sql
|
2361
|
+
end
|
2362
|
+
|
2128
2363
|
if (offset.nil?)
|
2129
|
-
|
2364
|
+
options[:paramArray] = []
|
2365
|
+
return sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2130
2366
|
end
|
2131
|
-
|
2367
|
+
|
2368
|
+
if(limit.nil?)
|
2369
|
+
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2370
|
+
sql << ") AS I) AS O WHERE sys_row_num > ?"
|
2371
|
+
options[:paramArray] = [offset]
|
2372
|
+
return
|
2373
|
+
end
|
2374
|
+
|
2375
|
+
# Defines what will be the last record
|
2376
|
+
last_record = offset + limit
|
2377
|
+
# Transforms the SELECT query in order to retrieve/fetch only
|
2378
|
+
# a number of records after the specified offset.
|
2379
|
+
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
2380
|
+
# to select with the condition of this column being between offset+1 and the offset+limit
|
2381
|
+
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2382
|
+
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
2383
|
+
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
2384
|
+
sql << ") AS I) AS O WHERE sys_row_num BETWEEN ? AND ?"
|
2385
|
+
options[:paramArray] = [offset+1, last_record]
|
2132
2386
|
end
|
2133
2387
|
|
2134
2388
|
# This method generates the default blob value specified for
|
@@ -2160,40 +2414,6 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2160
2414
|
def reorg_table(table_name)
|
2161
2415
|
execute("CALL ADMIN_CMD('REORG TABLE #{table_name}')")
|
2162
2416
|
end
|
2163
|
-
|
2164
|
-
def query_offset_limit(sql, offset, limit)
|
2165
|
-
if (offset.nil?)
|
2166
|
-
return sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2167
|
-
end
|
2168
|
-
# Defines what will be the last record
|
2169
|
-
last_record = offset + limit
|
2170
|
-
# Transforms the SELECT query in order to retrieve/fetch only
|
2171
|
-
# a number of records after the specified offset.
|
2172
|
-
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
2173
|
-
# to select with the condition of this column being between offset+1 and the offset+limit
|
2174
|
-
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2175
|
-
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
2176
|
-
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
2177
|
-
sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
|
2178
|
-
end
|
2179
|
-
|
2180
|
-
def query_offset_limit!(sql, offset, limit, options)
|
2181
|
-
if (offset.nil?)
|
2182
|
-
options[:paramArray] = []
|
2183
|
-
return sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2184
|
-
end
|
2185
|
-
# Defines what will be the last record
|
2186
|
-
last_record = offset + limit
|
2187
|
-
# Transforms the SELECT query in order to retrieve/fetch only
|
2188
|
-
# a number of records after the specified offset.
|
2189
|
-
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
2190
|
-
# to select with the condition of this column being between offset+1 and the offset+limit
|
2191
|
-
sql.sub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
2192
|
-
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
2193
|
-
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
2194
|
-
sql << ") AS I) AS O WHERE sys_row_num BETWEEN ? AND ?"
|
2195
|
-
options[:paramArray] = [offset+1, last_record]
|
2196
|
-
end
|
2197
2417
|
end # class IBM_DB2_LUW
|
2198
2418
|
|
2199
2419
|
class IBM_DB2_LUW_COBRA < IBM_DB2_LUW
|
@@ -2250,7 +2470,7 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2250
2470
|
if RESERVED_WORDS[col_name]
|
2251
2471
|
'"' + RESERVED_WORDS[col_name] + '"'
|
2252
2472
|
else
|
2253
|
-
col_name
|
2473
|
+
col_name.to_s
|
2254
2474
|
end
|
2255
2475
|
end
|
2256
2476
|
else
|
@@ -2328,6 +2548,20 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2328
2548
|
class IBM_DB2_ZOS_8 < IBM_DB2_ZOS
|
2329
2549
|
include HostedDataServer
|
2330
2550
|
|
2551
|
+
def query_offset_limit(sql, offset, limit)
|
2552
|
+
if (!limit.nil?)
|
2553
|
+
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2554
|
+
end
|
2555
|
+
return sql
|
2556
|
+
end
|
2557
|
+
|
2558
|
+
def query_offset_limit!(sql, offset, limit, options)
|
2559
|
+
if (!limit.nil?)
|
2560
|
+
sql << " FETCH FIRST #{limit} ROWS ONLY"
|
2561
|
+
end
|
2562
|
+
options[:paramArray] = []
|
2563
|
+
end
|
2564
|
+
|
2331
2565
|
# This call is needed on DB2 z/OS v8 for the creation of tables
|
2332
2566
|
# with LOBs. When issued, this call does the following:
|
2333
2567
|
# DB2 creates LOB table spaces, auxiliary tables, and indexes on auxiliary
|
@@ -2553,3 +2787,68 @@ SET WITH DEFAULT #{@adapter.quote(default)}"
|
|
2553
2787
|
end # class IBM_IDS
|
2554
2788
|
end # module ConnectionAdapters
|
2555
2789
|
end # module ActiveRecord
|
2790
|
+
|
2791
|
+
module Arel
|
2792
|
+
module Visitors
|
2793
|
+
class Visitor #opening and closing the class to ensure backward compatibility
|
2794
|
+
end
|
2795
|
+
|
2796
|
+
class ToSql < Arel::Visitors::Visitor #opening and closing the class to ensure backward compatibility
|
2797
|
+
# In case when using Rails-2.3.x there is no arel used due to which the constructor has to be defined explicitly
|
2798
|
+
# to ensure the same code works on any version of Rails
|
2799
|
+
|
2800
|
+
#Check Arel version
|
2801
|
+
begin
|
2802
|
+
@arelVersion = Arel::VERSION.to_i
|
2803
|
+
rescue
|
2804
|
+
@arelVersion = 0
|
2805
|
+
end
|
2806
|
+
|
2807
|
+
if(@arelVersion >= 3)
|
2808
|
+
def initialize connection
|
2809
|
+
@connection = connection
|
2810
|
+
@schema_cache = connection.schema_cache if(connection.respond_to?(:schema_cache))
|
2811
|
+
@quoted_tables = {}
|
2812
|
+
@quoted_columns = {}
|
2813
|
+
@last_column = nil
|
2814
|
+
end
|
2815
|
+
end
|
2816
|
+
end
|
2817
|
+
|
2818
|
+
class IBM_DB < Arel::Visitors::ToSql
|
2819
|
+
private
|
2820
|
+
|
2821
|
+
def visit_Arel_Nodes_Limit o
|
2822
|
+
visit o.expr
|
2823
|
+
end
|
2824
|
+
|
2825
|
+
def visit_Arel_Nodes_Offset o
|
2826
|
+
visit o.expr
|
2827
|
+
end
|
2828
|
+
|
2829
|
+
def visit_Arel_Nodes_SelectStatement o
|
2830
|
+
sql = [
|
2831
|
+
(visit(o.with) if o.with),
|
2832
|
+
o.cores.map { |x| visit_Arel_Nodes_SelectCore x }.join,
|
2833
|
+
("ORDER BY #{o.orders.map { |x| visit x }.join(', ')}" unless o.orders.empty?),
|
2834
|
+
].compact.join ' '
|
2835
|
+
|
2836
|
+
if o.limit
|
2837
|
+
limit = visit(o.limit)
|
2838
|
+
else
|
2839
|
+
limit = nil
|
2840
|
+
end
|
2841
|
+
|
2842
|
+
if o.offset
|
2843
|
+
offset = visit(o.offset)
|
2844
|
+
else
|
2845
|
+
offset = nil
|
2846
|
+
end
|
2847
|
+
@connection.add_limit_offset!(sql, {:limit => limit, :offset => offset})
|
2848
|
+
sql << " #{(visit(o.lock) if o.lock)}"
|
2849
|
+
return sql
|
2850
|
+
end
|
2851
|
+
|
2852
|
+
end
|
2853
|
+
end
|
2854
|
+
end
|