each_sql 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "bundler", "~> 1.0.0"
10
+ gem "jeweler", "~> 1.6.2"
11
+ gem "rcov", ">= 0"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ git (1.2.5)
5
+ jeweler (1.6.2)
6
+ bundler (~> 1.0)
7
+ git (>= 1.2.5)
8
+ rake
9
+ rake (0.8.7)
10
+ rcov (0.9.9)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ bundler (~> 1.0.0)
17
+ jeweler (~> 1.6.2)
18
+ rcov
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Junegunn Choi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,52 @@
1
+ = each_sql
2
+
3
+ Enumerate each SQL statement in the given SQL script.
4
+
5
+ == Installation
6
+ gem install 'each_sql'
7
+
8
+ == Example
9
+ === Basic
10
+ require 'each_sql'
11
+
12
+ EachSQL(sql_script).each do |sql|
13
+ puts sql
14
+ end
15
+
16
+ sqls = EachSQL(sql_script).to_a
17
+
18
+ === For scripts containing vendor-specific syntax
19
+ # For MySQL script
20
+ EachSQL(mysql_script, :mysql).each do |sql|
21
+ # ...
22
+ end
23
+
24
+ # For Oracle PL/SQL scripts
25
+ EachSQL(plsql_script, :oracle).each do |sql|
26
+ # ...
27
+ end
28
+
29
+ == TODO
30
+ - More/better tests.
31
+ - pgplsql support.
32
+
33
+ == Warning
34
+ Should be good enough for regular SQLs, but it is not guaranteed to parse stored procedures correctly.
35
+ I thought this would be simple when I first started, but actually it wasn't, and the code now is a mess.
36
+ Use it at your own risk.
37
+
38
+ == Contributing to each_sql
39
+
40
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
41
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
42
+ * Fork the project
43
+ * Start a feature/bugfix branch
44
+ * Commit and push until you are happy with your contribution
45
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
46
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
47
+
48
+ == Copyright
49
+
50
+ Copyright (c) 2011 Junegunn Choi. See LICENSE.txt for
51
+ further details.
52
+
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "each_sql"
18
+ gem.homepage = "http://github.com/junegunn/each_sql"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Enumerate through each SQL statement in SQL scripts.}
21
+ gem.description = %Q{Enumerate through each SQL statement in SQL scripts.}
22
+ gem.email = "junegunn.c@gmail.com"
23
+ gem.authors = ["Junegunn Choi"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "each_sql #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,160 @@
1
+ # encoding: UTF-8
2
+ # Junegunn Choi (junegunn.c@gmail.com)
3
+
4
+ # Enumerable EachSQL object.
5
+ class EachSQL
6
+ include Enumerable
7
+
8
+ def initialize input, options
9
+ raise NotImplementedError.new if options.nil?
10
+ # immutables
11
+ @org_input = input
12
+ @options = options
13
+ @blocks = @options[:blocks]
14
+ @nblocks = @options[:nesting_blocks]
15
+ @all_blocks = @blocks.merge @nblocks
16
+ end
17
+
18
+ def each
19
+ @input = @org_input
20
+ return nil if @input.nil? || @input.empty?
21
+
22
+ @delimiter = @options[:delimiter]
23
+
24
+ reset_cursor
25
+ while @input
26
+ # First look for next delimiter, this is to reduce the search space for blocks.
27
+ extend_scope
28
+
29
+ # We're done. Finished. Period. Out!
30
+ break if scope.empty?
31
+
32
+ # Extract a statement
33
+ statement = extract_statement
34
+
35
+ # When a non-empty statement is found
36
+ statement = @options[:strip_delimiter].call self, statement if @options[:strip_delimiter]
37
+ if statement.length > 0
38
+ # Apply replacements
39
+ @options[:replace].each do |k, v|
40
+ statement.gsub!(k, v)
41
+ end
42
+ statement.strip!
43
+
44
+ # Process callbacks
45
+ @options[:callbacks].each do |pattern, callback|
46
+ md = statement.match pattern
47
+ callback.call self, statement, md if md
48
+ end
49
+
50
+ # Ignore
51
+ if (@options[:ignore] || []).all? { |ipat| statement !~ ipat }
52
+ yield statement
53
+ @prev_statement = statement
54
+ end
55
+ end
56
+ end
57
+ nil
58
+ end
59
+
60
+ attr_accessor :delimiter, :delimiter_string
61
+ private
62
+
63
+ def extract_statement
64
+ while process_next_block != :not_found
65
+ end
66
+
67
+ ret = scope.strip
68
+ @input = @input[@next_head..-1]
69
+ reset_cursor
70
+ return ret
71
+ end
72
+
73
+ def reset_cursor
74
+ @cur = @from = @to = 0
75
+ end
76
+
77
+ def scope
78
+ @to ? @input[0, @to] : @input
79
+ end
80
+
81
+ def extend_scope
82
+ md = @input.match @delimiter, @to
83
+
84
+ if md
85
+ @to = md.begin(0) + md[0].length
86
+ @next_head = @to
87
+ else
88
+ @to = @input.length
89
+ @next_head = @input.length
90
+ end
91
+ #puts "Extended: #{scope.inspect} #{@input[@next_head..-1]}"
92
+ end
93
+
94
+ def process_next_block expect = nil
95
+ # Look for the closest block
96
+ block_start, opener_length, opener, closer = @all_blocks.map { |opener, closer|
97
+ closer = closer[:closer] if closer.is_a? Hash
98
+ md = scope.match(opener, @cur)
99
+ [md && md.begin(0), md && md[0].length, opener, closer]
100
+ }.reject { |e| e.first.nil? }.min_by(&:first)
101
+
102
+ # p [scope, scope[@cur..-1], expect, scope.index(expect, @cur), block_start] if expect
103
+ # We found a block, but after the end of the nesting block
104
+ if expect &&
105
+ (prev_end = scope.index(expect, @cur)) &&
106
+ (block_start.nil? || prev_end <= block_start)
107
+ skip_through_block expect, prev_end == block_start
108
+ return :end_nest
109
+ end
110
+
111
+ # If no block in this scope
112
+ return :not_found if block_start.nil?
113
+
114
+ # We found a block. Look for the end of it
115
+ @cur = block_start + opener_length
116
+
117
+ # If nesting block, we go deeper
118
+ if @nblocks.keys.include? opener
119
+ @prev_delimiter = @delimiter
120
+ if @nblocks[opener].is_a? Hash
121
+ @delimiter = @nblocks[opener][:delimiter] || @delimiter
122
+ end
123
+ while true
124
+ ret = process_next_block(closer)
125
+
126
+ break if ret == :end_nest
127
+ extend_scope if ret == :not_found
128
+ throw_exception(closer) if scope.length == @input.length
129
+ end
130
+ @delimiter = @prev_delimiter
131
+
132
+ # If non-nesting block, just skip through it
133
+ else
134
+ skip_through_block closer
135
+ end
136
+
137
+ return :continue
138
+ end
139
+
140
+ def skip_through_block closer, rewind_delimiter = false
141
+ md = @input.match closer, @cur
142
+ block_end = md && md.begin(0)
143
+
144
+ throw_exception(closer) if block_end.nil?
145
+
146
+ @cur = block_end + (rewind_delimiter ? 0 : md[0].length)
147
+ while @cur > scope.length
148
+ extend_scope
149
+ end
150
+ end
151
+
152
+ def throw_exception closer
153
+ raise ArgumentError.new(
154
+ "Unclosed block: was expecting #{closer.inspect} " +
155
+ "while processing #{$/ + scope.inspect}" +
156
+ (@prev_statement ?
157
+ " after #{@prev_statement.inspect}" : ""))
158
+ end
159
+ end#EachSQL
160
+
data/lib/each_sql.rb ADDED
@@ -0,0 +1,92 @@
1
+ # encoding: UTF-8
2
+ # Junegunn Choi (junegunn.c@gmail.com)
3
+
4
+ require 'each_sql/each_sql'
5
+
6
+ # Shortcut method for creating a Enumerable EachSQL object for the given input.
7
+ # @param[String] input Input script.
8
+ # @param[Symbol] The type of the input SQL script. :default, :mysql, and :oracle (or :plsql)
9
+ # @return[EachSQL] Enumerable
10
+ def EachSQL input, type = :default
11
+ EachSQL.new(input, EachSQL::Defaults[type])
12
+ end
13
+
14
+ class EachSQL
15
+ # EachSQL::Default Hash is a set of pre-defined parsing rules
16
+ # - :default: Default parsing rules for vendor-independent SQL scripts
17
+ # - :mysql: Parsing rules for MySQL scripts. Understands `delimiter' statements.
18
+ # - :oracle: Parsing rules for Oracle scripts. Removes trailing slashes after begin-end blocks.
19
+ Defaults = {
20
+ :default => {
21
+ :delimiter => /;+/,
22
+ :blocks => {
23
+ /'/ => /'/,
24
+ /\/\*[^+]/ => /\*\//,
25
+ /--+/ => $/,
26
+ },
27
+ :nesting_blocks => {
28
+ /\bdeclare\b/i => /\bbegin\b/i,
29
+ /\bbegin\b/i => /\bend\b/i
30
+ },
31
+ :callbacks => {},
32
+ :ignore => [],
33
+ :replace => {},
34
+ # Let's assume we don't change delimiters within usual sql scripts
35
+ :strip_delimiter => lambda { |obj, stmt| stmt.chomp ';' }
36
+ },
37
+
38
+ :mysql => {
39
+ :delimiter => /;+|delimiter\s+\S+/i,
40
+ :blocks => {
41
+ /'/ => /'/,
42
+ /\/\*[^+]/ => /\*\//,
43
+ /--+/ => $/,
44
+ },
45
+ :nesting_blocks => {
46
+ /\bbegin\b/i => /\bend\b/i
47
+ },
48
+ # We need to change delimiter on `delimiter' command
49
+ :callbacks => {
50
+ /^\s*delimiter\s+(\S+)/i => lambda { |obj, stmt, md|
51
+ new_delimiter = Regexp.new(Regexp.escape md[1])
52
+ obj.delimiter = /#{new_delimiter}+|delimiter\s+\S+/i
53
+ obj.delimiter_string = md[1]
54
+ }
55
+ },
56
+ :ignore => [
57
+ /^delimiter\s+\S+$/i
58
+ ],
59
+ :replace => {},
60
+ :strip_delimiter => lambda { |obj, stmt|
61
+ stmt.chomp(obj.delimiter_string || ';')
62
+ }
63
+ },
64
+
65
+ :oracle => {
66
+ :delimiter => /;+/,
67
+ :blocks => {
68
+ /'/ => /'/,
69
+ /\/\*[^+]/ => /\*\//,
70
+ /--+/ => $/,
71
+ },
72
+ :nesting_blocks => {
73
+ /\bbegin\b/i => /\bend\b/i,
74
+ /\bcreate[^;]*\b(procedure|function|trigger|package)\b/im => {
75
+ :closer => %r{;\s*/}m,
76
+ :delimiter => /;\s*\//
77
+ }
78
+ },
79
+ :callbacks => {},
80
+ :ignore => [],
81
+ :replace => {},
82
+ :strip_delimiter => lambda { |obj, stmt| obj
83
+ stmt.chomp( stmt =~ /;\s*\// ? '/' : ';' )
84
+ }
85
+ }
86
+ }
87
+ Defaults[:plsql] = Defaults[:oracle] # alias
88
+
89
+ # Freeze the Hash
90
+ Defaults.freeze
91
+ end
92
+
data/test/helper.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+
12
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ require 'each_sql'
15
+
16
+ class Test::Unit::TestCase
17
+ end
data/test/postgres.sql ADDED
@@ -0,0 +1,128 @@
1
+ --
2
+ -- Main tables - time dimension and sales fact.
3
+ --
4
+ CREATE TABLE time_dimension (
5
+ time_key integer NOT NULL,
6
+ day_of_week integer NOT NULL,
7
+ day_of_month integer NOT NULL,
8
+ month integer NOT NULL,
9
+ quarter integer NOT NULL,
10
+ year integer NOT NULL
11
+ );
12
+ CREATE UNIQUE INDEX time_dimension_key ON time_dimension(time_key);
13
+
14
+ CREATE TABLE sales_fact (
15
+ time_key integer NOT NULL,
16
+ product_key integer NOT NULL,
17
+ store_key integer NOT NULL,
18
+ amount_sold numeric(12,2) NOT NULL,
19
+ units_sold integer NOT NULL,
20
+ amount_cost numeric(12,2) NOT NULL
21
+ );
22
+ CREATE INDEX sales_fact_time ON sales_fact(time_key);
23
+
24
+ --
25
+ -- Summary table - sales by time.
26
+ --
27
+ CREATE TABLE sales_summary_bytime (
28
+ time_key integer NOT NULL,
29
+ amount_sold numeric(15,2) NOT NULL,
30
+ units_sold numeric(12) NOT NULL,
31
+ amount_cost numeric(15,2) NOT NULL
32
+ );
33
+ CREATE UNIQUE INDEX sales_summary_bytime_key ON sales_summary_bytime(time_key);
34
+
35
+ --
36
+ -- Function and trigger to amend summarized column(s) on UPDATE, INSERT, DELETE.
37
+ --
38
+ CREATE OR REPLACE FUNCTION maint_sales_summary_bytime() RETURNS TRIGGER AS $maint_sales_summary_bytime$
39
+ DECLARE
40
+ delta_time_key integer;
41
+ delta_amount_sold numeric(15,2);
42
+ delta_units_sold numeric(12);
43
+ delta_amount_cost numeric(15,2);
44
+ BEGIN
45
+
46
+ -- Work out the increment/decrement amount(s).
47
+ IF (TG_OP = 'DELETE') THEN
48
+
49
+ delta_time_key = OLD.time_key;
50
+ delta_amount_sold = -1 * OLD.amount_sold;
51
+ delta_units_sold = -1 * OLD.units_sold;
52
+ delta_amount_cost = -1 * OLD.amount_cost;
53
+
54
+ ELSIF (TG_OP = 'UPDATE') THEN
55
+
56
+ -- forbid updates that change the time_key -
57
+ -- (probably not too onerous, as DELETE + INSERT is how most
58
+ -- changes will be made).
59
+ IF ( OLD.time_key != NEW.time_key) THEN
60
+ RAISE EXCEPTION 'Update of time_key : % -> % not allowed', OLD.time_key, NEW.time_key;
61
+ END IF;
62
+
63
+ delta_time_key = OLD.time_key;
64
+ delta_amount_sold = NEW.amount_sold - OLD.amount_sold;
65
+ delta_units_sold = NEW.units_sold - OLD.units_sold;
66
+ delta_amount_cost = NEW.amount_cost - OLD.amount_cost;
67
+
68
+ ELSIF (TG_OP = 'INSERT') THEN
69
+
70
+ delta_time_key = NEW.time_key;
71
+ delta_amount_sold = NEW.amount_sold;
72
+ delta_units_sold = NEW.units_sold;
73
+ delta_amount_cost = NEW.amount_cost;
74
+
75
+ END IF;
76
+
77
+
78
+ -- Insert or update the summary row with the new values.
79
+ <<insert_update>>
80
+ LOOP
81
+ UPDATE sales_summary_bytime
82
+ SET amount_sold = amount_sold + delta_amount_sold,
83
+ units_sold = units_sold + delta_units_sold,
84
+ amount_cost = amount_cost + delta_amount_cost
85
+ WHERE time_key = delta_time_key;
86
+
87
+ EXIT insert_update WHEN found;
88
+
89
+ BEGIN
90
+ INSERT INTO sales_summary_bytime (
91
+ time_key,
92
+ amount_sold,
93
+ units_sold,
94
+ amount_cost)
95
+ VALUES (
96
+ delta_time_key,
97
+ delta_amount_sold,
98
+ delta_units_sold,
99
+ delta_amount_cost
100
+ );
101
+
102
+ EXIT insert_update;
103
+
104
+ EXCEPTION
105
+ WHEN UNIQUE_VIOLATION THEN
106
+ -- do nothing
107
+ END;
108
+ END LOOP insert_update;
109
+
110
+ RETURN NULL;
111
+
112
+ END;
113
+ $maint_sales_summary_bytime$ LANGUAGE plpgsql;
114
+
115
+ CREATE TRIGGER maint_sales_summary_bytime
116
+ AFTER INSERT OR UPDATE OR DELETE ON sales_fact
117
+ FOR EACH ROW EXECUTE PROCEDURE maint_sales_summary_bytime();
118
+
119
+ INSERT INTO sales_fact VALUES(1,1,1,10,3,15);
120
+ INSERT INTO sales_fact VALUES(1,2,1,20,5,35);
121
+ INSERT INTO sales_fact VALUES(2,2,1,40,15,135);
122
+ INSERT INTO sales_fact VALUES(2,3,1,10,1,13);
123
+ SELECT * FROM sales_summary_bytime;
124
+ DELETE FROM sales_fact WHERE product_key = 1;
125
+ SELECT * FROM sales_summary_bytime;
126
+ UPDATE sales_fact SET units_sold = units_sold * 2;
127
+ SELECT * FROM sales_summary_bytime;
128
+
@@ -0,0 +1,139 @@
1
+ $LOAD_PATH << File.dirname(__FILE__)
2
+ require 'helper'
3
+
4
+ class TestEachSql < Test::Unit::TestCase
5
+ def setup
6
+ @sql = [
7
+ "select * from a",
8
+ "select
9
+ *
10
+ from
11
+ b",
12
+ "select 'abc', 'abc;', 'abc''', 'abc/*', 'abc--' from c",
13
+
14
+ "select
15
+ /*+ help */ *
16
+ from
17
+ d",
18
+ "select * from /* block comment ; */ e",
19
+ "select *
20
+ from -- line comment ; /* ;; */
21
+ f",
22
+ "-------------- begin-end block;
23
+ begin
24
+ -- begin-end block;
25
+ -- line comment
26
+ -- line comment
27
+ -- line comment
28
+ begin
29
+ null;
30
+ begin
31
+ null;
32
+ end;
33
+ end;
34
+ -- end
35
+ /* end */
36
+ end",
37
+ "-------------- begin-end block;
38
+ declare
39
+ /* end; */
40
+ /* begin */
41
+ null;
42
+ null;
43
+ null;
44
+ begin
45
+ /* end */
46
+ end",
47
+ "-------------- begin-end block;
48
+ declare
49
+ /* end; */
50
+ /* begin */
51
+ null;
52
+ null;
53
+ null;
54
+ begin
55
+ -- begin-end block;
56
+ -- line comment
57
+ -- line comment
58
+ -- line comment
59
+ begin
60
+ null;
61
+ begin
62
+ null;
63
+ end;
64
+ end;
65
+ -- end
66
+ /* end */
67
+ end",
68
+ "select * from dual",
69
+ "select * from dual"]
70
+
71
+ @oracle = "
72
+ select * from dual;
73
+ Create or replace Procedure tmmp(p1 number, p2 number) as
74
+ str number(8, 2) := 1 / 4;
75
+ begin
76
+ begin
77
+ 1 / 4;
78
+ null;
79
+ end;
80
+ exception
81
+ when others then
82
+ raise;
83
+ end;
84
+ /
85
+ select * from dual;"
86
+
87
+ @mysql = "
88
+ delimiter //
89
+ drop procedure if exists proc //
90
+ create procedure proc(p1 int, p2 int)
91
+ begin
92
+ null;
93
+
94
+ end //
95
+ delimiter ;
96
+
97
+ delimiter $$
98
+ drop procedure if exists proc2 $$
99
+ create procedure proc(p1 int, p2 int)
100
+ begin
101
+ null;
102
+
103
+ end $$
104
+ delimiter ;
105
+
106
+ select * from dual;"
107
+ end
108
+
109
+ def test_sql
110
+ script = @sql.map { |e| e.strip + ';' }.join $/
111
+ EachSQL(script).each_with_index do |sql,idx|
112
+ puts sql
113
+ puts '-' * 40
114
+ assert_equal @sql[idx], sql
115
+ end
116
+ assert_equal EachSQL(script).to_a, EachSQL(script).map { |e| e }
117
+ end
118
+
119
+ def test_oracle
120
+ EachSQL(@oracle, :oracle).each_with_index do |sql,idx|
121
+ puts sql
122
+ puts '-' * 40
123
+ end
124
+ end
125
+
126
+ def test_mysql
127
+ EachSQL(@mysql, :mysql).each_with_index do |sql,idx|
128
+ puts sql
129
+ puts '-' * 40
130
+ end
131
+ end
132
+
133
+ def _test_postgres
134
+ EachSQL(File.read(File.dirname(__FILE__) + '/postgres.sql'), :postgres).each_with_index do |sql,idx|
135
+ puts sql
136
+ puts '-' * 40
137
+ end
138
+ end
139
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: each_sql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Junegunn Choi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-06-15 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &2161738720 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2161738720
25
+ - !ruby/object:Gem::Dependency
26
+ name: jeweler
27
+ requirement: &2161738240 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.2
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2161738240
36
+ - !ruby/object:Gem::Dependency
37
+ name: rcov
38
+ requirement: &2161737760 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2161737760
47
+ description: Enumerate through each SQL statement in SQL scripts.
48
+ email: junegunn.c@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files:
52
+ - LICENSE.txt
53
+ - README.rdoc
54
+ files:
55
+ - .document
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - LICENSE.txt
59
+ - README.rdoc
60
+ - Rakefile
61
+ - VERSION
62
+ - lib/each_sql.rb
63
+ - lib/each_sql/each_sql.rb
64
+ - test/helper.rb
65
+ - test/postgres.sql
66
+ - test/test_each_sql.rb
67
+ homepage: http://github.com/junegunn/each_sql
68
+ licenses:
69
+ - MIT
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ segments:
81
+ - 0
82
+ hash: -4303771573274782197
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.7.2
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Enumerate through each SQL statement in SQL scripts.
95
+ test_files: []