piggly 1.2.1 → 2.0.0

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