piggly 1.2.1 → 2.0.0

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.
Files changed (112) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +163 -0
  3. data/Rakefile +29 -15
  4. data/bin/piggly +4 -244
  5. data/lib/piggly.rb +19 -17
  6. data/lib/piggly/command.rb +9 -0
  7. data/lib/piggly/command/base.rb +148 -0
  8. data/lib/piggly/command/report.rb +162 -0
  9. data/lib/piggly/command/test.rb +157 -0
  10. data/lib/piggly/command/trace.rb +90 -0
  11. data/lib/piggly/command/untrace.rb +78 -0
  12. data/lib/piggly/compiler.rb +7 -5
  13. data/lib/piggly/compiler/cache_dir.rb +119 -0
  14. data/lib/piggly/compiler/coverage_report.rb +63 -0
  15. data/lib/piggly/compiler/trace_compiler.rb +105 -0
  16. data/lib/piggly/config.rb +47 -22
  17. data/lib/piggly/dumper.rb +9 -0
  18. data/lib/piggly/dumper/index.rb +121 -0
  19. data/lib/piggly/dumper/qualified_name.rb +36 -0
  20. data/lib/piggly/dumper/qualified_type.rb +81 -0
  21. data/lib/piggly/dumper/reified_procedure.rb +142 -0
  22. data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
  23. data/lib/piggly/installer.rb +84 -42
  24. data/lib/piggly/parser.rb +43 -49
  25. data/lib/piggly/parser/grammar.tt +289 -313
  26. data/lib/piggly/parser/nodes.rb +270 -211
  27. data/lib/piggly/parser/traversal.rb +35 -33
  28. data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
  29. data/lib/piggly/profile.rb +81 -60
  30. data/lib/piggly/reporter.rb +5 -18
  31. data/lib/piggly/reporter/base.rb +103 -0
  32. data/lib/piggly/reporter/html_dsl.rb +63 -0
  33. data/lib/piggly/reporter/index.rb +108 -0
  34. data/lib/piggly/reporter/procedure.rb +104 -0
  35. data/lib/piggly/reporter/resources/highlight.js +21 -0
  36. data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
  37. data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
  38. data/lib/piggly/tags.rb +280 -0
  39. data/lib/piggly/task.rb +191 -40
  40. data/lib/piggly/util.rb +8 -27
  41. data/lib/piggly/util/blankslate.rb +114 -0
  42. data/lib/piggly/util/cacheable.rb +19 -0
  43. data/lib/piggly/util/enumerable.rb +44 -0
  44. data/lib/piggly/util/file.rb +17 -0
  45. data/lib/piggly/util/process_queue.rb +96 -0
  46. data/lib/piggly/util/thunk.rb +39 -0
  47. data/lib/piggly/version.rb +8 -8
  48. data/spec/examples/compiler/cacheable_spec.rb +190 -0
  49. data/spec/examples/compiler/report_spec.rb +25 -0
  50. data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
  51. data/spec/examples/config_spec.rb +61 -0
  52. data/spec/examples/dumper/index_spec.rb +197 -0
  53. data/spec/examples/dumper/procedure_spec.rb +116 -0
  54. data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
  55. data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
  56. data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
  57. data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
  58. data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
  59. data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
  60. data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
  61. data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
  62. data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
  63. data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
  64. data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
  65. data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
  66. data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
  67. data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
  68. data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
  69. data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
  70. data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
  71. data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
  72. data/spec/examples/installer_spec.rb +59 -0
  73. data/spec/examples/parser/nodes_spec.rb +73 -0
  74. data/spec/examples/parser/traversal_spec.rb +14 -0
  75. data/spec/examples/parser_spec.rb +115 -0
  76. data/spec/examples/profile_spec.rb +153 -0
  77. data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
  78. data/spec/examples/reporter/html/index_spec.rb +0 -0
  79. data/spec/examples/reporter/html_spec.rb +1 -0
  80. data/spec/examples/reporter_spec.rb +0 -0
  81. data/spec/{compiler → examples}/tags_spec.rb +10 -10
  82. data/spec/examples/task_spec.rb +0 -0
  83. data/spec/examples/util/cacheable_spec.rb +41 -0
  84. data/spec/examples/util/enumerable_spec.rb +64 -0
  85. data/spec/examples/util/file_spec.rb +40 -0
  86. data/spec/examples/util/process_queue_spec.rb +16 -0
  87. data/spec/examples/util/thunk_spec.rb +58 -0
  88. data/spec/examples/version_spec.rb +0 -0
  89. data/spec/issues/007_spec.rb +25 -0
  90. data/spec/issues/008_spec.rb +73 -0
  91. data/spec/issues/018_spec.rb +25 -0
  92. data/spec/spec_helper.rb +253 -9
  93. metadata +136 -93
  94. data/README.markdown +0 -116
  95. data/lib/piggly/compiler/cache.rb +0 -151
  96. data/lib/piggly/compiler/pretty.rb +0 -67
  97. data/lib/piggly/compiler/queue.rb +0 -46
  98. data/lib/piggly/compiler/tags.rb +0 -244
  99. data/lib/piggly/compiler/trace.rb +0 -91
  100. data/lib/piggly/filecache.rb +0 -40
  101. data/lib/piggly/parser/parser.rb +0 -11794
  102. data/lib/piggly/reporter/html.rb +0 -207
  103. data/spec/compiler/cache_spec.rb +0 -9
  104. data/spec/compiler/pretty_spec.rb +0 -9
  105. data/spec/compiler/queue_spec.rb +0 -3
  106. data/spec/compiler/rewrite_spec.rb +0 -3
  107. data/spec/config_spec.rb +0 -58
  108. data/spec/filecache_spec.rb +0 -70
  109. data/spec/fixtures/snippets.sql +0 -158
  110. data/spec/grammar/tokens/lval_spec.rb +0 -50
  111. data/spec/parser_spec.rb +0 -8
  112. data/spec/profile_spec.rb +0 -5
