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.
- 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;
|