vorax 0.1.0pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|