mkxms-mssql 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -10
- data/lib/mkxms/mssql.rb +18 -0
- data/lib/mkxms/mssql/adoption_script_writer.rb +759 -91
- data/lib/mkxms/mssql/clr_aggregate_handler.rb +98 -0
- data/lib/mkxms/mssql/clr_assembly_handler.rb +92 -0
- data/lib/mkxms/mssql/clr_function_handler.rb +172 -0
- data/lib/mkxms/mssql/clr_impl.rb +58 -0
- data/lib/mkxms/mssql/clr_stored_procedure_handler.rb +88 -0
- data/lib/mkxms/mssql/clr_type_handler.rb +92 -0
- data/lib/mkxms/mssql/database_handler.rb +124 -3
- data/lib/mkxms/mssql/declaratives_creator.rb +206 -0
- data/lib/mkxms/mssql/dml_trigger_handler.rb +107 -0
- data/lib/mkxms/mssql/filegroup_handler.rb +1 -4
- data/lib/mkxms/mssql/function_handler.rb +1 -4
- data/lib/mkxms/mssql/indented_string_builder.rb +8 -2
- data/lib/mkxms/mssql/index_handler.rb +1 -4
- data/lib/mkxms/mssql/keywords.rb +492 -0
- data/lib/mkxms/mssql/primary_key_handler.rb +1 -4
- data/lib/mkxms/mssql/property_handler.rb +8 -0
- data/lib/mkxms/mssql/query_cursor.rb +12 -4
- data/lib/mkxms/mssql/references_handler.rb +24 -0
- data/lib/mkxms/mssql/role_handler.rb +1 -4
- data/lib/mkxms/mssql/scalar_type_handler.rb +108 -0
- data/lib/mkxms/mssql/schema_handler.rb +1 -4
- data/lib/mkxms/mssql/sql_string_manipulators.rb +4 -4
- data/lib/mkxms/mssql/statistics_handler.rb +1 -4
- data/lib/mkxms/mssql/stored_procedure_handler.rb +1 -4
- data/lib/mkxms/mssql/synonym_handler.rb +40 -0
- data/lib/mkxms/mssql/table_handler.rb +2 -8
- data/lib/mkxms/mssql/table_type_handler.rb +254 -0
- data/lib/mkxms/mssql/utils.rb +96 -0
- data/lib/mkxms/mssql/version.rb +1 -1
- data/lib/mkxms/mssql/view_handler.rb +1 -4
- data/spec/utils/indented_string_builder_spec.rb +21 -0
- data/spec/utils/query_cursor_spec.rb +2 -2
- data/spec/utils/sql_string_manipulators_spec.rb +59 -0
- metadata +18 -3
data/lib/mkxms/mssql/utils.rb
CHANGED
@@ -50,6 +50,92 @@ module Mkxms::Mssql::Utils
|
|
50
50
|
item.send(@children_message).each(&blk)
|
51
51
|
end
|
52
52
|
end
|
53
|
+
|
54
|
+
module StringHelpers
|
55
|
+
def expand_tabs(tabstops_every = 8)
|
56
|
+
self.lines.map do |l|
|
57
|
+
if l.include?("\t")
|
58
|
+
segs = l.split("\t")
|
59
|
+
segs[0...-1].map do |seg|
|
60
|
+
# seg length must _increase_ to a multiple of 8
|
61
|
+
spaces_needed = tabstops_every - (seg.length + 1) % tabstops_every + 1
|
62
|
+
seg + ' ' * spaces_needed
|
63
|
+
end.join('') + segs[-1]
|
64
|
+
else
|
65
|
+
l
|
66
|
+
end
|
67
|
+
end.join('')
|
68
|
+
end
|
69
|
+
|
70
|
+
def sql_quoted
|
71
|
+
%Q{N'#{gsub("'", "''")}'}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Primes in the interval [100, 255]. This enumerator can be queried by
|
76
|
+
# classes that generate RAISERROR statements to provide unique-ish context
|
77
|
+
# by passing the next multiple of one of the values taken from this
|
78
|
+
# enumerator for each RAISERROR statement output (as a literal number in
|
79
|
+
# the generated SQL). This will assist
|
80
|
+
RAISERROR_STATE_BASE = [
|
81
|
+
101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163 ,167, 173,
|
82
|
+
179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251
|
83
|
+
].each unless defined? RAISERROR_STATE_BASE
|
84
|
+
|
85
|
+
# Create one instance of this class to write a sequence of similar
|
86
|
+
# RAISERROR messages. The state of each message will be unique within the
|
87
|
+
# sequence until the 256th message. The particular order is unique to
|
88
|
+
# all other instances of this class.
|
89
|
+
class RaiserrorWriter
|
90
|
+
# Severity:
|
91
|
+
# 11 is the minimum to transfer into a CATCH
|
92
|
+
# 19 or higher can only be raised by sysadmin
|
93
|
+
# 20 or higher is fatal to the connection
|
94
|
+
|
95
|
+
SYMBOLIC_SEVERITIES = {
|
96
|
+
:warning => 1,
|
97
|
+
:error => 11,
|
98
|
+
}
|
99
|
+
|
100
|
+
def initialize(message, severity: 11)
|
101
|
+
# Get a unique prime to use as an ideal to generate the 0-255 state-value
|
102
|
+
# space. With luck, the number is fairly unique to the message.
|
103
|
+
severity = map_severity(severity)
|
104
|
+
@state_base = RAISERROR_STATE_BASE.next
|
105
|
+
@index = 1 # Start at 1 because 0 is the kernel -- every @state_base * 0 == 0
|
106
|
+
@message = message
|
107
|
+
@severity = severity
|
108
|
+
end
|
109
|
+
|
110
|
+
attr_reader :state_base
|
111
|
+
attr_accessor :message, :severity
|
112
|
+
|
113
|
+
def map_severity(value)
|
114
|
+
SYMBOLIC_SEVERITIES.fetch(value, value)
|
115
|
+
end
|
116
|
+
|
117
|
+
def current_statement(*args, severity: nil)
|
118
|
+
severity = map_severity(severity || self.severity)
|
119
|
+
state_str = current_error_marker
|
120
|
+
full_message = %Q{N'#{message.gsub("'", "''")} (search for "#{state_str}")'}
|
121
|
+
trailing_args = ([state_str] + args.map(&:to_s)).join(', ')
|
122
|
+
%Q{RAISERROR (#{full_message}, #{severity}, #{trailing_args})}.tap do |stmt|
|
123
|
+
stmt.define_singleton_method(:error_marker) {state_str}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def current_error_marker
|
128
|
+
"/*ERR*/ #{current_state} /*ERR*/"
|
129
|
+
end
|
130
|
+
|
131
|
+
def current_state
|
132
|
+
(state_base * @index) % 256
|
133
|
+
end
|
134
|
+
|
135
|
+
def next_statement(*args, **kwargs)
|
136
|
+
current_statement(*args, **kwargs).tap {@index += 1}
|
137
|
+
end
|
138
|
+
end
|
53
139
|
end
|
54
140
|
|
55
141
|
class << Mkxms::Mssql::Utils
|
@@ -80,4 +166,14 @@ class << Mkxms::Mssql::Utils
|
|
80
166
|
l
|
81
167
|
end.join('')
|
82
168
|
end
|
169
|
+
|
170
|
+
def dry_run?
|
171
|
+
@dry_run.tap do |v|
|
172
|
+
(break @dry_run = !!(ENV.fetch('DRY_RUN', '') =~ /^(y(es)?|t(rue)?|1)$/i)) if v.nil?
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class String
|
178
|
+
include Mkxms::Mssql::Utils::StringHelpers
|
83
179
|
end
|
data/lib/mkxms/mssql/version.rb
CHANGED
@@ -34,14 +34,11 @@ module Mkxms::Mssql
|
|
34
34
|
a = node.attributes
|
35
35
|
|
36
36
|
@view = View.new(a).tap do |v|
|
37
|
+
store_properties_on v
|
37
38
|
views << v
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
|
-
def extended_properties
|
42
|
-
@view.extended_properties
|
43
|
-
end
|
44
|
-
|
45
42
|
def handle_definition_element(parse); end
|
46
43
|
|
47
44
|
def handle_references_element(parse)
|
@@ -213,6 +213,27 @@ describe Mkxms::Mssql::IndentedStringBuilder do
|
|
213
213
|
test_instance = test_class.new
|
214
214
|
expect(test_instance.to_s).to eql("BEGIN\n command\nEND\n")
|
215
215
|
end
|
216
|
+
|
217
|
+
it "handles blank lines properly" do
|
218
|
+
test_class = Class.new(described_class) do
|
219
|
+
def initialize
|
220
|
+
super
|
221
|
+
|
222
|
+
add_level_one
|
223
|
+
end
|
224
|
+
|
225
|
+
def add_level_one
|
226
|
+
dsl {
|
227
|
+
puts "foo"
|
228
|
+
puts
|
229
|
+
}
|
230
|
+
puts "bar"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
test_instance = test_class.new
|
235
|
+
expect(test_instance.to_s).to eql("foo\n\nbar\n")
|
236
|
+
end
|
216
237
|
end
|
217
238
|
end
|
218
239
|
end
|
@@ -16,7 +16,7 @@ describe Mkxms::Mssql::QueryCursor do
|
|
16
16
|
sql.puts " -- Handle a row"
|
17
17
|
end
|
18
18
|
|
19
|
-
expect(sql.string).to eql("DECLARE @schema_id INT, @schema_name SYSNAME;\nDECLARE test_cursor CURSOR LOCAL FOR\nSELECT schema_id, name FROM sys.schemas;\nFETCH NEXT FROM test_cursor INTO @schema_id, @schema_name;\nWHILE @@FETCH_STATUS = 0\nBEGIN\n -- Handle a row\n FETCH NEXT FROM test_cursor INTO @schema_id, @schema_name;\nEND;\n")
|
19
|
+
expect(sql.string).to eql("DECLARE @schema_id INT, @schema_name SYSNAME;\nDECLARE test_cursor CURSOR LOCAL FOR\nSELECT schema_id, name FROM sys.schemas;\nOPEN test_cursor;\nFETCH NEXT FROM test_cursor INTO @schema_id, @schema_name;\nWHILE @@FETCH_STATUS = 0\nBEGIN\n -- Handle a row\n FETCH NEXT FROM test_cursor INTO @schema_id, @schema_name;\nEND;\n")
|
20
20
|
end
|
21
21
|
|
22
22
|
it "provides a expectation loop" do
|
@@ -52,6 +52,6 @@ describe Mkxms::Mssql::QueryCursor do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
expect(sql.string).to eql("DECLARE @column_name SYSNAME, @is_sorted_descending BIT;\nDECLARE test_cursor CURSOR LOCAL FOR\nSELECT c.name, ic.is_descending_key FROM sys.index_columns ic JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.object_id = @relation_id AND ic.index_id = @index_id AND ic.key_ordinal >= 1 ORDER BY ic.key_ordinal;\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS <> 0\nBEGIN\n-- Handle missing entry\nEND ELSE BEGIN\n-- Test column name is foo.\n-- Test is ascending.\nEND;\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS <> 0\nBEGIN\n-- Handle missing entry\nEND ELSE BEGIN\n-- Test column name is bar.\n-- Test is ascending.\nEND;\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS <> 0\nBEGIN\n-- Handle missing entry\nEND ELSE BEGIN\n-- Test column name is baz.\n-- Test is descending.\nEND;\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS = 0\nBEGIN\n-- Handle extra entry/ies\nEND;\nCLOSE test_cursor; DEALLOCATE test_cursor;\n")
|
55
|
+
expect(sql.string).to eql("DECLARE @column_name SYSNAME, @is_sorted_descending BIT;\nDECLARE test_cursor CURSOR LOCAL FOR\nSELECT c.name, ic.is_descending_key FROM sys.index_columns ic JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id WHERE ic.object_id = @relation_id AND ic.index_id = @index_id AND ic.key_ordinal >= 1 ORDER BY ic.key_ordinal;\nOPEN test_cursor;\n\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS <> 0\nBEGIN\n-- Handle missing entry\nEND ELSE BEGIN\n-- Test column name is foo.\n-- Test is ascending.\nEND;\n\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS <> 0\nBEGIN\n-- Handle missing entry\nEND ELSE BEGIN\n-- Test column name is bar.\n-- Test is ascending.\nEND;\n\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS <> 0\nBEGIN\n-- Handle missing entry\nEND ELSE BEGIN\n-- Test column name is baz.\n-- Test is descending.\nEND;\nFETCH NEXT FROM test_cursor INTO @column_name, @is_sorted_descending;\nIF @@FETCH_STATUS = 0\nBEGIN\n-- Handle extra entry/ies\nEND;\nCLOSE test_cursor; DEALLOCATE test_cursor;\n")
|
56
56
|
end
|
57
57
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'mkxms/mssql/sql_string_manipulators'
|
2
|
+
|
3
|
+
describe Mkxms::Mssql::SqlStringManipulators do
|
4
|
+
module T
|
5
|
+
extend Mkxms::Mssql::SqlStringManipulators
|
6
|
+
end
|
7
|
+
|
8
|
+
context "dedenting" do
|
9
|
+
it "handles a string with no newlines" do
|
10
|
+
expect(T.dedent("foo")).to eq("foo")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "handles a string with a all lines at a constant indent" do
|
14
|
+
s = T.dedent %Q{
|
15
|
+
Jack and Jill went up the hill
|
16
|
+
to fetch a pail of water
|
17
|
+
}
|
18
|
+
expect(s.lines.size).to eq(2)
|
19
|
+
expect(s.lines[0]).not_to start_with(' ')
|
20
|
+
end
|
21
|
+
|
22
|
+
it "handles nested indentation" do
|
23
|
+
s = T.dedent %Q{
|
24
|
+
one
|
25
|
+
two
|
26
|
+
one
|
27
|
+
two
|
28
|
+
}
|
29
|
+
expect(s.lines.size).to eq(4)
|
30
|
+
expect(s.lines[0]).not_to start_with(' ')
|
31
|
+
expect(s.lines[1]).to start_with(' t')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "allows leading blank lines" do
|
35
|
+
s = T.dedent %Q{
|
36
|
+
|
37
|
+
after the break
|
38
|
+
}
|
39
|
+
expect(s.lines[0]).to match(/^\s*$/)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "allows trailing blank lines" do
|
43
|
+
s = T.dedent %Q{
|
44
|
+
before the break
|
45
|
+
|
46
|
+
}
|
47
|
+
expect(s.lines[1]).to match(/^\s*$/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "allows internal blank lines" do
|
51
|
+
s = T.dedent %Q{
|
52
|
+
before
|
53
|
+
|
54
|
+
after
|
55
|
+
}
|
56
|
+
expect(s.lines[1]).to eq("\n")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mkxms-mssql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Weeks
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xmigra
|
@@ -85,8 +85,16 @@ files:
|
|
85
85
|
- lib/mkxms/mssql/access_object_definition.rb
|
86
86
|
- lib/mkxms/mssql/adoption_script_writer.rb
|
87
87
|
- lib/mkxms/mssql/check_constraint_handler.rb
|
88
|
+
- lib/mkxms/mssql/clr_aggregate_handler.rb
|
89
|
+
- lib/mkxms/mssql/clr_assembly_handler.rb
|
90
|
+
- lib/mkxms/mssql/clr_function_handler.rb
|
91
|
+
- lib/mkxms/mssql/clr_impl.rb
|
92
|
+
- lib/mkxms/mssql/clr_stored_procedure_handler.rb
|
93
|
+
- lib/mkxms/mssql/clr_type_handler.rb
|
88
94
|
- lib/mkxms/mssql/database_handler.rb
|
95
|
+
- lib/mkxms/mssql/declaratives_creator.rb
|
89
96
|
- lib/mkxms/mssql/default_constraint_handler.rb
|
97
|
+
- lib/mkxms/mssql/dml_trigger_handler.rb
|
90
98
|
- lib/mkxms/mssql/engine.rb
|
91
99
|
- lib/mkxms/mssql/exceptions.rb
|
92
100
|
- lib/mkxms/mssql/filegroup_handler.rb
|
@@ -96,16 +104,21 @@ files:
|
|
96
104
|
- lib/mkxms/mssql/index_column.rb
|
97
105
|
- lib/mkxms/mssql/index_handler.rb
|
98
106
|
- lib/mkxms/mssql/keylike_constraint_helper.rb
|
107
|
+
- lib/mkxms/mssql/keywords.rb
|
99
108
|
- lib/mkxms/mssql/permission_handler.rb
|
100
109
|
- lib/mkxms/mssql/primary_key_handler.rb
|
101
110
|
- lib/mkxms/mssql/property_handler.rb
|
102
111
|
- lib/mkxms/mssql/query_cursor.rb
|
112
|
+
- lib/mkxms/mssql/references_handler.rb
|
103
113
|
- lib/mkxms/mssql/role_handler.rb
|
114
|
+
- lib/mkxms/mssql/scalar_type_handler.rb
|
104
115
|
- lib/mkxms/mssql/schema_handler.rb
|
105
116
|
- lib/mkxms/mssql/sql_string_manipulators.rb
|
106
117
|
- lib/mkxms/mssql/statistics_handler.rb
|
107
118
|
- lib/mkxms/mssql/stored_procedure_handler.rb
|
119
|
+
- lib/mkxms/mssql/synonym_handler.rb
|
108
120
|
- lib/mkxms/mssql/table_handler.rb
|
121
|
+
- lib/mkxms/mssql/table_type_handler.rb
|
109
122
|
- lib/mkxms/mssql/unique_constraint_handler.rb
|
110
123
|
- lib/mkxms/mssql/utils.rb
|
111
124
|
- lib/mkxms/mssql/version.rb
|
@@ -113,6 +126,7 @@ files:
|
|
113
126
|
- mkxms-mssql.gemspec
|
114
127
|
- spec/utils/indented_string_builder_spec.rb
|
115
128
|
- spec/utils/query_cursor_spec.rb
|
129
|
+
- spec/utils/sql_string_manipulators_spec.rb
|
116
130
|
homepage: ''
|
117
131
|
licenses:
|
118
132
|
- MIT
|
@@ -133,10 +147,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
147
|
version: '0'
|
134
148
|
requirements: []
|
135
149
|
rubyforge_project:
|
136
|
-
rubygems_version: 2.
|
150
|
+
rubygems_version: 2.4.8
|
137
151
|
signing_key:
|
138
152
|
specification_version: 4
|
139
153
|
summary: XMigra source files from MS-SQL database description.
|
140
154
|
test_files:
|
141
155
|
- spec/utils/indented_string_builder_spec.rb
|
142
156
|
- spec/utils/query_cursor_spec.rb
|
157
|
+
- spec/utils/sql_string_manipulators_spec.rb
|