activerecord-jdbc-adapter 5.0.pre1 → 51.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.
- checksums.yaml +5 -5
- data/.gitignore +1 -2
- data/.travis.yml +15 -416
- data/Gemfile +35 -37
- data/README.md +23 -118
- data/RUNNING_TESTS.md +31 -26
- data/Rakefile +2 -3
- data/activerecord-jdbc-adapter.gemspec +1 -2
- data/lib/arjdbc/abstract/connection_management.rb +21 -0
- data/lib/arjdbc/abstract/core.rb +62 -0
- data/lib/arjdbc/abstract/database_statements.rb +46 -0
- data/lib/arjdbc/abstract/statement_cache.rb +58 -0
- data/lib/arjdbc/abstract/transaction_support.rb +86 -0
- data/lib/arjdbc/derby/adapter.rb +6 -1
- data/lib/arjdbc/discover.rb +0 -7
- data/lib/arjdbc/firebird/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +10 -252
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/connection.rb +6 -0
- data/lib/arjdbc/jdbc.rb +2 -2
- data/lib/arjdbc/mysql/adapter.rb +87 -944
- data/lib/arjdbc/mysql/connection_methods.rb +4 -2
- data/lib/arjdbc/postgresql/adapter.rb +288 -1023
- data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +8 -5
- data/lib/arjdbc/postgresql/column.rb +10 -599
- data/lib/arjdbc/postgresql/connection_methods.rb +9 -0
- data/lib/arjdbc/postgresql/name.rb +24 -0
- data/lib/arjdbc/postgresql/oid_types.rb +25 -110
- data/lib/arjdbc/sqlite3/adapter.rb +171 -170
- data/lib/arjdbc/tasks/database_tasks.rb +1 -3
- data/lib/arjdbc/tasks/db2_database_tasks.rb +2 -2
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +3 -3
- data/rakelib/02-test.rake +0 -12
- data/rakelib/compile.rake +1 -1
- data/rakelib/db.rake +7 -5
- data/rakelib/rails.rake +63 -64
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +1 -17
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +518 -1260
- data/src/java/arjdbc/mysql/MySQLModule.java +3 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +53 -134
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +214 -240
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +0 -20
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +85 -10
- metadata +20 -34
- data/Appraisals +0 -41
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -1
- data/lib/arjdbc/common_jdbc_methods.rb +0 -89
- data/lib/arjdbc/mysql/bulk_change_table.rb +0 -150
- data/lib/arjdbc/mysql/column.rb +0 -162
- data/lib/arjdbc/mysql/explain_support.rb +0 -82
- data/lib/arjdbc/mysql/schema_creation.rb +0 -58
- data/lib/arjdbc/oracle/adapter.rb +0 -952
- data/lib/arjdbc/oracle/column.rb +0 -126
- data/lib/arjdbc/oracle/connection_methods.rb +0 -21
- data/lib/arjdbc/oracle.rb +0 -4
- data/lib/arjdbc/postgresql/_bc_time_cast_patch.rb +0 -21
- data/lib/arjdbc/postgresql/base/oid.rb +0 -412
- data/lib/arjdbc/postgresql/base/schema_definitions.rb +0 -131
- data/lib/arjdbc/postgresql/explain_support.rb +0 -53
- data/lib/arjdbc/postgresql/oid/bytea.rb +0 -2
- data/lib/arjdbc/postgresql/schema_creation.rb +0 -60
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +0 -297
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +0 -65
- data/src/java/arjdbc/oracle/OracleModule.java +0 -75
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +0 -465
@@ -1,131 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
module PostgreSQL
|
4
|
-
class ColumnDefinition < ActiveRecord::ConnectionAdapters::ColumnDefinition
|
5
|
-
attr_accessor :array
|
6
|
-
def array?; !!@array; end
|
7
|
-
end
|
8
|
-
|
9
|
-
module ColumnMethods
|
10
|
-
def xml(*args)
|
11
|
-
options = args.extract_options!
|
12
|
-
column(args[0], 'xml', options)
|
13
|
-
end
|
14
|
-
|
15
|
-
def tsvector(*args)
|
16
|
-
options = args.extract_options!
|
17
|
-
column(args[0], 'tsvector', options)
|
18
|
-
end
|
19
|
-
|
20
|
-
def int4range(name, options = {})
|
21
|
-
column(name, 'int4range', options)
|
22
|
-
end
|
23
|
-
|
24
|
-
def int8range(name, options = {})
|
25
|
-
column(name, 'int8range', options)
|
26
|
-
end
|
27
|
-
|
28
|
-
def tsrange(name, options = {})
|
29
|
-
column(name, 'tsrange', options)
|
30
|
-
end
|
31
|
-
|
32
|
-
def tstzrange(name, options = {})
|
33
|
-
column(name, 'tstzrange', options)
|
34
|
-
end
|
35
|
-
|
36
|
-
def numrange(name, options = {})
|
37
|
-
column(name, 'numrange', options)
|
38
|
-
end
|
39
|
-
|
40
|
-
def daterange(name, options = {})
|
41
|
-
column(name, 'daterange', options)
|
42
|
-
end
|
43
|
-
|
44
|
-
def hstore(name, options = {})
|
45
|
-
column(name, 'hstore', options)
|
46
|
-
end
|
47
|
-
|
48
|
-
def ltree(name, options = {})
|
49
|
-
column(name, 'ltree', options)
|
50
|
-
end
|
51
|
-
|
52
|
-
def inet(name, options = {})
|
53
|
-
column(name, 'inet', options)
|
54
|
-
end
|
55
|
-
|
56
|
-
def cidr(name, options = {})
|
57
|
-
column(name, 'cidr', options)
|
58
|
-
end
|
59
|
-
|
60
|
-
def macaddr(name, options = {})
|
61
|
-
column(name, 'macaddr', options)
|
62
|
-
end
|
63
|
-
|
64
|
-
def uuid(name, options = {})
|
65
|
-
column(name, 'uuid', options)
|
66
|
-
end
|
67
|
-
|
68
|
-
def json(name, options = {})
|
69
|
-
column(name, 'json', options)
|
70
|
-
end
|
71
|
-
|
72
|
-
def jsonb(name, options = {})
|
73
|
-
column(name, :jsonb, options)
|
74
|
-
end
|
75
|
-
|
76
|
-
def bit(name, options)
|
77
|
-
column(name, 'bit', options)
|
78
|
-
end
|
79
|
-
|
80
|
-
def bit_varying(name, options)
|
81
|
-
column(name, 'bit varying', options)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
86
|
-
include ColumnMethods
|
87
|
-
|
88
|
-
def primary_key(name, type = :primary_key, options = {})
|
89
|
-
return super unless type == :uuid
|
90
|
-
options[:default] = options.fetch(:default, 'uuid_generate_v4()')
|
91
|
-
options[:primary_key] = true
|
92
|
-
column name, type, options
|
93
|
-
end if ::ActiveRecord::VERSION::MAJOR > 3 # 3.2 super expects (name)
|
94
|
-
|
95
|
-
def column(name, type = nil, options = {})
|
96
|
-
super
|
97
|
-
column = self[name]
|
98
|
-
# NOTE: <= 3.1 no #new_column_definition hard-coded ColumnDef.new :
|
99
|
-
# column = self[name] || ColumnDefinition.new(@base, name, type)
|
100
|
-
# thus we simply do not support array column definitions on <= 3.1
|
101
|
-
column.array = options[:array] if column.is_a?(ColumnDefinition)
|
102
|
-
self
|
103
|
-
end
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
if ::ActiveRecord::VERSION::MAJOR > 3
|
108
|
-
|
109
|
-
def create_column_definition(name, type)
|
110
|
-
ColumnDefinition.new name, type
|
111
|
-
end
|
112
|
-
|
113
|
-
else # no #create_column_definition on 3.2
|
114
|
-
|
115
|
-
def new_column_definition(base, name, type)
|
116
|
-
definition = ColumnDefinition.new base, name, type
|
117
|
-
@columns << definition
|
118
|
-
@columns_hash[name] = definition
|
119
|
-
definition
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
class Table < ActiveRecord::ConnectionAdapters::Table
|
127
|
-
include ColumnMethods
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module ArJdbc
|
2
|
-
module PostgreSQL
|
3
|
-
# @private
|
4
|
-
module ExplainSupport
|
5
|
-
def supports_explain?
|
6
|
-
true
|
7
|
-
end
|
8
|
-
|
9
|
-
def explain(arel, binds = [])
|
10
|
-
sql = "EXPLAIN #{to_sql(arel, binds)}"
|
11
|
-
result = exec_query(sql, "EXPLAIN", binds)
|
12
|
-
ExplainPrettyPrinter.new.pp result # we can assume AR >= 3.1
|
13
|
-
end
|
14
|
-
# @private
|
15
|
-
class ExplainPrettyPrinter
|
16
|
-
# Pretty prints the result of a EXPLAIN in a way that resembles the output of the
|
17
|
-
# PostgreSQL shell:
|
18
|
-
#
|
19
|
-
# QUERY PLAN
|
20
|
-
# ------------------------------------------------------------------------------
|
21
|
-
# Nested Loop Left Join (cost=0.00..37.24 rows=8 width=0)
|
22
|
-
# Join Filter: (posts.user_id = users.id)
|
23
|
-
# -> Index Scan using users_pkey on users (cost=0.00..8.27 rows=1 width=4)
|
24
|
-
# Index Cond: (id = 1)
|
25
|
-
# -> Seq Scan on posts (cost=0.00..28.88 rows=8 width=4)
|
26
|
-
# Filter: (posts.user_id = 1)
|
27
|
-
# (6 rows)
|
28
|
-
#
|
29
|
-
def pp(result)
|
30
|
-
header = result.columns.first
|
31
|
-
lines = result.rows.map(&:first)
|
32
|
-
|
33
|
-
# We add 2 because there's one char of padding at both sides, note
|
34
|
-
# the extra hyphens in the example above.
|
35
|
-
width = [header, *lines].map(&:length).max + 2
|
36
|
-
|
37
|
-
pp = []
|
38
|
-
|
39
|
-
pp << header.center(width).rstrip
|
40
|
-
pp << '-' * width
|
41
|
-
|
42
|
-
pp += lines.map {|line| " #{line}"}
|
43
|
-
|
44
|
-
nrows = result.rows.length
|
45
|
-
rows_label = nrows == 1 ? 'row' : 'rows'
|
46
|
-
pp << "(#{nrows} #{rows_label})"
|
47
|
-
|
48
|
-
pp.join("\n") + "\n"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module ArJdbc
|
2
|
-
module PostgreSQL
|
3
|
-
# @private copied (and adjusted) from native adapter 4.0/4.1/4.2
|
4
|
-
class SchemaCreation < ::ActiveRecord::ConnectionAdapters::AbstractAdapter::SchemaCreation
|
5
|
-
|
6
|
-
private
|
7
|
-
|
8
|
-
def visit_AddColumn(o)
|
9
|
-
sql_type = type_to_sql(o.type.to_sym, o.limit, o.precision, o.scale)
|
10
|
-
sql = "ADD COLUMN #{quote_column_name(o.name)} #{sql_type}"
|
11
|
-
add_column_options!(sql, column_options(o))
|
12
|
-
end unless AR42
|
13
|
-
|
14
|
-
def visit_ColumnDefinition(o)
|
15
|
-
sql = super
|
16
|
-
if o.primary_key? && o.type == :uuid
|
17
|
-
sql << " PRIMARY KEY "
|
18
|
-
add_column_options!(sql, column_options(o))
|
19
|
-
end
|
20
|
-
sql
|
21
|
-
end unless AR42
|
22
|
-
|
23
|
-
def visit_ColumnDefinition(o)
|
24
|
-
sql = super
|
25
|
-
if o.primary_key? && o.type != :primary_key
|
26
|
-
sql << " PRIMARY KEY "
|
27
|
-
add_column_options!(sql, column_options(o))
|
28
|
-
end
|
29
|
-
sql
|
30
|
-
end if AR42
|
31
|
-
|
32
|
-
def add_column_options!(sql, options)
|
33
|
-
if options[:array] || options[:column].try(:array)
|
34
|
-
sql << '[]'
|
35
|
-
end
|
36
|
-
|
37
|
-
column = options.fetch(:column) { return super }
|
38
|
-
if column.type == :uuid && options[:default] =~ /\(\)/
|
39
|
-
sql << " DEFAULT #{options[:default]}"
|
40
|
-
else
|
41
|
-
super
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def type_for_column(column)
|
46
|
-
if column.array
|
47
|
-
@conn.lookup_cast_type("#{column.sql_type}[]")
|
48
|
-
else
|
49
|
-
super
|
50
|
-
end
|
51
|
-
end if AR42
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def schema_creation
|
56
|
-
SchemaCreation.new self
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end if ::ActiveRecord::ConnectionAdapters::AbstractAdapter.const_defined? :SchemaCreation
|
@@ -1,297 +0,0 @@
|
|
1
|
-
# NOTE: kindly copy-pasted from Raimonds Simanovskis's oracle-enhanced adapter :
|
2
|
-
# https://github.com/rsim/oracle-enhanced/blob/master/lib/active_record/connection_adapters/oracle_enhanced_structure_dump.rb
|
3
|
-
|
4
|
-
module ActiveRecord #:nodoc:
|
5
|
-
module ConnectionAdapters #:nodoc:
|
6
|
-
module OracleEnhancedStructureDump #:nodoc:
|
7
|
-
|
8
|
-
# Statements separator used in structure dump to allow loading of structure dump also with SQL*Plus
|
9
|
-
STATEMENT_TOKEN = "\n\n/\n\n"
|
10
|
-
|
11
|
-
def structure_dump #:nodoc:
|
12
|
-
structure = select_values("SELECT sequence_name FROM user_sequences ORDER BY 1").map do |seq|
|
13
|
-
"CREATE SEQUENCE \"#{seq}\""
|
14
|
-
end
|
15
|
-
select_values("SELECT table_name FROM all_tables t
|
16
|
-
WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N'
|
17
|
-
AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
|
18
|
-
AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
|
19
|
-
ORDER BY 1").each do |table_name|
|
20
|
-
virtual_columns = virtual_columns_for(table_name)
|
21
|
-
ddl = "CREATE#{ ' GLOBAL TEMPORARY' if temporary_table?(table_name)} TABLE \"#{table_name}\" (\n"
|
22
|
-
cols = select_all(%Q{
|
23
|
-
SELECT column_name, data_type, data_length, char_used, char_length, data_precision, data_scale, data_default, nullable
|
24
|
-
FROM user_tab_columns
|
25
|
-
WHERE table_name = '#{table_name}'
|
26
|
-
ORDER BY column_id
|
27
|
-
}).map do |row|
|
28
|
-
if(v = virtual_columns.find {|col| col['column_name'] == row['column_name']})
|
29
|
-
structure_dump_virtual_column(row, v['data_default'])
|
30
|
-
else
|
31
|
-
structure_dump_column(row)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
ddl << cols.join(",\n ")
|
35
|
-
ddl << structure_dump_primary_key(table_name)
|
36
|
-
ddl << "\n)"
|
37
|
-
structure << ddl
|
38
|
-
structure << structure_dump_indexes(table_name)
|
39
|
-
structure << structure_dump_unique_keys(table_name)
|
40
|
-
end
|
41
|
-
|
42
|
-
join_with_statement_token(structure) << structure_dump_fk_constraints
|
43
|
-
end
|
44
|
-
|
45
|
-
def structure_dump_column(column) #:nodoc:
|
46
|
-
col = "\"#{column['column_name']}\" #{column['data_type']}"
|
47
|
-
if column['data_type'] =='NUMBER' && ! column['data_precision'].blank?
|
48
|
-
col << "(#{column['data_precision'].to_i}"
|
49
|
-
col << ",#{column['data_scale'].to_i}" unless column['data_scale'].blank?
|
50
|
-
col << ')'
|
51
|
-
elsif column['data_type'].include?('CHAR')
|
52
|
-
length = column['char_used'] == 'C' ? column['char_length'].to_i : column['data_length'].to_i
|
53
|
-
col << "(#{length})"
|
54
|
-
end
|
55
|
-
col << " DEFAULT #{column['data_default']}" unless column['data_default'].blank?
|
56
|
-
col << ' NOT NULL' if column['nullable'] == 'N'
|
57
|
-
col
|
58
|
-
end
|
59
|
-
|
60
|
-
def structure_dump_virtual_column(column, data_default) #:nodoc:
|
61
|
-
data_default = data_default.gsub(/"/, '')
|
62
|
-
col = "\"#{column['column_name']}\" #{column['data_type']}"
|
63
|
-
if column['data_type'] =='NUMBER' && ! column['data_precision'].blank?
|
64
|
-
col << "(#{column['data_precision'].to_i}"
|
65
|
-
col << ",#{column['data_scale'].to_i}" unless column['data_scale'].blank?
|
66
|
-
col << ')'
|
67
|
-
elsif column['data_type'].include?('CHAR')
|
68
|
-
length = column['char_used'] == 'C' ? column['char_length'].to_i : column['data_length'].to_i
|
69
|
-
col << "(#{length})"
|
70
|
-
end
|
71
|
-
col << " GENERATED ALWAYS AS (#{data_default}) VIRTUAL"
|
72
|
-
end
|
73
|
-
|
74
|
-
def structure_dump_primary_key(table) #:nodoc:
|
75
|
-
opts = {:name => '', :cols => []}
|
76
|
-
pks = select_all(<<-SQL, "Primary Keys")
|
77
|
-
SELECT a.constraint_name, a.column_name, a.position
|
78
|
-
FROM user_cons_columns a
|
79
|
-
JOIN user_constraints c
|
80
|
-
ON a.constraint_name = c.constraint_name
|
81
|
-
WHERE c.table_name = '#{table.upcase}'
|
82
|
-
AND c.constraint_type = 'P'
|
83
|
-
AND c.owner = SYS_CONTEXT('userenv', 'session_user')
|
84
|
-
SQL
|
85
|
-
pks.each do |row|
|
86
|
-
opts[:name] = row['constraint_name']
|
87
|
-
opts[:cols][row['position']-1] = row['column_name']
|
88
|
-
end
|
89
|
-
opts[:cols].length > 0 ? ",\n CONSTRAINT #{opts[:name]} PRIMARY KEY (#{opts[:cols].join(',')})" : ''
|
90
|
-
end
|
91
|
-
|
92
|
-
def structure_dump_unique_keys(table) #:nodoc:
|
93
|
-
keys = {}
|
94
|
-
uks = select_all(<<-SQL, "Primary Keys")
|
95
|
-
SELECT a.constraint_name, a.column_name, a.position
|
96
|
-
FROM user_cons_columns a
|
97
|
-
JOIN user_constraints c
|
98
|
-
ON a.constraint_name = c.constraint_name
|
99
|
-
WHERE c.table_name = '#{table.upcase}'
|
100
|
-
AND c.constraint_type = 'U'
|
101
|
-
AND c.owner = SYS_CONTEXT('userenv', 'session_user')
|
102
|
-
SQL
|
103
|
-
uks.each do |uk|
|
104
|
-
keys[uk['constraint_name']] ||= []
|
105
|
-
keys[uk['constraint_name']][uk['position']-1] = uk['column_name']
|
106
|
-
end
|
107
|
-
keys.map do |k,v|
|
108
|
-
"ALTER TABLE #{table.upcase} ADD CONSTRAINT #{k} UNIQUE (#{v.join(',')})"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def structure_dump_indexes(table_name) #:nodoc:
|
113
|
-
indexes(table_name).map do |options|
|
114
|
-
column_names = options[:columns]
|
115
|
-
options = {:name => options[:name], :unique => options[:unique]}
|
116
|
-
index_name = index_name(table_name, :column => column_names)
|
117
|
-
if Hash === options # legacy support, since this param was a string
|
118
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
119
|
-
index_name = options[:name] || index_name
|
120
|
-
else
|
121
|
-
index_type = options
|
122
|
-
end
|
123
|
-
quoted_column_names = column_names.map { |e| quote_column_name_or_expression(e) }.join(", ")
|
124
|
-
"CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names})"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def structure_dump_fk_constraints #:nodoc:
|
129
|
-
fks = select_all("SELECT table_name FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY 1").map do |table|
|
130
|
-
if respond_to?(:foreign_keys) && (foreign_keys = foreign_keys(table["table_name"])).any?
|
131
|
-
foreign_keys.map do |fk|
|
132
|
-
sql = "ALTER TABLE #{quote_table_name(fk.from_table)} ADD CONSTRAINT #{quote_column_name(fk.options[:name])} "
|
133
|
-
sql << "#{foreign_key_definition(fk.to_table, fk.options)}"
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end.flatten.compact
|
137
|
-
join_with_statement_token(fks)
|
138
|
-
end
|
139
|
-
|
140
|
-
def dump_schema_information #:nodoc:
|
141
|
-
sm_table = ActiveRecord::Migrator.schema_migrations_table_name
|
142
|
-
migrated = select_values("SELECT version FROM #{sm_table} ORDER BY version")
|
143
|
-
join_with_statement_token(migrated.map{|v| "INSERT INTO #{sm_table} (version) VALUES ('#{v}')" })
|
144
|
-
end
|
145
|
-
|
146
|
-
# Extract all stored procedures, packages, synonyms and views.
|
147
|
-
def structure_dump_db_stored_code #:nodoc:
|
148
|
-
structure = []
|
149
|
-
select_all("SELECT DISTINCT name, type
|
150
|
-
FROM all_source
|
151
|
-
WHERE type IN ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION', 'TRIGGER', 'TYPE')
|
152
|
-
AND name NOT LIKE 'BIN$%'
|
153
|
-
AND owner = SYS_CONTEXT('userenv', 'session_user') ORDER BY type").each do |source|
|
154
|
-
ddl = "CREATE OR REPLACE \n"
|
155
|
-
select_all(%Q{
|
156
|
-
SELECT text
|
157
|
-
FROM all_source
|
158
|
-
WHERE name = '#{source['name']}'
|
159
|
-
AND type = '#{source['type']}'
|
160
|
-
AND owner = SYS_CONTEXT('userenv', 'session_user')
|
161
|
-
ORDER BY line
|
162
|
-
}).each do |row|
|
163
|
-
ddl << row['text']
|
164
|
-
end
|
165
|
-
ddl << ";" unless ddl.strip[-1,1] == ';'
|
166
|
-
structure << ddl
|
167
|
-
end
|
168
|
-
|
169
|
-
# export views
|
170
|
-
select_all("SELECT view_name, text FROM user_views").each do |view|
|
171
|
-
structure << "CREATE OR REPLACE VIEW #{view['view_name']} AS\n #{view['text']}"
|
172
|
-
end
|
173
|
-
|
174
|
-
# export synonyms
|
175
|
-
select_all("SELECT owner, synonym_name, table_name, table_owner
|
176
|
-
FROM all_synonyms
|
177
|
-
WHERE owner = SYS_CONTEXT('userenv', 'session_user') ").each do |synonym|
|
178
|
-
structure << "CREATE OR REPLACE #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']}"
|
179
|
-
structure << " FOR #{synonym['table_owner']}.#{synonym['table_name']}"
|
180
|
-
end
|
181
|
-
|
182
|
-
join_with_statement_token(structure)
|
183
|
-
end
|
184
|
-
|
185
|
-
def structure_drop #:nodoc:
|
186
|
-
statements = select_values("SELECT sequence_name FROM user_sequences ORDER BY 1").map do |seq|
|
187
|
-
"DROP SEQUENCE \"#{seq}\""
|
188
|
-
end
|
189
|
-
select_values("SELECT table_name from all_tables t
|
190
|
-
WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N'
|
191
|
-
AND NOT EXISTS (SELECT mv.mview_name FROM all_mviews mv WHERE mv.owner = t.owner AND mv.mview_name = t.table_name)
|
192
|
-
AND NOT EXISTS (SELECT mvl.log_table FROM all_mview_logs mvl WHERE mvl.log_owner = t.owner AND mvl.log_table = t.table_name)
|
193
|
-
ORDER BY 1").each do |table|
|
194
|
-
statements << "DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
|
195
|
-
end
|
196
|
-
join_with_statement_token(statements)
|
197
|
-
end
|
198
|
-
|
199
|
-
def temp_table_drop #:nodoc:
|
200
|
-
join_with_statement_token(select_values(
|
201
|
-
"SELECT table_name FROM all_tables
|
202
|
-
WHERE owner = SYS_CONTEXT('userenv', 'session_user') AND secondary = 'N' AND temporary = 'Y' ORDER BY 1").map do |table|
|
203
|
-
"DROP TABLE \"#{table}\" CASCADE CONSTRAINTS"
|
204
|
-
end)
|
205
|
-
end
|
206
|
-
|
207
|
-
def full_drop(preserve_tables=false) #:nodoc:
|
208
|
-
s = preserve_tables ? [] : [structure_drop]
|
209
|
-
s << temp_table_drop if preserve_tables
|
210
|
-
s << drop_sql_for_feature("view")
|
211
|
-
s << drop_sql_for_feature("materialized view")
|
212
|
-
s << drop_sql_for_feature("synonym")
|
213
|
-
s << drop_sql_for_feature("type")
|
214
|
-
s << drop_sql_for_object("package")
|
215
|
-
s << drop_sql_for_object("function")
|
216
|
-
s << drop_sql_for_object("procedure")
|
217
|
-
s.join
|
218
|
-
end
|
219
|
-
|
220
|
-
def add_column_options!(sql, options) #:nodoc:
|
221
|
-
type = options[:type] || ((column = options[:column]) && column.type)
|
222
|
-
type = type && type.to_sym
|
223
|
-
# handle case of defaults for CLOB columns, which would otherwise get "quoted" incorrectly
|
224
|
-
if options_include_default?(options)
|
225
|
-
if type == :text
|
226
|
-
sql << " DEFAULT #{quote(options[:default])}"
|
227
|
-
else
|
228
|
-
# from abstract adapter
|
229
|
-
sql << " DEFAULT #{quote(options[:default], options[:column])}"
|
230
|
-
end
|
231
|
-
end
|
232
|
-
# must explicitly add NULL or NOT NULL to allow change_column to work on migrations
|
233
|
-
if options[:null] == false
|
234
|
-
sql << " NOT NULL"
|
235
|
-
elsif options[:null] == true
|
236
|
-
sql << " NULL" unless type == :primary_key
|
237
|
-
end
|
238
|
-
# add AS expression for virtual columns
|
239
|
-
if options[:as].present?
|
240
|
-
sql << " AS (#{options[:as]})"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def execute_structure_dump(string)
|
245
|
-
string.split(STATEMENT_TOKEN).each do |ddl|
|
246
|
-
ddl.chop! if ddl[-1,1] == ';'
|
247
|
-
execute(ddl) unless ddl.blank?
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
private
|
252
|
-
|
253
|
-
# virtual columns are an 11g feature. This returns [] if feature is not
|
254
|
-
# present or none are found.
|
255
|
-
# return [{'column_name' => 'FOOS', 'data_default' => '...'}, ...]
|
256
|
-
def virtual_columns_for(table)
|
257
|
-
begin
|
258
|
-
select_all <<-SQL
|
259
|
-
SELECT column_name, data_default
|
260
|
-
FROM user_tab_cols
|
261
|
-
WHERE virtual_column = 'YES'
|
262
|
-
AND table_name = '#{table.upcase}'
|
263
|
-
SQL
|
264
|
-
# feature not supported previous to 11g
|
265
|
-
rescue ActiveRecord::StatementInvalid => e
|
266
|
-
[]
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
def drop_sql_for_feature(type)
|
271
|
-
short_type = type == 'materialized view' ? 'mview' : type
|
272
|
-
join_with_statement_token(
|
273
|
-
select_values("SELECT #{short_type}_name FROM user_#{short_type.tableize}").map do |name|
|
274
|
-
"DROP #{type.upcase} \"#{name}\""
|
275
|
-
end)
|
276
|
-
end
|
277
|
-
|
278
|
-
def drop_sql_for_object(type)
|
279
|
-
join_with_statement_token(
|
280
|
-
select_values("SELECT object_name FROM user_objects WHERE object_type = '#{type.upcase}'").map do |name|
|
281
|
-
"DROP #{type.upcase} \"#{name}\""
|
282
|
-
end)
|
283
|
-
end
|
284
|
-
|
285
|
-
def join_with_statement_token(array)
|
286
|
-
string = array.join(STATEMENT_TOKEN)
|
287
|
-
string << STATEMENT_TOKEN unless string.blank?
|
288
|
-
string
|
289
|
-
end
|
290
|
-
|
291
|
-
end
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
|
296
|
-
include ActiveRecord::ConnectionAdapters::OracleEnhancedStructureDump
|
297
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'arjdbc/tasks/jdbc_database_tasks'
|
2
|
-
|
3
|
-
module ArJdbc
|
4
|
-
module Tasks
|
5
|
-
class OracleDatabaseTasks < JdbcDatabaseTasks
|
6
|
-
|
7
|
-
def create
|
8
|
-
print "Please provide the SYSTEM password for your oracle installation\n>"
|
9
|
-
system_password = $stdin.gets.strip
|
10
|
-
establish_connection(config.merge('username' => 'SYSTEM', 'password' => system_password))
|
11
|
-
unless ( config = self.config ).key?('username')
|
12
|
-
config = config_from_url(config['url']) if config['url']
|
13
|
-
end
|
14
|
-
begin
|
15
|
-
connection.execute "CREATE USER #{config['username']} IDENTIFIED BY #{config['password']}"
|
16
|
-
rescue => e
|
17
|
-
if e.message =~ /ORA-01920/ # user name conflicts with another user or role name
|
18
|
-
connection.execute "ALTER USER #{config['username']} IDENTIFIED BY #{config['password']}"
|
19
|
-
else
|
20
|
-
raise e
|
21
|
-
end
|
22
|
-
end
|
23
|
-
connection.execute "GRANT unlimited tablespace TO #{config['username']}"
|
24
|
-
connection.execute "GRANT create session TO #{config['username']}"
|
25
|
-
connection.execute "GRANT create table TO #{config['username']}"
|
26
|
-
connection.execute "GRANT create sequence TO #{config['username']}"
|
27
|
-
end
|
28
|
-
|
29
|
-
def drop
|
30
|
-
self.class.load_enhanced_structure_dump
|
31
|
-
establish_connection(config)
|
32
|
-
connection.execute_structure_dump(connection.full_drop)
|
33
|
-
end
|
34
|
-
|
35
|
-
def purge
|
36
|
-
self.class.load_enhanced_structure_dump
|
37
|
-
establish_connection(:test)
|
38
|
-
connection.execute_structure_dump(connection.full_drop)
|
39
|
-
connection.execute("PURGE RECYCLEBIN") rescue nil
|
40
|
-
end
|
41
|
-
|
42
|
-
def structure_dump(filename)
|
43
|
-
self.class.load_enhanced_structure_dump
|
44
|
-
establish_connection(config)
|
45
|
-
File.open(filename, "w:utf-8") { |f| f << connection.structure_dump }
|
46
|
-
end
|
47
|
-
|
48
|
-
def structure_load(filename)
|
49
|
-
self.class.load_enhanced_structure_dump
|
50
|
-
establish_connection(config)
|
51
|
-
connection.execute_structure_dump(File.read(filename))
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.load_enhanced_structure_dump
|
55
|
-
unless defined? ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
|
56
|
-
ActiveRecord::ConnectionAdapters.module_eval do
|
57
|
-
const_set :OracleEnhancedAdapter, ActiveRecord::ConnectionAdapters::OracleAdapter
|
58
|
-
end
|
59
|
-
end
|
60
|
-
require 'arjdbc/tasks/oracle/enhanced_structure_dump'
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
@@ -1,75 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* The MIT License
|
3
|
-
*
|
4
|
-
* Copyright 2013-2014 Karol Bucek.
|
5
|
-
*
|
6
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
* of this software and associated documentation files (the "Software"), to deal
|
8
|
-
* in the Software without restriction, including without limitation the rights
|
9
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
* copies of the Software, and to permit persons to whom the Software is
|
11
|
-
* furnished to do so, subject to the following conditions:
|
12
|
-
*
|
13
|
-
* The above copyright notice and this permission notice shall be included in
|
14
|
-
* all copies or substantial portions of the Software.
|
15
|
-
*
|
16
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
* THE SOFTWARE.
|
23
|
-
*/
|
24
|
-
package arjdbc.oracle;
|
25
|
-
|
26
|
-
import static arjdbc.util.QuotingUtils.BYTES_0;
|
27
|
-
import static arjdbc.util.QuotingUtils.BYTES_1;
|
28
|
-
import static arjdbc.util.QuotingUtils.quoteCharWith;
|
29
|
-
|
30
|
-
import org.jruby.RubyModule;
|
31
|
-
import org.jruby.RubyString;
|
32
|
-
import org.jruby.anno.JRubyMethod;
|
33
|
-
import org.jruby.runtime.ThreadContext;
|
34
|
-
import org.jruby.runtime.builtin.IRubyObject;
|
35
|
-
|
36
|
-
/**
|
37
|
-
* ArJdbc::Oracle
|
38
|
-
*
|
39
|
-
* @author kares
|
40
|
-
*/
|
41
|
-
public class OracleModule {
|
42
|
-
|
43
|
-
public static RubyModule load(final RubyModule arJdbc) {
|
44
|
-
RubyModule oracle = arJdbc.defineModuleUnder("Oracle");
|
45
|
-
oracle.defineAnnotatedMethods( OracleModule.class );
|
46
|
-
return oracle;
|
47
|
-
}
|
48
|
-
|
49
|
-
@JRubyMethod(name = "quote_string", required = 1)
|
50
|
-
public static IRubyObject quote_string(
|
51
|
-
final ThreadContext context,
|
52
|
-
final IRubyObject self,
|
53
|
-
final IRubyObject string) { // string.gsub("'", "''") :
|
54
|
-
final char single = '\'';
|
55
|
-
final RubyString quoted = quoteCharWith(
|
56
|
-
context, (RubyString) string, single, single
|
57
|
-
);
|
58
|
-
return quoted;
|
59
|
-
}
|
60
|
-
|
61
|
-
@JRubyMethod(name = "quoted_true", required = 0)
|
62
|
-
public static IRubyObject quoted_true(
|
63
|
-
final ThreadContext context,
|
64
|
-
final IRubyObject self) {
|
65
|
-
return RubyString.newString(context.getRuntime(), BYTES_1);
|
66
|
-
}
|
67
|
-
|
68
|
-
@JRubyMethod(name = "quoted_false", required = 0)
|
69
|
-
public static IRubyObject quoted_false(
|
70
|
-
final ThreadContext context,
|
71
|
-
final IRubyObject self) {
|
72
|
-
return RubyString.newString(context.getRuntime(), BYTES_0);
|
73
|
-
}
|
74
|
-
|
75
|
-
}
|