db2_query 0.1.0 → 0.3.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 +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +209 -55
- data/Rakefile +1 -17
- data/lib/db2_query.rb +10 -17
- data/lib/db2_query/base.rb +2 -78
- data/lib/db2_query/config.rb +29 -0
- data/lib/db2_query/connection.rb +108 -30
- data/lib/db2_query/core.rb +140 -0
- data/lib/db2_query/error.rb +12 -1
- data/lib/db2_query/formatter.rb +5 -23
- data/lib/db2_query/logger.rb +42 -0
- data/lib/db2_query/railtie.rb +5 -12
- data/lib/db2_query/result.rb +47 -65
- data/lib/db2_query/tasks/database.rake +38 -0
- data/lib/{tasks → db2_query/tasks}/init.rake +0 -0
- data/lib/{tasks → db2_query/tasks}/initializer.rake +10 -4
- data/lib/db2_query/version.rb +1 -1
- metadata +45 -57
- data/lib/db2_query/column.rb +0 -42
- data/lib/db2_query/connection_handling.rb +0 -56
- data/lib/db2_query/database_configurations.rb +0 -50
- data/lib/db2_query/database_statements.rb +0 -32
- data/lib/db2_query/log_subscriber.rb +0 -50
- data/lib/db2_query/odbc_connector.rb +0 -38
- data/lib/db2_query/path.rb +0 -17
- data/lib/db2_query/schema.rb +0 -113
- data/lib/db2_query/sql_validator.rb +0 -26
- data/lib/tasks/database.rake +0 -56
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
module ConnectionHandling
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
DEFAULT_DB = "primary"
|
8
|
-
|
9
|
-
included do |base|
|
10
|
-
def base.inherited(child)
|
11
|
-
child.connection = @connection
|
12
|
-
end
|
13
|
-
|
14
|
-
base.extend ClassMethods
|
15
|
-
base.connection = nil
|
16
|
-
end
|
17
|
-
|
18
|
-
module ClassMethods
|
19
|
-
attr_reader :connection
|
20
|
-
|
21
|
-
def connection=(connection)
|
22
|
-
@connection = connection
|
23
|
-
update_descendants_connection unless self.descendants.empty?
|
24
|
-
end
|
25
|
-
|
26
|
-
def update_descendants_connection
|
27
|
-
self.descendants.each { |child| child.connection = @connection }
|
28
|
-
end
|
29
|
-
|
30
|
-
def establish_connection(db_name = nil)
|
31
|
-
clear_connection unless self.connection.nil?
|
32
|
-
db_name = db_name.nil? ? DEFAULT_DB : db_name.to_s
|
33
|
-
|
34
|
-
self.load_database_configurations if self.configurations.nil?
|
35
|
-
|
36
|
-
if self.configurations[db_name].nil?
|
37
|
-
raise Error, "Database (:#{db_name}) not found at database configurations."
|
38
|
-
end
|
39
|
-
|
40
|
-
conn_type, conn_config = extract_configuration(db_name)
|
41
|
-
|
42
|
-
connector = ODBCConnector.new(conn_type, conn_config)
|
43
|
-
self.connection = Connection.new(connector, db_name)
|
44
|
-
end
|
45
|
-
|
46
|
-
def current_database
|
47
|
-
@connection.db_name
|
48
|
-
end
|
49
|
-
|
50
|
-
def clear_connection
|
51
|
-
@connection.disconnect!
|
52
|
-
@connection = nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
module DatabaseConfigurations
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
DEFAULT_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
|
8
|
-
|
9
|
-
included do |base|
|
10
|
-
@@configurations = Hash.new
|
11
|
-
|
12
|
-
base.extend ClassMethods
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
def configurations
|
17
|
-
@@configurations
|
18
|
-
end
|
19
|
-
|
20
|
-
def load_database_configurations(path = nil)
|
21
|
-
file_path = path.nil? ? Path.database_config_file : path
|
22
|
-
|
23
|
-
if File.exist?(file_path)
|
24
|
-
file = File.read(file_path)
|
25
|
-
@@configurations = YAML.load(ERB.new(file).result)[DEFAULT_ENV.call]
|
26
|
-
else
|
27
|
-
raise Error, "Could not load db2query database configuration. No such file - #{file_path}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def configurations_databases
|
32
|
-
self.load_database_configurations if self.configurations.nil?
|
33
|
-
@@configurations.keys
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
def extract_configuration(db_name)
|
38
|
-
configs = @@configurations[db_name.to_s]
|
39
|
-
conn_config = configs.nil? ? configs : configs.transform_keys(&:to_sym)
|
40
|
-
conn_type = (conn_config.keys & ODBCConnector::CONNECTION_TYPES).first
|
41
|
-
|
42
|
-
if conn_type.nil?
|
43
|
-
raise Error, "No data source name (:dsn) or connection string (:conn_str) provided."
|
44
|
-
end
|
45
|
-
|
46
|
-
[conn_type, conn_config]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
module DatabaseStatements
|
5
|
-
def query_value(sql) # :nodoc:
|
6
|
-
single_value_from_rows(query(sql))
|
7
|
-
end
|
8
|
-
|
9
|
-
def query(sql)
|
10
|
-
exec_query(sql).last
|
11
|
-
end
|
12
|
-
|
13
|
-
def query_values(sql)
|
14
|
-
query(sql).map(&:first)
|
15
|
-
end
|
16
|
-
|
17
|
-
def current_database
|
18
|
-
db_name.to_s
|
19
|
-
end
|
20
|
-
|
21
|
-
def current_schema
|
22
|
-
query_value("select current_schema from sysibm.sysdummy1").strip
|
23
|
-
end
|
24
|
-
alias library current_schema
|
25
|
-
|
26
|
-
private
|
27
|
-
def single_value_from_rows(rows)
|
28
|
-
row = rows.first
|
29
|
-
row && row.first
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
|
-
# Embed in a String to clear all previous ANSI sequences.
|
6
|
-
CLEAR = "\e[0m"
|
7
|
-
BOLD = "\e[1m"
|
8
|
-
|
9
|
-
# Colors
|
10
|
-
BLACK = "\e[30m"
|
11
|
-
RED = "\e[31m"
|
12
|
-
GREEN = "\e[32m"
|
13
|
-
YELLOW = "\e[33m"
|
14
|
-
BLUE = "\e[34m"
|
15
|
-
MAGENTA = "\e[35m"
|
16
|
-
CYAN = "\e[36m"
|
17
|
-
WHITE = "\e[37m"
|
18
|
-
|
19
|
-
def sql(event)
|
20
|
-
class_load_duration = color("#{event.payload[:name]} Load (#{event.duration.round(2)}ms)", :cyan, true)
|
21
|
-
sql_statement = color("#{event.payload[:sql]}", :blue, true)
|
22
|
-
message = " #{class_load_duration} #{sql_statement}"
|
23
|
-
|
24
|
-
if event.payload[:binds].size > 0
|
25
|
-
binds = color("#{event.payload[:binds]}", :white)
|
26
|
-
message = "#{message} [#{binds}]"
|
27
|
-
end
|
28
|
-
|
29
|
-
puts message
|
30
|
-
end
|
31
|
-
|
32
|
-
def schema_task(event)
|
33
|
-
puts color(" Done (#{(event.duration).round(2)}ms)", :green, true)
|
34
|
-
end
|
35
|
-
|
36
|
-
def schema_task_perform(event)
|
37
|
-
task_name = color(":#{event.payload[:task_name]}", :white, true)
|
38
|
-
schema = color("#{event.payload[:schema]}", :white, true)
|
39
|
-
puts "- Performing #{task_name} in #{schema} ..."
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
def color(text, color, bold = false) # :doc:
|
44
|
-
return text unless colorize_logging
|
45
|
-
color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
|
46
|
-
bold = bold ? BOLD : ""
|
47
|
-
"#{bold}#{color}#{text}#{CLEAR}"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
class ODBCConnector
|
5
|
-
attr_reader :connector, :conn_type, :conn_config
|
6
|
-
|
7
|
-
CONNECTION_TYPES = %i[dsn conn_string].freeze
|
8
|
-
|
9
|
-
def initialize(type, config)
|
10
|
-
@conn_type, @conn_config = type, config.transform_keys(&:to_sym)
|
11
|
-
@connector = Db2Query.const_get("#{conn_type.to_s.camelize}Connector").new
|
12
|
-
end
|
13
|
-
|
14
|
-
def connect
|
15
|
-
connector.connect(conn_config)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class DsnConnector
|
20
|
-
def connect(config)
|
21
|
-
::ODBC.connect(config[:dsn], config[:uid], config[:pwd])
|
22
|
-
rescue ::ODBC::Error => e
|
23
|
-
raise Error, "Unable to activate ODBC DSN connection #{e}"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class ConnStringConnector
|
28
|
-
def connect(config)
|
29
|
-
driver = ::ODBC::Driver.new.tap do |d|
|
30
|
-
d.attrs = config[:conn_string].transform_keys(&:to_s)
|
31
|
-
d.name = "odbc"
|
32
|
-
end
|
33
|
-
::ODBC::Database.new.drvconnect(driver)
|
34
|
-
rescue ::ODBC::Error => e
|
35
|
-
raise Error, "Unable to activate ODBC Conn String connection #{e}"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
data/lib/db2_query/path.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
module Path
|
5
|
-
def self.database_config_file
|
6
|
-
@@database_config_file ||= nil
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.database_config_file=(file_path)
|
10
|
-
@@database_config_file ||= file_path
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.database_config_file_exists?
|
14
|
-
File.exist?(self.database_config_file)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/db2_query/schema.rb
DELETED
@@ -1,113 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
class Schema
|
5
|
-
include SQLValidator
|
6
|
-
|
7
|
-
attr_accessor :config, :current_schema
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@config = Config.new
|
11
|
-
end
|
12
|
-
|
13
|
-
def connection
|
14
|
-
Base.connection
|
15
|
-
end
|
16
|
-
|
17
|
-
def schema
|
18
|
-
config.schema
|
19
|
-
end
|
20
|
-
|
21
|
-
def sql_files_dir(path)
|
22
|
-
config.sql_files_dir = path
|
23
|
-
end
|
24
|
-
|
25
|
-
def is_valid_schema?
|
26
|
-
connection.current_schema == config.schema
|
27
|
-
end
|
28
|
-
|
29
|
-
def perform_tasks(&block)
|
30
|
-
raise Error, "#{config.main_library} is not connection's current schema" unless is_valid_schema?
|
31
|
-
|
32
|
-
if Base.connection.nil? && config.init_connection
|
33
|
-
Base.establish_connection
|
34
|
-
end
|
35
|
-
|
36
|
-
puts "\n# Perform Schema Tasks: \n\n"
|
37
|
-
|
38
|
-
instance_eval(&block)
|
39
|
-
|
40
|
-
puts "\n"
|
41
|
-
end
|
42
|
-
|
43
|
-
def sql(sql_statement)
|
44
|
-
raise Error, "Task only for SQL execute commands." if query_command?(sql_statement)
|
45
|
-
sql_statement
|
46
|
-
end
|
47
|
-
|
48
|
-
def file(file_name)
|
49
|
-
sql(File.read("#{config.sql_files_dir}/#{file_name}"))
|
50
|
-
end
|
51
|
-
|
52
|
-
def task(task_name, sql = nil, *args)
|
53
|
-
Task.new(schema, task_name).perform do
|
54
|
-
if block_given?
|
55
|
-
yield(sql)
|
56
|
-
else
|
57
|
-
execute(sql, *args)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def execute(sql, *args)
|
63
|
-
connection.execute(sql, *args)
|
64
|
-
rescue ::ODBC::Error => e
|
65
|
-
raise Error, "Unable to execute SQL - #{e}"
|
66
|
-
end
|
67
|
-
|
68
|
-
def tables_in_schema
|
69
|
-
connection.query_values <<-SQL
|
70
|
-
SELECT table_name FROM SYSIBM.SQLTABLES
|
71
|
-
WHERE table_schem='#{schema}' AND table_type='TABLE'
|
72
|
-
SQL
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.initiation(&block)
|
76
|
-
new.initiation(&block)
|
77
|
-
end
|
78
|
-
|
79
|
-
def initiation(&block)
|
80
|
-
instance_eval(&block)
|
81
|
-
end
|
82
|
-
|
83
|
-
class Task
|
84
|
-
attr_reader :instrumenter, :schema, :task_name, :start_time, :finish_time
|
85
|
-
|
86
|
-
def initialize(schema, task_name)
|
87
|
-
@schema = schema
|
88
|
-
@task_name = task_name
|
89
|
-
@instrumenter = ActiveSupport::Notifications.instrumenter
|
90
|
-
end
|
91
|
-
|
92
|
-
def perform
|
93
|
-
instrumenter.instrument("schema_task_perform.db2_query", payload)
|
94
|
-
instrumenter.start("schema_task.db2_query", payload)
|
95
|
-
yield
|
96
|
-
instrumenter.finish("schema_task.db2_query", payload)
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
def payload
|
101
|
-
{ task_name: task_name, schema: schema }
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class Config
|
106
|
-
attr_accessor :initial_tasks, :init_connection, :schema, :sql_files_dir
|
107
|
-
|
108
|
-
def initialize
|
109
|
-
@init_connection = false
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Db2Query
|
4
|
-
module SQLValidator
|
5
|
-
DEFAULT_TASK_COMMANDS = [:create, :drop, :delete, :insert, :set, :update]
|
6
|
-
COMMENT_REGEX = %r{/\*(?:[^\*]|\*[^/])*\*/}m
|
7
|
-
|
8
|
-
def task_command?(sql_statement)
|
9
|
-
sql_statement.match?(task_commands_regexp)
|
10
|
-
end
|
11
|
-
|
12
|
-
def query_command?(sql_statement)
|
13
|
-
sql_statement.match?(/select/i)
|
14
|
-
end
|
15
|
-
|
16
|
-
def is_query?(sql_statement)
|
17
|
-
query_command?(sql_statement) && !task_command?(sql_statement)
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
def task_commands_regexp
|
22
|
-
parts = DEFAULT_TASK_COMMANDS.map { |part| /#{part}/i }
|
23
|
-
/\A(?:[\(\s]|#{COMMENT_REGEX})*#{Regexp.union(*parts)}/i
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/lib/tasks/database.rake
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
DB2_QUERY_DATABASE_TEMPLATE ||= <<-EOF
|
4
|
-
# frozen_string_literal: true
|
5
|
-
|
6
|
-
# Database configuration example
|
7
|
-
development:
|
8
|
-
primary:
|
9
|
-
conn_string:
|
10
|
-
driver: DB2
|
11
|
-
database: SAMPLE
|
12
|
-
dbalias: SAMPLE
|
13
|
-
hostname: LOCALHOST
|
14
|
-
currentschema: LIBTEST
|
15
|
-
port: "0"
|
16
|
-
protocol: IPC
|
17
|
-
uid: <%= ENV["DB2EC_UID"] %>
|
18
|
-
pwd: <%= ENV["DB2EC_PWD"] %>
|
19
|
-
secondary:
|
20
|
-
dsn: SAMPLE
|
21
|
-
uid: <%= ENV["DB2EC_UID"] %>
|
22
|
-
pwd: <%= ENV["DB2EC_PWD"] %>
|
23
|
-
|
24
|
-
test:
|
25
|
-
primary:
|
26
|
-
conn_string:
|
27
|
-
driver: DB2
|
28
|
-
database: SAMPLE
|
29
|
-
dbalias: SAMPLE
|
30
|
-
hostname: LOCALHOST
|
31
|
-
currentschema: LIBTEST
|
32
|
-
port: "0"
|
33
|
-
protocol: IPC
|
34
|
-
uid: <%= ENV["DB2EC_UID"] %>
|
35
|
-
pwd: <%= ENV["DB2EC_PWD"] %>
|
36
|
-
secondary:
|
37
|
-
dsn: SAMPLE
|
38
|
-
uid: <%= ENV["DB2EC_UID"] %>
|
39
|
-
pwd: <%= ENV["DB2EC_PWD"] %>
|
40
|
-
EOF
|
41
|
-
|
42
|
-
namespace :db2query do
|
43
|
-
desc "Create Database configuration file"
|
44
|
-
task :database do
|
45
|
-
database_path = "#{Rails.root}/config/db2query_database.yml"
|
46
|
-
if File.exist?(database_path)
|
47
|
-
raise ArgumentError, "File exists."
|
48
|
-
else
|
49
|
-
puts " Creating database config file ..."
|
50
|
-
File.open(database_path, "w") do |file|
|
51
|
-
file.puts DB2_QUERY_DATABASE_TEMPLATE
|
52
|
-
end
|
53
|
-
puts " File '#{database_path}' created."
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|