piggly 1.2.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +163 -0
- data/Rakefile +29 -15
- data/bin/piggly +4 -244
- data/lib/piggly.rb +19 -17
- data/lib/piggly/command.rb +9 -0
- data/lib/piggly/command/base.rb +148 -0
- data/lib/piggly/command/report.rb +162 -0
- data/lib/piggly/command/test.rb +157 -0
- data/lib/piggly/command/trace.rb +90 -0
- data/lib/piggly/command/untrace.rb +78 -0
- data/lib/piggly/compiler.rb +7 -5
- data/lib/piggly/compiler/cache_dir.rb +119 -0
- data/lib/piggly/compiler/coverage_report.rb +63 -0
- data/lib/piggly/compiler/trace_compiler.rb +105 -0
- data/lib/piggly/config.rb +47 -22
- data/lib/piggly/dumper.rb +9 -0
- data/lib/piggly/dumper/index.rb +121 -0
- data/lib/piggly/dumper/qualified_name.rb +36 -0
- data/lib/piggly/dumper/qualified_type.rb +81 -0
- data/lib/piggly/dumper/reified_procedure.rb +142 -0
- data/lib/piggly/dumper/skeleton_procedure.rb +102 -0
- data/lib/piggly/installer.rb +84 -42
- data/lib/piggly/parser.rb +43 -49
- data/lib/piggly/parser/grammar.tt +289 -313
- data/lib/piggly/parser/nodes.rb +270 -211
- data/lib/piggly/parser/traversal.rb +35 -33
- data/lib/piggly/parser/treetop_ruby19_patch.rb +1 -1
- data/lib/piggly/profile.rb +81 -60
- data/lib/piggly/reporter.rb +5 -18
- data/lib/piggly/reporter/base.rb +103 -0
- data/lib/piggly/reporter/html_dsl.rb +63 -0
- data/lib/piggly/reporter/index.rb +108 -0
- data/lib/piggly/reporter/procedure.rb +104 -0
- data/lib/piggly/reporter/resources/highlight.js +21 -0
- data/lib/piggly/reporter/{piggly.css → resources/piggly.css} +52 -12
- data/lib/piggly/reporter/{sortable.js → resources/sortable.js} +0 -0
- data/lib/piggly/tags.rb +280 -0
- data/lib/piggly/task.rb +191 -40
- data/lib/piggly/util.rb +8 -27
- data/lib/piggly/util/blankslate.rb +114 -0
- data/lib/piggly/util/cacheable.rb +19 -0
- data/lib/piggly/util/enumerable.rb +44 -0
- data/lib/piggly/util/file.rb +17 -0
- data/lib/piggly/util/process_queue.rb +96 -0
- data/lib/piggly/util/thunk.rb +39 -0
- data/lib/piggly/version.rb +8 -8
- data/spec/examples/compiler/cacheable_spec.rb +190 -0
- data/spec/examples/compiler/report_spec.rb +25 -0
- data/spec/{compiler → examples/compiler}/trace_spec.rb +7 -57
- data/spec/examples/config_spec.rb +61 -0
- data/spec/examples/dumper/index_spec.rb +197 -0
- data/spec/examples/dumper/procedure_spec.rb +116 -0
- data/spec/{grammar → examples/grammar}/expression_spec.rb +60 -60
- data/spec/{grammar → examples/grammar}/statements/assignment_spec.rb +15 -15
- data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
- data/spec/{grammar → examples/grammar}/statements/exception_spec.rb +10 -10
- data/spec/{grammar → examples/grammar}/statements/if_spec.rb +47 -34
- data/spec/{grammar → examples/grammar}/statements/loop_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/statements/sql_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/comment_spec.rb +11 -11
- data/spec/{grammar → examples/grammar}/tokens/datatype_spec.rb +14 -8
- data/spec/{grammar → examples/grammar}/tokens/identifier_spec.rb +26 -10
- data/spec/{grammar → examples/grammar}/tokens/keyword_spec.rb +5 -5
- data/spec/{grammar → examples/grammar}/tokens/label_spec.rb +7 -7
- data/spec/{grammar → examples/grammar}/tokens/literal_spec.rb +1 -1
- data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
- data/spec/{grammar → examples/grammar}/tokens/number_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/sqlkeywords_spec.rb +1 -1
- data/spec/{grammar → examples/grammar}/tokens/string_spec.rb +9 -9
- data/spec/{grammar → examples/grammar}/tokens/whitespace_spec.rb +1 -1
- data/spec/examples/installer_spec.rb +59 -0
- data/spec/examples/parser/nodes_spec.rb +73 -0
- data/spec/examples/parser/traversal_spec.rb +14 -0
- data/spec/examples/parser_spec.rb +115 -0
- data/spec/examples/profile_spec.rb +153 -0
- data/spec/{reporter/html_spec.rb → examples/reporter/html/dsl_spec.rb} +0 -0
- data/spec/examples/reporter/html/index_spec.rb +0 -0
- data/spec/examples/reporter/html_spec.rb +1 -0
- data/spec/examples/reporter_spec.rb +0 -0
- data/spec/{compiler → examples}/tags_spec.rb +10 -10
- data/spec/examples/task_spec.rb +0 -0
- data/spec/examples/util/cacheable_spec.rb +41 -0
- data/spec/examples/util/enumerable_spec.rb +64 -0
- data/spec/examples/util/file_spec.rb +40 -0
- data/spec/examples/util/process_queue_spec.rb +16 -0
- data/spec/examples/util/thunk_spec.rb +58 -0
- data/spec/examples/version_spec.rb +0 -0
- data/spec/issues/007_spec.rb +25 -0
- data/spec/issues/008_spec.rb +73 -0
- data/spec/issues/018_spec.rb +25 -0
- data/spec/spec_helper.rb +253 -9
- metadata +136 -93
- data/README.markdown +0 -116
- data/lib/piggly/compiler/cache.rb +0 -151
- data/lib/piggly/compiler/pretty.rb +0 -67
- data/lib/piggly/compiler/queue.rb +0 -46
- data/lib/piggly/compiler/tags.rb +0 -244
- data/lib/piggly/compiler/trace.rb +0 -91
- data/lib/piggly/filecache.rb +0 -40
- data/lib/piggly/parser/parser.rb +0 -11794
- data/lib/piggly/reporter/html.rb +0 -207
- data/spec/compiler/cache_spec.rb +0 -9
- data/spec/compiler/pretty_spec.rb +0 -9
- data/spec/compiler/queue_spec.rb +0 -3
- data/spec/compiler/rewrite_spec.rb +0 -3
- data/spec/config_spec.rb +0 -58
- data/spec/filecache_spec.rb +0 -70
- data/spec/fixtures/snippets.sql +0 -158
- data/spec/grammar/tokens/lval_spec.rb +0 -50
- data/spec/parser_spec.rb +0 -8
- data/spec/profile_spec.rb +0 -5
data/lib/piggly/reporter/html.rb
DELETED
@@ -1,207 +0,0 @@
|
|
1
|
-
module Piggly
|
2
|
-
|
3
|
-
#
|
4
|
-
# Markup DSL
|
5
|
-
#
|
6
|
-
module HtmlTag
|
7
|
-
unless defined? HTML_REPLACE
|
8
|
-
HTML_REPLACE = { '&' => '&', '"' => '"', '>' => '>', '<' => '<' }
|
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%% ' % 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
|
data/spec/compiler/cache_spec.rb
DELETED
data/spec/compiler/queue_spec.rb
DELETED
data/spec/config_spec.rb
DELETED
@@ -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
|
data/spec/filecache_spec.rb
DELETED
@@ -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
|
data/spec/fixtures/snippets.sql
DELETED
@@ -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;
|