vorax 0.1.0pre
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/.gitignore +7 -0
- data/.rspec +1 -0
- data/LICENSE.txt +22 -0
- data/README.md +45 -0
- data/Rakefile +30 -0
- data/lib/vorax/base_funnel.rb +30 -0
- data/lib/vorax/output/html_convertor.rb +120 -0
- data/lib/vorax/output/html_funnel.rb +79 -0
- data/lib/vorax/output/pagezip_convertor.rb +20 -0
- data/lib/vorax/output/tablezip_convertor.rb +22 -0
- data/lib/vorax/output/vertical_convertor.rb +53 -0
- data/lib/vorax/output/zip_convertor.rb +117 -0
- data/lib/vorax/parser/argument.rb~ +125 -0
- data/lib/vorax/parser/body_split.rb +168 -0
- data/lib/vorax/parser/conn_string.rb +104 -0
- data/lib/vorax/parser/grammars/alias.rb +912 -0
- data/lib/vorax/parser/grammars/alias.rl +146 -0
- data/lib/vorax/parser/grammars/column.rb +454 -0
- data/lib/vorax/parser/grammars/column.rl +64 -0
- data/lib/vorax/parser/grammars/common.rl +98 -0
- data/lib/vorax/parser/grammars/package_spec.rb +1186 -0
- data/lib/vorax/parser/grammars/package_spec.rl +78 -0
- data/lib/vorax/parser/grammars/plsql_def.rb +469 -0
- data/lib/vorax/parser/grammars/plsql_def.rl +59 -0
- data/lib/vorax/parser/grammars/statement.rb +925 -0
- data/lib/vorax/parser/grammars/statement.rl +83 -0
- data/lib/vorax/parser/parser.rb +320 -0
- data/lib/vorax/parser/plsql_structure.rb +158 -0
- data/lib/vorax/parser/plsql_walker.rb +143 -0
- data/lib/vorax/parser/statement_inspector.rb~ +52 -0
- data/lib/vorax/parser/stmt_inspector.rb +78 -0
- data/lib/vorax/parser/target_ref.rb +110 -0
- data/lib/vorax/sqlplus.rb +281 -0
- data/lib/vorax/version.rb +7 -0
- data/lib/vorax/vorax_io.rb +70 -0
- data/lib/vorax.rb +60 -0
- data/spec/column_spec.rb +40 -0
- data/spec/conn_string_spec.rb +53 -0
- data/spec/package_spec_spec.rb +48 -0
- data/spec/pagezip_spec.rb +153 -0
- data/spec/parser_spec.rb +299 -0
- data/spec/plsql_structure_spec.rb +44 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/sql/create_objects.sql +69 -0
- data/spec/sql/dbms_crypto.spc +339 -0
- data/spec/sql/dbms_crypto.~spc +339 -0
- data/spec/sql/dbms_stats.spc +4097 -0
- data/spec/sql/drop_user.sql +10 -0
- data/spec/sql/muci.spc +24 -0
- data/spec/sql/setup_user.sql +22 -0
- data/spec/sql/test.pkg +67 -0
- data/spec/sqlplus_spec.rb +52 -0
- data/spec/stmt_inspector_spec.rb +84 -0
- data/spec/tablezip_spec.rb +111 -0
- data/spec/vertical_spec.rb +150 -0
- data/vorax.gemspec +21 -0
- metadata +139 -0
@@ -0,0 +1,168 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'strscan'
|
3
|
+
|
4
|
+
module Vorax
|
5
|
+
|
6
|
+
module Parser
|
7
|
+
|
8
|
+
class SubProgram
|
9
|
+
|
10
|
+
attr_accessor :start_pos, :declare_pos, :end_pos, :text, :level
|
11
|
+
attr_reader :name, :type
|
12
|
+
|
13
|
+
def initialize(name, type, start_pos)
|
14
|
+
@name = name
|
15
|
+
@type = type
|
16
|
+
@start_pos = start_pos
|
17
|
+
@declare_pos = nil
|
18
|
+
@end_pos = nil
|
19
|
+
@text = ''
|
20
|
+
@level = 0
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class BodySplit
|
26
|
+
|
27
|
+
PLSQL_SPEC = '(?:\bpackage\b|\btype\b)'
|
28
|
+
SUBPROG = '(?:\bfunction\b|\bprocedure\b)'
|
29
|
+
BEGIN_MODULE = '(?:\bbegin\b)'
|
30
|
+
END_MODULE = '(?:\bend\b)'
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
spots = [BEGIN_ML_COMMENT, BEGIN_SL_COMMENT,
|
34
|
+
BEGIN_PLSQL_SPECIAL_QUOTING, BEGIN_QUOTING,
|
35
|
+
PLSQL_SPEC, SUBPROG, BEGIN_MODULE, END_MODULE]
|
36
|
+
@marks = Regexp.new(spots.join('|'), Regexp::IGNORECASE)
|
37
|
+
@level = 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def split(text)
|
41
|
+
@blocks = []
|
42
|
+
@ss = StringScanner.new(text)
|
43
|
+
@level = 0
|
44
|
+
@crr_block = nil
|
45
|
+
while !@ss.eos?
|
46
|
+
Parser::consume(@ss, :scan_until, @marks)
|
47
|
+
process_ml_comment
|
48
|
+
process_sl_comment
|
49
|
+
process_double_quotes
|
50
|
+
process_plsql_quoting
|
51
|
+
process_single_quotes
|
52
|
+
process_plsql_spec
|
53
|
+
process_subprog
|
54
|
+
process_begin
|
55
|
+
process_end
|
56
|
+
end
|
57
|
+
return @blocks
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def process_ml_comment
|
63
|
+
scan_until(/\*\/\s*/) if @ss.matched =~ /#{BEGIN_ML_COMMENT}/
|
64
|
+
end
|
65
|
+
|
66
|
+
def process_sl_comment
|
67
|
+
scan_until(/\n/) if @ss.matched =~ /#{BEGIN_SL_COMMENT}/
|
68
|
+
end
|
69
|
+
|
70
|
+
def process_double_quotes
|
71
|
+
scan_until(/"/) if @ss.matched == '"'
|
72
|
+
end
|
73
|
+
|
74
|
+
def process_plsql_quoting
|
75
|
+
if @ss.matched =~ /q'\[/
|
76
|
+
scan_until(/\]'/)
|
77
|
+
elsif @ss.matched =~ /q'[{]/
|
78
|
+
scan_until(/[}]'/)
|
79
|
+
elsif @ss.matched =~ /q'[(]/
|
80
|
+
scan_until(/[)]'/)
|
81
|
+
elsif @ss.matched =~ /q'[<]/
|
82
|
+
scan_until(/[>]'/)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def process_single_quotes
|
87
|
+
if @ss.matched == "'"
|
88
|
+
begin
|
89
|
+
scan_until(/\'+/)
|
90
|
+
end while (@ss.matched != "'" && !@ss.eos?)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def process_plsql_spec
|
95
|
+
if @ss.matched =~ /#{PLSQL_SPEC}/i
|
96
|
+
meta_data = Parser.plsql_spec("#{@ss.matched}#{@ss.rest}")
|
97
|
+
if meta_data[:end_def] > 0
|
98
|
+
spec = SubProgram.new(meta_data[:name], 'spec', @ss.pos)
|
99
|
+
spec.declare_pos = @ss.pos + meta_data[:end_def]
|
100
|
+
scan_until(/#{SLASH_TERMINATOR}/)
|
101
|
+
spec.end_pos = @ss.pos
|
102
|
+
spec.text = @ss.string[(spec.start_pos..spec.end_pos)]
|
103
|
+
@blocks << spec
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def process_subprog
|
109
|
+
if @ss.matched =~ /#{SUBPROG}/i
|
110
|
+
subprog_name = @ss.peek(32)[/(?:"[^"]+")|(?:[A-Z0-9$_#]+)/i]
|
111
|
+
if @ss.matched =~ /function/i
|
112
|
+
subprog_type = 'function'
|
113
|
+
elsif @ss.matched =~ /procedure/i
|
114
|
+
subprog_type = 'procedure'
|
115
|
+
end
|
116
|
+
start_pos = @ss.pos - @ss.matched.length
|
117
|
+
@crr_block = SubProgram.new(subprog_name, subprog_type, start_pos)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def process_begin
|
122
|
+
if @ss.matched =~ /#{BEGIN_MODULE}/i && @crr_block
|
123
|
+
@level += 1
|
124
|
+
@crr_block.declare_pos = @ss.pos
|
125
|
+
@crr_block.level = @level
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def process_end
|
130
|
+
if @ss.matched =~ /#{END_MODULE}/i
|
131
|
+
# we have an "end" match. first of all check if it's not part
|
132
|
+
# of an conditional compiling "$end" definition
|
133
|
+
char_behind = @ss.string[@ss.pos - @ss.matched.length - 1, 1]
|
134
|
+
if char_behind != '$'
|
135
|
+
finish = Parser.end_subprog("#{@ss.matched}#{@ss.rest}")
|
136
|
+
if finish > 0
|
137
|
+
if @level == 1
|
138
|
+
if @crr_block
|
139
|
+
@crr_block.end_pos = (@ss.pos - 1) + (finish - 1)
|
140
|
+
@crr_block.text = @ss.string[(@crr_block.start_pos..@crr_block.end_pos)]
|
141
|
+
@blocks << @crr_block.clone
|
142
|
+
@crr_block = nil
|
143
|
+
end
|
144
|
+
end
|
145
|
+
@level -= 1
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def scan_until(regexp, skip = false)
|
152
|
+
if skip
|
153
|
+
@ss.skip_until(regexp)
|
154
|
+
else
|
155
|
+
segment = @ss.scan_until(regexp)
|
156
|
+
if !segment
|
157
|
+
@ss.terminate
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module Vorax
|
6
|
+
|
7
|
+
module Parser
|
8
|
+
|
9
|
+
# A class used to parse a connection string.
|
10
|
+
class ConnString
|
11
|
+
|
12
|
+
# Parse the given connection string.
|
13
|
+
#
|
14
|
+
# @return [Hash] a hash with the following keys:
|
15
|
+
#
|
16
|
+
# :user => the username,
|
17
|
+
# :password => the password,
|
18
|
+
# :db => the target database,
|
19
|
+
# :role => sysdba, sysasm or sysoper (if that's the case),
|
20
|
+
# :prompt_for => when some pieces are missing (e.g. password), the corresponding keys from above is put here
|
21
|
+
def parse(cstr)
|
22
|
+
# well known connection strings:
|
23
|
+
# - user => just the password will be prompted
|
24
|
+
# - user/pwd
|
25
|
+
# - user@db => just the password will be prompted
|
26
|
+
# - user/pwd@db [as sysdba|sysoper|sysasm]
|
27
|
+
# - /
|
28
|
+
# - / [as sysdba|sysoper|sysasm}
|
29
|
+
# - /@db => use wallet
|
30
|
+
Vorax::debug("parse connection string #{cstr.inspect}")
|
31
|
+
result = {:user => '', :password => '', :db => '', :role => '', :prompt_for => nil}
|
32
|
+
input = cstr.strip
|
33
|
+
scanner = StringScanner.new(input)
|
34
|
+
result[:user] = unquoted_scan(scanner, /[@\/]/)
|
35
|
+
has_pwd_slash = false
|
36
|
+
|
37
|
+
if scanner.matched?
|
38
|
+
# we have a @ or a / in our connection string
|
39
|
+
result[:user].chop!
|
40
|
+
if scanner.matched == "/"
|
41
|
+
has_pwd_slash = true
|
42
|
+
result[:password] = unquoted_scan(scanner, /@/)
|
43
|
+
if scanner.matched?
|
44
|
+
# there is a "@" so we know where to stop to extract the pwd
|
45
|
+
result[:password].chop!
|
46
|
+
extract_db(scanner, result)
|
47
|
+
else
|
48
|
+
# there's no "@" so assume everything to be the password
|
49
|
+
# except for the role
|
50
|
+
result[:password] = scanner.scan_until(/\z/)
|
51
|
+
extract_role(result, :password)
|
52
|
+
end
|
53
|
+
elsif scanner.matched == "@"
|
54
|
+
extract_db(scanner, result)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
# we don't have a @ or a / in our connection string
|
58
|
+
result[:user] = input
|
59
|
+
end
|
60
|
+
result[:user] = strip_quotes(result[:user])
|
61
|
+
result[:password] = strip_quotes(result[:password])
|
62
|
+
if result[:user].empty? && result[:password].empty? && has_pwd_slash
|
63
|
+
# assume OS authentication
|
64
|
+
result[:prompt_for] = nil
|
65
|
+
else
|
66
|
+
if result[:user].empty?
|
67
|
+
result[:prompt_for] = :user
|
68
|
+
elsif (not result[:user].empty?) && result[:password].empty?
|
69
|
+
result[:prompt_for] = :password
|
70
|
+
end
|
71
|
+
end
|
72
|
+
result
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def strip_quotes(text)
|
78
|
+
text.gsub(/\A"|"\z/, '')
|
79
|
+
end
|
80
|
+
|
81
|
+
def extract_db(scanner, cstr_hash)
|
82
|
+
cstr_hash[:db] = scanner.scan_until(/\z/)
|
83
|
+
extract_role(cstr_hash, :db)
|
84
|
+
end
|
85
|
+
|
86
|
+
def extract_role(cstr_hash, from_attr)
|
87
|
+
cstr_hash[from_attr].sub!(/\s+as\s+(sysdba|sysoper|sysasm)\z/i, '')
|
88
|
+
cstr_hash[:role] = $1.downcase if $1
|
89
|
+
end
|
90
|
+
|
91
|
+
def unquoted_scan(scanner, pattern)
|
92
|
+
result = ''
|
93
|
+
begin
|
94
|
+
fragment = scanner.scan_until(pattern)
|
95
|
+
result << fragment if fragment
|
96
|
+
end while fragment && result.count('"').odd? # go on if between quotes
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|