@@ -1,207 +0,0 @@
1
- module Piggly
2
-
3
- #
4
- # Markup DSL
5
- #
6
- module HtmlTag
7
- unless defined? HTML_REPLACE
8
- HTML_REPLACE = { '&' => '&amp;', '"' => '&quot;', '>' => '&gt;', '<' => '&lt;' }
9
- HTML_PATTERN = /[&"<>]/
10
- end
11
-
12
- def html(output = '')
13
- begin
14
- @htmltag_output, htmltag_output = output, @htmltag_output
15
- # TODO: doctype
16
- yield
17
- ensure
18
- # restore
19
- @htmltag_output = htmltag_output
20
- end
21
- end
22
-
23
- def tag(name, content = nil, attributes = {})
24
- if content.is_a?(Hash) and attributes.empty?
25
- content, attributes = nil, content
26
- end
27
-
28
- attributes = attributes.inject('') do |string, pair|
29
- k, v = pair
30
- string << %[ #{k}="#{v}"]
31
- end
32
-
33
- if content.nil?
34
- if block_given?
35
- @htmltag_output << "<#{name}#{attributes}>"
36
- yield
37
- @htmltag_output << "</#{name}>"
38
- else
39
- @htmltag_output << "<#{name}#{attributes}/>"
40
- end
41
- else
42
- @htmltag_output << "<#{name}#{attributes}>#{content.to_s}</#{name}>"
43
- end
44
- end
45
-
46
- if ''.respond_to?(:fast_xs)
47
- def e(string)
48
- e.fast_xs
49
- end
50
- elsif ''.respond_to?(:to_xs)
51
- def e(string)
52
- e.to_xs
53
- end
54
- else
55
- def e(string)
56
- string.gsub(HTML_PATTERN) {|c| HTML_REPLACE[c] }
57
- end
58
- end
59
- end
60
-
61
- class HtmlReporter < Reporter
62
- extend HtmlTag
63
-
64
- def self.output(path, data, summary)
65
- File.open(report_path(path, '.html'), 'w') do |f|
66
- html(f) do
67
-
68
- tag :html, :xmlns => 'http://www.w3.org/1999/xhtml' do
69
- tag :head do
70
- tag :title, "Code Coverage: #{File.basename(path)}"
71
- tag :link, :rel => 'stylesheet', :type => 'text/css', :href => 'piggly.css'
72
- end
73
-
74
- tag :body do
75
- table(path)
76
-
77
- tag :br
78
- tag :div, :class => 'listing' do
79
- tag :table do
80
- tag :tr do
81
- tag :td, data.fetch('lines').to_a.map{|n| %[<a href="#L#{n}" id="L#{n}">#{n}</a>] }.join("\n"), :class => 'lines'
82
- tag :td, data.fetch('html'), :class => 'code'
83
- end
84
- end
85
- end
86
-
87
- toc(data.fetch('tags'))
88
- end
89
- end
90
-
91
- end
92
- end
93
- end
94
-
95
- def self.toc(tags)
96
- todo = tags.reject{|t| t.complete? }
97
-
98
- tag :div, :class => 'toc' do
99
- tag :a, 'Index', :href => 'index.html'
100
-
101
- unless todo.empty?
102
- tag :ol do
103
- todo.each do |t|
104
- tag(:li, :class => t.type) { tag :a, t.description, :href => "#T#{t.id}" }
105
- end
106
- end
107
- end
108
- end
109
- end
110
-
111
- def self.timestamp
112
- tag :div, "Generated by piggly #{Piggly::VERSION} at #{Time.now.strftime('%B %d, %Y %H:%M %Z')}", :class => 'timestamp'
113
- end
114
-
115
- def self.table(*files)
116
- tag :table, :class => 'summary sortable' do
117
- tag :tr do
118
- tag :th, 'File'
119
- tag :th, 'Blocks'
120
- tag :th, 'Loops'
121
- tag :th, 'Branches'
122
- tag :th, 'Block Coverage'
123
- tag :th, 'Loop Coverage'
124
- tag :th, 'Branch Coverage'
125
- end
126
-
127
- files.each_with_index do |name, index|
128
- summary = Profile.summary(name)
129
- row = index.modulo(2) == 0 ? 'even' : 'odd'
130
-
131
- tag :tr, :class => row do
132
- unless summary.include?(:block) or summary.include?(:loop) or summary.include?(:branch)
133
- # PigglyParser couldn't parse this file
134
- tag :td, File.basename(name), :class => 'file fail'
135
- tag(:td, :class => 'count') { tag :span, -1, :style => 'display:none' }
136
- tag(:td, :class => 'count') { tag :span, -1, :style => 'display:none' }
137
- tag(:td, :class => 'count') { tag :span, -1, :style => 'display:none' }
138
- tag(:td, :class => 'pct') { tag :span, -1, :style => 'display:none' }
139
- tag(:td, :class => 'pct') { tag :span, -1, :style => 'display:none' }
140
- tag(:td, :class => 'pct') { tag :span, -1, :style => 'display:none' }
141
- else
142
- tag(:td, :class => 'file') { tag :a, File.basename(name), :href => File.basename(name, '.*') + '.html' }
143
- tag :td, (summary[:block][:count] || 0), :class => 'count'
144
- tag :td, (summary[:loop][:count] || 0), :class => 'count'
145
- tag :td, (summary[:branch][:count] || 0), :class => 'count'
146
- tag(:td, :class => 'pct') { percent(summary[:block][:percent]) }
147
- tag(:td, :class => 'pct') { percent(summary[:loop][:percent]) }
148
- tag(:td, :class => 'pct') { percent(summary[:branch][:percent]) }
149
- end
150
- end
151
-
152
- end
153
- end
154
- end
155
-
156
- def self.percent(pct)
157
- if pct
158
- tag :table, :align => 'center' do
159
- tag :tr do
160
-
161
- tag :td, '%0.2f%%&nbsp;' % pct, :class => 'num'
162
- tag :td, :class => 'graph' do
163
- if pct
164
- tag :table, :align => 'right', :class => 'graph' do
165
- tag :tr do
166
- tag :td, :class => 'covered', :width => (pct/2.0).to_i
167
- tag :td, :class => 'uncovered', :width => ((100-pct)/2.0).to_i
168
- end
169
- end
170
- end
171
- end
172
-
173
- end
174
- end
175
- else
176
- tag :span, -1, :style => 'display:none'
177
- end
178
- end
179
-
180
- class Index < HtmlReporter
181
- extend HtmlTag
182
-
183
- def self.output(sources)
184
- File.open(File.join(report_path, 'index.html'), 'w') do |f|
185
- html(f) do
186
-
187
- tag :html do
188
- tag :head do
189
- tag :title, 'Piggly PL/pgSQL Code Coverage'
190
- tag :link, :rel => 'stylesheet', :type => 'text/css', :href => 'piggly.css'
191
- tag :script, '<!-- -->', :type => 'text/javascript', :src => 'sortable.js'
192
- end
193
-
194
- tag :body do
195
- table(*sources.sort)
196
- tag :br
197
- timestamp
198
- end
199
- end
200
-
201
- end
202
- end
203
- end
204
- end
205
-
206
- end
207
- end
@@ -1,9 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- module Piggly
4
-
5
- describe CompilerCache do
6
-
7
- end
8
-
9
- end
@@ -1,9 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
- module Piggly
4
-
5
- describe PrettyCompiler do
6
-
7
- end
8
-
9
- end
@@ -1,3 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
-
@@ -1,3 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
-
3
-
@@ -1,58 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- module Piggly
4
-
5
- describe Config do
6
- it "has class accessors and mutators" do
7
- Config.should respond_to(:cache_root)
8
- Config.should respond_to(:cache_root=)
9
- Config.should respond_to(:report_root)
10
- Config.should respond_to(:report_root=)
11
- Config.should respond_to(:trace_prefix)
12
- Config.should respond_to(:trace_prefix=)
13
- end
14
-
15
- it "has default values" do
16
- Config.cache_root = nil
17
- Config.cache_root.should_not be_nil
18
- Config.cache_root.should =~ /cache$/
19
-
20
- Config.report_root = nil
21
- Config.report_root.should_not be_nil
22
- Config.report_root.should =~ /reports$/
23
-
24
- Config.trace_prefix = nil
25
- Config.trace_prefix.should_not be_nil
26
- Config.trace_prefix.should == 'PIGGLY'
27
- end
28
-
29
- describe "path" do
30
- it "doesn't reparent absolute paths" do
31
- Config.path('/tmp', '/usr/bin/ps').should == '/usr/bin/ps'
32
- Config.path('A:/data/tmp', 'C:/USER/tmp').should == 'C:/USER/tmp'
33
- Config.path('/tmp/data', '../data.txt').should == '../data.txt'
34
- end
35
-
36
- it "reparents relative paths" do
37
- Config.path('/tmp', 'note.txt').should == '/tmp/note.txt'
38
- end
39
-
40
- it "doesn't require path parameter" do
41
- Config.path('/tmp').should == '/tmp'
42
- end
43
- end
44
-
45
- describe "mkpath" do
46
- it "creates root if doesn't exist" do
47
- FileUtils.stub!(:makedirs).and_return(true)
48
- FileUtils.should_receive(:makedirs).with('x/y').once
49
- Config.mkpath('x/y', 'z')
50
- end
51
-
52
- it "throws an error on path components that exist as files" do
53
- lambda { Config.mkpath('/etc/passwd/file') }.should raise_error(Errno::EEXIST)
54
- end
55
- end
56
- end
57
-
58
- end
@@ -1,70 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
-
3
- module Piggly
4
-
5
- describe File, "cache invalidation" do
6
- before do
7
- mtime = Hash['a' => 1, 'b' => 2, 'c' => 3]
8
- File.stub!(:mtime).and_return{|f| mtime.fetch(f) }
9
- File.stub!(:exists?).and_return{|f| mtime.include?(f) }
10
- end
11
-
12
- it "invalidates non-existant cache file" do
13
- File.stale?('d', 'a').should == true
14
- File.stale?('d', 'a', 'b').should == true
15
- end
16
-
17
- it "performs validation using file mtimes" do
18
- File.stale?('c', 'b').should_not be_true
19
- File.stale?('c', 'a').should_not be_true
20
- File.stale?('c', 'b', 'a').should_not be_true
21
- File.stale?('c', 'a', 'b').should_not be_true
22
-
23
- File.stale?('b', 'a').should_not be_true
24
- File.stale?('b', 'c').should be_true
25
- File.stale?('b', 'a', 'c').should be_true
26
- File.stale?('b', 'c', 'a').should be_true
27
-
28
- File.stale?('a', 'b').should be_true
29
- File.stale?('a', 'c').should be_true
30
- File.stale?('a', 'b', 'c').should be_true
31
- File.stale?('a', 'c', 'b').should be_true
32
- end
33
-
34
- it "assumes sources exist" do
35
- lambda{ File.stale?('a', 'd') }.should raise_error(StandardError)
36
- lambda{ File.stale?('c', 'a', 'x') }.should raise_error(StandardError)
37
- end
38
- end
39
-
40
- class ExampleClass; include FileCache; end
41
- class ExampleCacheClass; include FileCache; end
42
- class PigglyExampleClassHTML; include FileCache; end
43
- class PigglyExampleHTMLClass; include FileCache; end
44
- class HTMLPiggly; include FileCache; end
45
- class ExampleRedefined
46
- include FileCache
47
- def self.cache_path(file)
48
- 'redefined'
49
- end
50
- end
51
-
52
- describe FileCache do
53
- it "installs class methods" do
54
- ExampleClass.should respond_to(:cache_path)
55
- end
56
-
57
- it "uses class name as cache subdirectory" do
58
- Config.cache_root = '/'
59
- FileUtils.should_receive(:makedirs).at_least(:once)
60
-
61
- ExampleClass.cache_path('a.ext').should =~ %r(/Example/a.ext$)
62
- ExampleCacheClass.cache_path('a.ext').should =~ %r(/ExampleCache/a.ext$)
63
- PigglyExampleClassHTML.cache_path('a.ext').should =~ %r(/PigglyExampleClassHTML/a.ext$)
64
- PigglyExampleHTMLClass.cache_path('a.ext').should =~ %r(/PigglyExampleHTML/a.ext$)
65
- HTMLPiggly.cache_path('a.ext').should =~ %r(/HTML/a.ext$)
66
- ExampleRedefined.cache_path('a.ext').should == 'redefined'
67
- end
68
- end
69
-
70
- end
@@ -1,158 +0,0 @@
1
- CREATE OR REPLACE FUNCTION piggly_coverage_prog(a integer, b boolean) RETURNS void AS $$
2
- DECLARE
3
- x varchar(20);
4
- y integer[] := '{}';
5
- BEGIN
6
-
7
- -- IF-THEN
8
- IF v_user_id <> 0
9
- THEN
10
- UPDATE users SET email = v_email WHERE user_id = v_user_id;
11
- END IF;
12
-
13
- -- IF-THEN-ELSE
14
- IF parentid IS NULL OR parentid = ''
15
- THEN
16
- RETURN fullname;
17
- ELSE
18
- RETURN hp_true_filename(parentid) || '/' || fullname;
19
- END IF;
20
-
21
- -- IF-THEN-ELSE
22
- IF v_count > 0 THEN
23
- INSERT INTO users_count(count) VALUES (v_count);
24
- RETURN 't';
25
- ELSE
26
- RETURN 'f';
27
- END IF;
28
-
29
- -- IF-THEN-ELSIF
30
- IF number = 0 THEN
31
- result := 'zero';
32
- ELSIF number > 0 THEN
33
- result := 'positive';
34
- ELSIF number < 0 THEN
35
- result := 'negative';
36
- ELSE
37
- -- hmm, the only other possibility is that the number is null
38
- result := 'NULL';
39
- END IF;
40
-
41
- -- nest IF-THEN-ELSE statements
42
- IF demo_row.sex = 'm' THEN
43
- pretty_sex := 'man';
44
- ELSE
45
- IF demo_row.sex = 'f' THEN
46
- pretty_sex := 'woman';
47
- END IF;
48
- END IF;
49
-
50
- -- simple CASE with search-expression
51
- CASE x
52
- WHEN 1, 2 THEN
53
- msg := 'one or two';
54
- ELSE
55
- msg := 'other value than one or two';
56
- END CASE;
57
-
58
- -- searched CASE with boolean-expression
59
- CASE
60
- WHEN x BETWEEN 0 and 10 THEN
61
- msg := 'value is between zero and ten';
62
- WHEN x BETWEEN 11 and 20 THEN
63
- msg := 'value is between eleven and twenty';
64
- END CASE;
65
-
66
- << labelA >>
67
- LOOP
68
- a := a + 1;
69
- EXIT labelA WHEN a > 10;
70
- END LOOP labelA;
71
-
72
- LOOP
73
- b := b + 1
74
- EXIT WHEN b > 10;
75
- END LOOP;
76
-
77
- LOOP
78
- c := c + 1;
79
- IF c > 10 THEN
80
- EXIT;
81
- END IF;
82
- END LOOP;
83
-
84
- << labelB >>
85
- BEGIN
86
- -- some computations
87
- IF stocks > 100000 THEN
88
- EXIT labelB; -- causes exit from BEGIN block
89
- END IF;
90
- -- computations here will be skipped when stocks > 100000
91
- END;
92
-
93
- LOOP
94
- -- some computations
95
- EXIT WHEN count > 100;
96
- CONTINUE WHEN count < 50;
97
- -- some computations for count IN [50 .. 100]
98
- END LOOP;
99
-
100
- WHILE amount_owed > 0 AND gift_certificate_balance > 0
101
- LOOP
102
- -- some computations here
103
- a := 10;
104
- END LOOP;
105
-
106
- << labelC >>
107
- WHILE NOT done LOOP
108
- -- some computations here
109
- a := 10;
110
- END LOOP labelC;
111
-
112
- << labelD >>
113
- WHILE x NOT IN (1,2,3) LOOP
114
- CONTINUE labelD WHEN x < 10;
115
- END LOOP;
116
-
117
- FOR i IN 1..10 LOOP
118
- --
119
- END LOOP;
120
-
121
- << labelD >>
122
- FOR i IN REVERSE 10..1 LOOP
123
- --
124
- EXIT labelD WHEN i = 5;
125
- END LOOP labelD;
126
-
127
- << labelE >>
128
- FOR i IN REVERSE 10..1 BY 2 LOOP
129
- --
130
- CONTINUE labelE;
131
- END LOOP;
132
-
133
- FOR f IN SELECT *
134
- FROM foo
135
- WHERE id > 100
136
- LOOP
137
- -- can do some processing home
138
- RETURN NEXT f; -- return current row of SELECT
139
- END LOOP;
140
-
141
- FOR t IN EXECUTE 'SELECT * FROM foo' LOOP
142
- CONTINUE;
143
- END LOOP;
144
-
145
- BEGIN
146
- UPDATE tab SET fname = 'J' WHERE lname = 'J';
147
- x := x + 1;
148
- y := x / 0;
149
- EXCEPTION
150
- WHEN SQLSTATE '22012' THEN
151
- -- relax, don't do it
152
- WHEN division_by_zero OR unique_violation THEN
153
- RAISE NOTICE 'caught a fool';
154
- RETURN x;
155
- END;
156
-
157
- END $$
158
- LANGUAGE 'plpgsql' IMMUTABLE;