vorax 0.1.0pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +7 -0
  2. data/.rspec +1 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +45 -0
  5. data/Rakefile +30 -0
  6. data/lib/vorax/base_funnel.rb +30 -0
  7. data/lib/vorax/output/html_convertor.rb +120 -0
  8. data/lib/vorax/output/html_funnel.rb +79 -0
  9. data/lib/vorax/output/pagezip_convertor.rb +20 -0
  10. data/lib/vorax/output/tablezip_convertor.rb +22 -0
  11. data/lib/vorax/output/vertical_convertor.rb +53 -0
  12. data/lib/vorax/output/zip_convertor.rb +117 -0
  13. data/lib/vorax/parser/argument.rb~ +125 -0
  14. data/lib/vorax/parser/body_split.rb +168 -0
  15. data/lib/vorax/parser/conn_string.rb +104 -0
  16. data/lib/vorax/parser/grammars/alias.rb +912 -0
  17. data/lib/vorax/parser/grammars/alias.rl +146 -0
  18. data/lib/vorax/parser/grammars/column.rb +454 -0
  19. data/lib/vorax/parser/grammars/column.rl +64 -0
  20. data/lib/vorax/parser/grammars/common.rl +98 -0
  21. data/lib/vorax/parser/grammars/package_spec.rb +1186 -0
  22. data/lib/vorax/parser/grammars/package_spec.rl +78 -0
  23. data/lib/vorax/parser/grammars/plsql_def.rb +469 -0
  24. data/lib/vorax/parser/grammars/plsql_def.rl +59 -0
  25. data/lib/vorax/parser/grammars/statement.rb +925 -0
  26. data/lib/vorax/parser/grammars/statement.rl +83 -0
  27. data/lib/vorax/parser/parser.rb +320 -0
  28. data/lib/vorax/parser/plsql_structure.rb +158 -0
  29. data/lib/vorax/parser/plsql_walker.rb +143 -0
  30. data/lib/vorax/parser/statement_inspector.rb~ +52 -0
  31. data/lib/vorax/parser/stmt_inspector.rb +78 -0
  32. data/lib/vorax/parser/target_ref.rb +110 -0
  33. data/lib/vorax/sqlplus.rb +281 -0
  34. data/lib/vorax/version.rb +7 -0
  35. data/lib/vorax/vorax_io.rb +70 -0
  36. data/lib/vorax.rb +60 -0
  37. data/spec/column_spec.rb +40 -0
  38. data/spec/conn_string_spec.rb +53 -0
  39. data/spec/package_spec_spec.rb +48 -0
  40. data/spec/pagezip_spec.rb +153 -0
  41. data/spec/parser_spec.rb +299 -0
  42. data/spec/plsql_structure_spec.rb +44 -0
  43. data/spec/spec_helper.rb +13 -0
  44. data/spec/sql/create_objects.sql +69 -0
  45. data/spec/sql/dbms_crypto.spc +339 -0
  46. data/spec/sql/dbms_crypto.~spc +339 -0
  47. data/spec/sql/dbms_stats.spc +4097 -0
  48. data/spec/sql/drop_user.sql +10 -0
  49. data/spec/sql/muci.spc +24 -0
  50. data/spec/sql/setup_user.sql +22 -0
  51. data/spec/sql/test.pkg +67 -0
  52. data/spec/sqlplus_spec.rb +52 -0
  53. data/spec/stmt_inspector_spec.rb +84 -0
  54. data/spec/tablezip_spec.rb +111 -0
  55. data/spec/vertical_spec.rb +150 -0
  56. data/vorax.gemspec +21 -0
  57. 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