globegit-postgresql-plruby 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/Changes +121 -0
  2. data/README.markdown +155 -0
  3. data/Rakefile +48 -0
  4. data/docs/plruby.rb +1931 -0
  5. data/ex_trans.sql +33 -0
  6. data/extconf.rb +267 -0
  7. data/plruby.html +1454 -0
  8. data/plruby.rd +1571 -0
  9. data/postgresql-plruby.gemspec +56 -0
  10. data/src/conversions.h +5 -0
  11. data/src/conversions/basic/conversions.h +25 -0
  12. data/src/conversions/basic/extconf.rb +8 -0
  13. data/src/conversions/basic/plruby_basic.c +357 -0
  14. data/src/conversions/bitstring/bitstring.sql +75 -0
  15. data/src/conversions/bitstring/conversions.h +15 -0
  16. data/src/conversions/bitstring/extconf.rb +8 -0
  17. data/src/conversions/bitstring/plruby_bitstring.c +579 -0
  18. data/src/conversions/convcommon.h +129 -0
  19. data/src/conversions/datetime/conversions.h +13 -0
  20. data/src/conversions/datetime/extconf.rb +8 -0
  21. data/src/conversions/datetime/plruby_datetime.c +269 -0
  22. data/src/conversions/geometry/conversions.h +37 -0
  23. data/src/conversions/geometry/extconf.rb +8 -0
  24. data/src/conversions/geometry/geometry.sql +196 -0
  25. data/src/conversions/geometry/plruby_geometry.c +2494 -0
  26. data/src/conversions/network/conversions.h +21 -0
  27. data/src/conversions/network/extconf.rb +8 -0
  28. data/src/conversions/network/network.sql +63 -0
  29. data/src/conversions/network/plruby_network.c +537 -0
  30. data/src/package.h +20 -0
  31. data/src/plpl.c +1708 -0
  32. data/src/plplan.c +893 -0
  33. data/src/plruby.c +1676 -0
  34. data/src/plruby.h +324 -0
  35. data/src/pltrans.c +388 -0
  36. data/test/conv_bitstring/b.rb +45 -0
  37. data/test/conv_bitstring/runtest +26 -0
  38. data/test/conv_bitstring/test.expected.73 +148 -0
  39. data/test/conv_bitstring/test.expected.74 +148 -0
  40. data/test/conv_bitstring/test.expected.80 +148 -0
  41. data/test/conv_bitstring/test.expected.81 +148 -0
  42. data/test/conv_bitstring/test.expected.82 +148 -0
  43. data/test/conv_bitstring/test.expected.83 +148 -0
  44. data/test/conv_bitstring/test.expected.84 +148 -0
  45. data/test/conv_bitstring/test.out +148 -0
  46. data/test/conv_bitstring/test_mklang.sql +8 -0
  47. data/test/conv_bitstring/test_queries.sql +63 -0
  48. data/test/conv_bitstring/test_queries.sql.in +63 -0
  49. data/test/conv_geometry/b.rb +45 -0
  50. data/test/conv_geometry/runtest +26 -0
  51. data/test/conv_geometry/test.expected.73 +265 -0
  52. data/test/conv_geometry/test.expected.74 +265 -0
  53. data/test/conv_geometry/test.expected.80 +265 -0
  54. data/test/conv_geometry/test.expected.81 +265 -0
  55. data/test/conv_geometry/test.expected.82 +265 -0
  56. data/test/conv_geometry/test.expected.83 +265 -0
  57. data/test/conv_geometry/test.expected.84 +265 -0
  58. data/test/conv_geometry/test.out +265 -0
  59. data/test/conv_geometry/test_mklang.sql +8 -0
  60. data/test/conv_geometry/test_queries.sql +194 -0
  61. data/test/conv_geometry/test_queries.sql.in +194 -0
  62. data/test/conv_network/b.rb +45 -0
  63. data/test/conv_network/runtest +26 -0
  64. data/test/conv_network/test.expected.73 +213 -0
  65. data/test/conv_network/test.expected.74 +237 -0
  66. data/test/conv_network/test.expected.80 +237 -0
  67. data/test/conv_network/test.expected.81 +237 -0
  68. data/test/conv_network/test.expected.82 +237 -0
  69. data/test/conv_network/test.expected.83 +237 -0
  70. data/test/conv_network/test.expected.84 +237 -0
  71. data/test/conv_network/test.out +237 -0
  72. data/test/conv_network/test_mklang.sql +8 -0
  73. data/test/conv_network/test_queries.sql +60 -0
  74. data/test/conv_network/test_queries.sql.in +60 -0
  75. data/test/plp/b.rb +34 -0
  76. data/test/plp/runtest +29 -0
  77. data/test/plp/test.expected.73 +472 -0
  78. data/test/plp/test.expected.74 +472 -0
  79. data/test/plp/test.expected.75 +472 -0
  80. data/test/plp/test.expected.80 +472 -0
  81. data/test/plp/test.expected.81 +472 -0
  82. data/test/plp/test.expected.82 +472 -0
  83. data/test/plp/test.expected.83 +472 -0
  84. data/test/plp/test.expected.84 +472 -0
  85. data/test/plp/test.out +472 -0
  86. data/test/plp/test_mklang.sql +8 -0
  87. data/test/plp/test_queries.sql +273 -0
  88. data/test/plp/test_setup.sql +931 -0
  89. data/test/plp/test_setup.sql.in +931 -0
  90. data/test/plt/b.rb +34 -0
  91. data/test/plt/runtest +29 -0
  92. data/test/plt/test.expected.73 +178 -0
  93. data/test/plt/test.expected.74 +178 -0
  94. data/test/plt/test.expected.75 +178 -0
  95. data/test/plt/test.expected.80 +178 -0
  96. data/test/plt/test.expected.81 +178 -0
  97. data/test/plt/test.expected.82 +178 -0
  98. data/test/plt/test.expected.83 +164 -0
  99. data/test/plt/test.expected.84 +168 -0
  100. data/test/plt/test.out +168 -0
  101. data/test/plt/test_mklang.sql +8 -0
  102. data/test/plt/test_queries.sql +72 -0
  103. data/test/plt/test_setup.sql +252 -0
  104. data/test/plt/test_setup.sql.in +252 -0
  105. data/test/range/b.rb +45 -0
  106. data/test/range/runtest +26 -0
  107. data/test/range/test.expected.73 +396 -0
  108. data/test/range/test.expected.73.in +396 -0
  109. data/test/range/test.expected.74 +396 -0
  110. data/test/range/test.expected.74.in +396 -0
  111. data/test/range/test.expected.75 +396 -0
  112. data/test/range/test.expected.75.in +396 -0
  113. data/test/range/test.expected.80 +396 -0
  114. data/test/range/test.expected.81 +397 -0
  115. data/test/range/test.expected.82 +397 -0
  116. data/test/range/test.expected.83 +397 -0
  117. data/test/range/test.expected.84 +399 -0
  118. data/test/range/test.out +399 -0
  119. data/test/range/test_mklang.sql +8 -0
  120. data/test/range/test_queries.sql +249 -0
  121. data/test/range/test_queries.sql.in +249 -0
  122. metadata +207 -0
@@ -0,0 +1,33 @@
1
+ create table tu (a int, b int);
2
+
3
+ create or replace function uu(abort bool) returns bool as '
4
+ transaction do |txn|
5
+ PL.exec("insert into tu values (1, 2)")
6
+ transaction do |txn1|
7
+ PL.exec("insert into tu values (3, 4)")
8
+ txn1.abort
9
+ end
10
+ PL.exec("insert into tu values (5, 6)")
11
+ txn.abort if abort
12
+ end
13
+ abort
14
+ ' language 'plruby';
15
+
16
+
17
+ create or replace function uu() returns bool as '
18
+ transaction do |txn1|
19
+ PL.exec("insert into tu values (3, 4)")
20
+ txn1.abort
21
+ end
22
+ true
23
+ ' language 'plruby';
24
+
25
+ create or replace function tt(abort bool) returns bool as '
26
+ transaction do |txn|
27
+ PL.exec("insert into tu values (1, 2)")
28
+ PL.exec("select uu()")
29
+ PL.exec("insert into tu values (5, 6)")
30
+ txn.abort if abort
31
+ end
32
+ abort
33
+ ' language 'plruby';
@@ -0,0 +1,267 @@
1
+ #!/usr/bin/ruby
2
+ ARGV.collect! {|x|
3
+ x = x.sub(/\A--((?:en|dis)able)-shared\z/) { "--#$1-plruby-shared" }
4
+ }
5
+
6
+ orig_argv = ARGV.dup
7
+
8
+ require 'mkmf'
9
+
10
+ class AX
11
+ def marshal_dump
12
+ "abc"
13
+ end
14
+ end
15
+
16
+ def check_autoload(safe = 12)
17
+ File.open("a.rb", "w") {|f| f.puts "class A; end" }
18
+ autoload :A, "a.rb"
19
+ Thread.new do
20
+ begin
21
+ $SAFE = safe
22
+ A.new
23
+ rescue Exception
24
+ false
25
+ end
26
+ end.value
27
+ ensure
28
+ File.unlink("a.rb")
29
+ end
30
+
31
+ def check_md
32
+ Marshal.load(Marshal.dump(AX.new))
33
+ false
34
+ rescue
35
+ true
36
+ end
37
+
38
+ def create_lang(version = 74, suffix = '', safe = 0)
39
+ language, opaque = 'C', 'language_handler'
40
+ opaque = "opaque" if version == 72
41
+ safe = safe.to_i
42
+ trusted = if safe >= 4
43
+ "trusted"
44
+ else
45
+ ""
46
+ end
47
+ puts <<-EOT
48
+
49
+ ========================================================================
50
+ After the installation use *something like this* to create the language
51
+ plruby#{suffix}
52
+
53
+
54
+ create function plruby#{suffix}_call_handler() returns #{opaque}
55
+ as '#{Config::CONFIG["sitearchdir"]}/plruby#{suffix}.#{CONFIG["DLEXT"]}'
56
+ language '#{language}';
57
+
58
+ create #{trusted} language 'plruby#{suffix}'
59
+ handler plruby#{suffix}_call_handler
60
+ lancompiler 'PL/Ruby#{suffix}';
61
+
62
+ ========================================================================
63
+ EOT
64
+ end
65
+
66
+ def rule(target, clean = nil)
67
+ wr = "#{target}:
68
+ \t@for subdir in $(SUBDIRS); do \\
69
+ \t\t(cd $${subdir} && $(MAKE) #{target}); \\
70
+ \tdone;
71
+ "
72
+ if clean != nil
73
+ wr << "\t@-rm tmp/* tests/tmp/* 2> /dev/null\n"
74
+ wr << "\t@rm Makefile\n" if clean
75
+ end
76
+ wr
77
+ end
78
+
79
+
80
+ include_dir, = dir_config("pgsql")
81
+ if include_dir
82
+ raise "--with-pgsql-include/--with-pgsql-dir is obsolete. Use --with-pg-config instead only if necessary."
83
+ end
84
+
85
+ pg_config = with_config('pg-config', 'pg_config')
86
+ include_dir = `#{pg_config} --includedir`.strip
87
+ $CFLAGS << " -I" << include_dir
88
+ $CFLAGS << " -I" << `#{pg_config} --includedir-server`.strip
89
+
90
+ if safe = with_config("safe-level")
91
+ safe = Integer(safe)
92
+ if safe < 0
93
+ raise "invalid value for safe #{safe}"
94
+ end
95
+ $CFLAGS += " -DSAFE_LEVEL=#{safe}"
96
+ else
97
+ safe = 12
98
+ end
99
+
100
+ if with_config("greenplum")
101
+ $CFLAGS += " -I" << File.join( include_dir, "postgresql", "internal" )
102
+ $CFLAGS += " -DWITH_GREENPLUM=1"
103
+ end
104
+
105
+ if timeout = with_config("timeout")
106
+ timeout = Integer(timeout)
107
+ if timeout < 2
108
+ raise "Invalid value for timeout #{timeout}"
109
+ end
110
+ $CFLAGS += " -DPLRUBY_TIMEOUT=#{timeout}"
111
+ if mainsafe = with_config("main-safe-level")
112
+ $CFLAGS += " -DMAIN_SAFE_LEVEL=#{mainsafe}"
113
+ end
114
+ end
115
+
116
+ if ! have_header("catalog/pg_proc.h")
117
+ raise "Some include file are missing (see README for the installation)"
118
+ end
119
+
120
+ if have_func("rb_hash_delete", "ruby.h")
121
+ $CFLAGS += " -DHAVE_RB_HASH_DELETE"
122
+ end
123
+
124
+ case version_str = `#{pg_config} --version`
125
+ when /^PostgreSQL ([7-9])\.([0-9])(\.[0-9]+)?$/
126
+ version = 10 * $1.to_i + $2.to_i
127
+ else
128
+ version = 0
129
+ end
130
+ if version < 73
131
+ raise <<-EOT
132
+
133
+ ============================================================
134
+ #{version_str} is unsupported. Try plruby-0.4.2.
135
+ ============================================================
136
+ EOT
137
+ end
138
+
139
+ if "aa".respond_to?(:initialize_copy, true)
140
+ $CFLAGS += " -DHAVE_RB_INITIALIZE_COPY"
141
+ end
142
+
143
+ have_func("rb_block_call")
144
+ have_header("ruby/st.h")
145
+ have_header("st.h")
146
+
147
+ if version >= 74
148
+ if !have_header("server/utils/array.h")
149
+ if !have_header("utils/array.h")
150
+ raise "I cant't find server/utils/array.h"
151
+ end
152
+ $CFLAGS += " -DPG_UTILS_ARRAY"
153
+ end
154
+ end
155
+
156
+ if macro_defined?("PG_TRY", %Q{#include "c.h"\n#include "utils/elog.h"})
157
+ $CFLAGS += " -DPG_PL_TRYCATCH"
158
+ end
159
+
160
+ have_library('pq', 'PQconnectdb')
161
+
162
+ enable_conversion = false
163
+ if enable_conversion = enable_config("conversion", true)
164
+ $CFLAGS += " -DPLRUBY_ENABLE_CONVERSION"
165
+ if check_autoload(safe.to_i)
166
+ $CFLAGS += " -DRUBY_CAN_USE_AUTOLOAD"
167
+ end
168
+ if check_md
169
+ $CFLAGS += " -DRUBY_CAN_USE_MARSHAL_DUMP"
170
+ end
171
+ end
172
+
173
+ conversions = {}
174
+ subdirs = []
175
+
176
+ if enable_conversion
177
+ Dir.foreach("src/conversions") do |dir|
178
+ next if dir[0] == ?. || !File.directory?("src/conversions/" + dir)
179
+ conversions[dir] = true
180
+ end
181
+ if !conversions.empty?
182
+ File.open("src/conversions.h", "w") do |conv|
183
+ conversions.sort.each do |key, val|
184
+ conv.puts "#include \"conversions/#{key}/conversions.h\""
185
+ subdirs << "src/conversions/#{key}"
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ $CFLAGS += " -DPG_PL_VERSION=#{version}"
192
+
193
+ suffix = with_config('suffix').to_s
194
+ $CFLAGS += " -DPLRUBY_CALL_HANDLER=plruby#{suffix}_call_handler"
195
+ $CFLAGS += " -DPLRUBY_VALIDATOR=plruby#{suffix}_validator"
196
+
197
+ subdirs.each do |key|
198
+ orig_argv << "--with-cflags='#$CFLAGS -I.. -I ../..'"
199
+ orig_argv << "--with-ldflags='#$LDFLAGS'"
200
+ orig_argv << "--with-cppflags='#$CPPFLAGS'"
201
+ cmd = "#{CONFIG['RUBY_INSTALL_NAME']} extconf.rb #{orig_argv.join(' ')}"
202
+ system("cd #{key}; #{cmd}")
203
+ end
204
+
205
+ subdirs.unshift("src")
206
+
207
+ begin
208
+ Dir.chdir("src")
209
+ if CONFIG["ENABLE_SHARED"] == "no"
210
+ libs = if CONFIG.key?("LIBRUBYARG_STATIC")
211
+ Config::expand(CONFIG["LIBRUBYARG_STATIC"].dup).sub(/^-l/, '')
212
+ else
213
+ Config::expand(CONFIG["LIBRUBYARG"].dup).sub(/lib([^.]*).*/, '\\1')
214
+ end
215
+ find_library(libs, "ruby_init", Config::expand(CONFIG["archdir"].dup))
216
+ end
217
+ $objs = ["plruby.o", "plplan.o", "plpl.o", "pltrans.o"] unless $objs
218
+ create_makefile("plruby#{suffix}")
219
+ ensure
220
+ Dir.chdir("..")
221
+ end
222
+
223
+ make = open("Makefile", "w")
224
+ make.print <<-EOF
225
+ SUBDIRS = #{subdirs.join(' ')}
226
+
227
+ #{rule('all')}
228
+ #{rule('clean', false)}
229
+ #{rule('distclean', true)}
230
+ #{rule('realclean', true)}
231
+ #{rule('install')}
232
+ #{rule('site-install')}
233
+
234
+ %.html: %.rd
235
+ \trd2 $< > ${<:%.rd=%.html}
236
+
237
+ plruby.html: plruby.rd
238
+
239
+ rd2: html
240
+
241
+ html: plruby.html
242
+
243
+ rdoc: docs/doc/index.html
244
+
245
+ docs/doc/index.html: $(RDOC)
246
+ \t@-(cd docs; rdoc plruby.rb)
247
+
248
+ ri:
249
+ \t@-(cd docs; rdoc -r plruby.rb)
250
+
251
+ ri-site:
252
+ \t@-(cd docs; rdoc -R plruby.rb)
253
+
254
+ test: src/$(DLLIB)
255
+ EOF
256
+ regexp = %r{\Atest/conv_(.*)}
257
+ Dir["test/*"].each do |dir|
258
+ if regexp =~ dir
259
+ next unless subdirs.include?("src/conversions/#{$1}")
260
+ end
261
+ make.puts "\t-(cd #{dir} ; RUBY='#{$ruby}' sh ./runtest #{version} #{suffix})"
262
+ end
263
+
264
+ make.close
265
+
266
+ create_lang(version, suffix, safe)
267
+
@@ -0,0 +1,1454 @@
1
+ <?xml version="1.0" ?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml">
6
+ <head>
7
+ <title>Untitled</title>
8
+ </head>
9
+ <body>
10
+ <h1><a name="label-0" id="label-0">PL/Ruby</a></h1><!-- RDLabel: "PL/Ruby" -->
11
+ <ul>
12
+ <li><a href="#label-2">Defining function in PL Ruby</a></li>
13
+ <li><a href="#label-5">Function returning SET (SFRM Materialize)</a></li>
14
+ <li><a href="#label-6">Function returning SET (ExprMultiResult)</a></li>
15
+ <li><a href="#label-7">Trigger procedures in PL Ruby</a></li>
16
+ <li><a href="#label-19">plruby_singleton_methods</a></li>
17
+ <li><a href="#label-20">Conversion</a></li>
18
+ <li><a href="#label-21">Class and modules</a>
19
+ <ul>
20
+ <li><a href="#label-26">module PL</a> : general module</li>
21
+ <li><a href="#label-45">class PL::Plan</a> : class for prepared plans</li>
22
+ <li><a href="#label-58">class PL::Cursor</a> : class for cursors</li>
23
+ <li><a href="#label-66">class PL::Transaction</a> : class for transactions (8.0)</li>
24
+ <li><a href="#label-69">class BitString</a></li>
25
+ <li><a href="#label-117">class Tinterval</a></li>
26
+ <li><a href="#label-91">class NetAddr</a></li>
27
+ <li><a href="#label-111">class MacAddr</a></li>
28
+ <li><a href="#label-125">class Box</a></li>
29
+ <li><a href="#label-230">class Circle</a></li>
30
+ <li><a href="#label-157">class Path</a></li>
31
+ <li><a href="#label-173">class Point</a></li>
32
+ <li><a href="#label-211">class Polygon</a></li>
33
+ <li><a href="#label-196">class Segment</a></li>
34
+ </ul></li>
35
+ </ul>
36
+ <p>PL/Ruby is a loadable procedural language for the Postgres database
37
+ system that enable the Ruby language to create functions and trigger
38
+ procedures</p>
39
+ <p>Functions and triggers are singleton methods of the module PLtemp.</p>
40
+ <h1><a name="label-1" id="label-1">WARNING</a></h1><!-- RDLabel: "WARNING" -->
41
+ <p><em>if PL/Ruby was compiled with <kbd>--disable-conversion</kbd>,
42
+ all arguments (to the function or the triggers) are passed as string
43
+ values, except for NULL values represented by <kbd>Qnil</kbd>.</em>
44
+ <em>In this case you must explicitely call a conversion function (like to_i)
45
+ if you want to use an argument as an integer</em></p>
46
+ <h2><a name="label-2" id="label-2">Defining function in PL Ruby</a></h2><!-- RDLabel: "Defining function in PL Ruby" -->
47
+ <p>To create a function in the PL/Ruby language use the syntax</p>
48
+ <pre>CREATE FUNCTION funcname(arguments_type) RETURNS type AS '
49
+
50
+ # PL/Ruby function body
51
+
52
+ ' LANGUAGE 'plruby';</pre>
53
+ <p>when calling the function in a query, the arguments are given <em>as
54
+ string values</em> in the array <kbd>args</kbd>. To create a little max
55
+ function returning the higher of two int4 values write :</p>
56
+ <pre>CREATE FUNCTION ruby_max(int4, int4) RETURNS int4 AS '
57
+ if args[0].to_i &gt; args[1].to_i
58
+ return args[0]
59
+ else
60
+ return args[1]
61
+ end
62
+ ' LANGUAGE 'plruby';</pre>
63
+ <p>Tuple arguments are given as hash. Here is an example that defines
64
+ the overpaid_2 function (as found in the older Postgres documentation)
65
+ in PL/Ruby.</p>
66
+ <pre>CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS '
67
+ args[0]["salary"].to_f &gt; 200000 ||
68
+ (args[0]["salary"].to_f &gt; 100000 &amp;&amp; args[0]["age"].to_i &lt; 30)
69
+ ' LANGUAGE 'plruby';</pre>
70
+ <h3><a name="label-3" id="label-3">Warning : with PostgreSQL &gt;= 7.4 "array" are given as a ruby Array</a></h3><!-- RDLabel: "Warning : with PostgreSQL >= 7.4 "array" are given as a ruby Array" -->
71
+ <p>For example to define a function (int4[], int4) and return int4[],
72
+ in version &lt; 7.4 you write</p>
73
+ <pre>CREATE FUNCTION ruby_int4_accum(_int4, int4) RETURNS _int4 AS '
74
+ if /\\{(\\d+),(\\d+)\\}/ =~ args[0]
75
+ a, b = $1, $2
76
+ newsum = a.to_i + args[1].to_i
77
+ newcnt = b.to_i + 1
78
+ else
79
+ raise "unexpected value #{args[0]}"
80
+ end
81
+ "{#{newsum},#{newcnt}}"
82
+ ' LANGUAGE 'plruby';</pre>
83
+ <p>This must now (&gt;= 7.4) be written</p>
84
+ <pre>CREATE FUNCTION ruby_int4_accum(_int4, int4) RETURNS _int4 AS '
85
+ a = args[0]
86
+ [a[0].to_i + args[1].to_i, a[1].to_i + 1]
87
+ ' LANGUAGE 'plruby';</pre>
88
+ <h3><a name="label-4" id="label-4">Release PostgreSQL 8.0</a></h3><!-- RDLabel: "Release PostgreSQL 8.0" -->
89
+ <p>With this version, plruby can have named arguments and the previous functions
90
+ can be written</p>
91
+ <pre>CREATE FUNCTION ruby_max(a int4, b int4) RETURNS int4 AS '
92
+ if a &gt; b
93
+ a
94
+ else
95
+ b
96
+ end
97
+ ' LANGUAGE 'plruby';
98
+
99
+
100
+ CREATE FUNCTION overpaid_2 (emp EMP) RETURNS bool AS '
101
+ emp["salary"] &gt; 200000 ||
102
+ (emp["salary"] &gt; 100000 &amp;&amp; emp["age"] &lt; 30)
103
+ ' LANGUAGE 'plruby';</pre>
104
+ <p>With this version, you can also use transaction. For example</p>
105
+ <pre>plruby_test=# create table tu (a int, b int);
106
+ CREATE TABLE
107
+ plruby_test=# create or replace function tt(abort bool) returns bool as '
108
+ plruby_test'# transaction do |txn|
109
+ plruby_test'# PL.exec("insert into tu values (1, 2)")
110
+ plruby_test'# transaction do |txn1|
111
+ plruby_test'# PL.exec("insert into tu values (3, 4)")
112
+ plruby_test'# txn1.abort
113
+ plruby_test'# end
114
+ plruby_test'# PL.exec("insert into tu values (5, 6)")
115
+ plruby_test'# txn.abort if abort
116
+ plruby_test'# end
117
+ plruby_test'# abort
118
+ plruby_test'# ' language 'plruby';
119
+ CREATE FUNCTION
120
+ plruby_test=#
121
+ plruby_test=# select tt(true);
122
+ tt
123
+ ----
124
+ t
125
+ (1 row)
126
+
127
+ plruby_test=# select * from tu;
128
+ a | b
129
+ ---+---
130
+ (0 rows)
131
+
132
+ plruby_test=# select tt(false);
133
+ tt
134
+ ----
135
+ f
136
+ (1 row)
137
+
138
+ plruby_test=# select * from tu;
139
+ a | b
140
+ ---+---
141
+ 1 | 2
142
+ 5 | 6
143
+ (2 rows)
144
+
145
+ plruby_test=# </pre>
146
+ <h2><a name="label-5" id="label-5">Function returning SET (SFRM Materialize)</a></h2><!-- RDLabel: "Function returning SET (SFRM Materialize)" -->
147
+ <p>The return type must be declared as SETOF</p>
148
+ <p>The function must call <kbd>yield</kbd> to return rows or return a String which
149
+ must be a valid SELECT statement</p>
150
+ <p>For example to concatenate 2 rows create the function</p>
151
+ <pre>plruby_test=# CREATE FUNCTION tu(varchar) RETURNS setof record
152
+ plruby_test-# AS '
153
+ plruby_test'# size = PL.column_name(args[0]).size
154
+ plruby_test'# res = nil
155
+ plruby_test'# PL::Plan.new("select * from #{args[0]}",
156
+ plruby_test'# "block" =&gt; 50).each do |row|
157
+ plruby_test'# if res.nil?
158
+ plruby_test'# res = row.values
159
+ plruby_test'# else
160
+ plruby_test'# res.concat row.values
161
+ plruby_test'# yield res
162
+ plruby_test'# res = nil
163
+ plruby_test'# end
164
+ plruby_test'# end
165
+ plruby_test'# if res
166
+ plruby_test'# res.concat Array.new(size)
167
+ plruby_test'# yield res
168
+ plruby_test'# end
169
+ plruby_test'# ' language 'plruby';
170
+ CREATE FUNCTION
171
+ plruby_test=#
172
+ plruby_test=# select * from tt;
173
+ a | b
174
+ ---+----
175
+ 1 | 2
176
+ 3 | 4
177
+ 5 | 6
178
+ 7 | 8
179
+ 9 | 10
180
+ (5 rows)
181
+
182
+ plruby_test=# select * from tu('tt') as tbl(a int, b int, c int, d int);
183
+ a | b | c | d
184
+ ---+----+---+---
185
+ 1 | 2 | 3 | 4
186
+ 5 | 6 | 7 | 8
187
+ 9 | 10 | |
188
+ (3 rows)
189
+
190
+ plruby_test=# </pre>
191
+ <h2><a name="label-6" id="label-6">Function returning SET (ExprMultiResult)</a></h2><!-- RDLabel: "Function returning SET (ExprMultiResult)" -->
192
+ <p>The return type must be declared as SETOF</p>
193
+ <p>The function is called until it returns nil</p>
194
+ <p>The method PL#context and PL#context= give the possibility to store information
195
+ between the call</p>
196
+ <p>For example</p>
197
+ <pre>plruby_test=# create or replace function vv(int) returns setof int as '
198
+ plruby_test'# i = PL.context || 0
199
+ plruby_test'# if i &gt;= args[0].to_i
200
+ plruby_test'# nil
201
+ plruby_test'# else
202
+ plruby_test'# PL.context = i + 1
203
+ plruby_test'# end
204
+ plruby_test'# ' language plruby;
205
+ CREATE FUNCTION
206
+ plruby_test=#
207
+ plruby_test=# select * from uu;
208
+ b
209
+ ---
210
+ 2
211
+ (1 row)
212
+
213
+ plruby_test=#
214
+ plruby_test=# select *,vv(3) from uu;
215
+ b | vv
216
+ ---+----
217
+ 2 | 1
218
+ 2 | 2
219
+ 2 | 3
220
+ (3 rows)
221
+
222
+ plruby_test=# </pre>
223
+ <h2><a name="label-7" id="label-7">Trigger procedures in PL Ruby</a></h2><!-- RDLabel: "Trigger procedures in PL Ruby" -->
224
+ <p>Trigger procedures are defined in Postgres as functions without
225
+ arguments and a return type of trigger. In PL/Ruby the procedure is
226
+ called with 4 arguments :</p>
227
+ <dl>
228
+ <dt><a name="label-8" id="label-8">new (hash, tainted)</a></dt><!-- RDLabel: "new (hash, tainted)" -->
229
+ <dd>
230
+ an hash containing the values of the new table row on INSERT/UPDATE
231
+ actions, or empty on DELETE.
232
+ </dd>
233
+ <dt><a name="label-9" id="label-9">old (hash, tainted)</a></dt><!-- RDLabel: "old (hash, tainted)" -->
234
+ <dd>
235
+ an hash containing the values of the old table row on UPDATE/DELETE
236
+ actions, or empty on INSERT
237
+ </dd>
238
+ <dt><a name="label-10" id="label-10">args (array, tainted, frozen)</a></dt><!-- RDLabel: "args (array, tainted, frozen)" -->
239
+ <dd>
240
+ An array of the arguments to the procedure as given in the CREATE
241
+ TRIGGER statement
242
+ </dd>
243
+ <dt><a name="label-11" id="label-11">tg (hash, tainted, frozen)</a></dt><!-- RDLabel: "tg (hash, tainted, frozen)" -->
244
+ <dd>
245
+ The following keys are defined
246
+ <dl>
247
+ <dt><a name="label-12" id="label-12">name</a></dt><!-- RDLabel: "name" -->
248
+ <dd>
249
+ The name of the trigger from the CREATE TRIGGER statement.
250
+ </dd>
251
+ <dt><a name="label-13" id="label-13">relname</a></dt><!-- RDLabel: "relname" -->
252
+ <dd>
253
+ The name of the relation who has fired the trigger
254
+ </dd>
255
+ <dt><a name="label-14" id="label-14">relid</a></dt><!-- RDLabel: "relid" -->
256
+ <dd>
257
+ The object ID of the table that caused the trigger procedure to be invoked.
258
+ </dd>
259
+ <dt><a name="label-15" id="label-15">relatts</a></dt><!-- RDLabel: "relatts" -->
260
+ <dd>
261
+ An array containing the name of the tables field.
262
+ </dd>
263
+ <dt><a name="label-16" id="label-16">when</a></dt><!-- RDLabel: "when" -->
264
+ <dd>
265
+ The constant <kbd>PL::BEFORE</kbd>, <kbd>PL::AFTER</kbd> or
266
+ <kbd>PL::UNKNOWN</kbd> depending on the event of the trigger call.
267
+ </dd>
268
+ <dt><a name="label-17" id="label-17">level</a></dt><!-- RDLabel: "level" -->
269
+ <dd>
270
+ The constant <kbd>PL::ROW</kbd> or <kbd>PL::STATEMENT</kbd>
271
+ depending on the event of the trigger call.
272
+ </dd>
273
+ <dt><a name="label-18" id="label-18">op</a></dt><!-- RDLabel: "op" -->
274
+ <dd>
275
+ The constant <kbd>PL::INSERT</kbd>, <kbd>PL::UPDATE</kbd> or
276
+ <kbd>PL::DELETE</kbd> depending on the event of the trigger call.
277
+ </dd>
278
+ </dl>
279
+ </dd>
280
+ </dl>
281
+ <p>The return value from a trigger procedure is one of the constant
282
+ <kbd>PL::OK</kbd> or <kbd>PL::SKIP</kbd>, or an hash. If the
283
+ return value is <kbd>PL::OK</kbd>, the normal operation
284
+ (INSERT/UPDATE/DELETE) that fired this trigger will take
285
+ place. Obviously, <kbd>PL::SKIP</kbd> tells the trigger manager to
286
+ silently suppress the operation. The hash tells
287
+ PL/Ruby to return a modified row to the trigger manager that will be
288
+ inserted instead of the one given in <kbd>new</kbd> (INSERT/UPDATE
289
+ only). Needless to say that all this is only meaningful when the
290
+ trigger is BEFORE and FOR EACH ROW.</p>
291
+ <p>Here's a little example trigger procedure that forces an integer
292
+ value in a table to keep track of the # of updates that are performed
293
+ on the row. For new row's inserted, the value is initialized to 0 and
294
+ then incremented on every update operation :</p>
295
+ <pre>CREATE FUNCTION trigfunc_modcount() RETURNS TRIGGER AS '
296
+ case tg["op"]
297
+ when PL::INSERT
298
+ new[args[0]] = 0
299
+ when PL::UPDATE
300
+ new[args[0]] = old[args[0]].to_i + 1
301
+ else
302
+ return PL::OK
303
+ end
304
+ new
305
+ ' LANGUAGE 'plruby';
306
+
307
+ CREATE TABLE mytab (num int4, modcnt int4, descr text);
308
+
309
+ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
310
+ FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt');</pre>
311
+ <p>A more complex example (extract from test_setup.sql in the distribution)
312
+ which use the global variable <kbd>$Plans</kbd> to store a prepared
313
+ plan</p>
314
+ <pre>create function trig_pkey2_after() returns trigger as '
315
+ if ! $Plans.key?("plan_dta2_upd")
316
+ $Plans["plan_dta2_upd"] =
317
+ PL::Plan.new("update T_dta2
318
+ set ref1 = $3, ref2 = $4
319
+ where ref1 = $1 and ref2 = $2",
320
+ ["int4", "varchar", "int4", "varchar" ]).save
321
+ $Plans["plan_dta2_del"] =
322
+ PL::Plan.new("delete from T_dta2
323
+ where ref1 = $1 and ref2 = $2",
324
+ ["int4", "varchar"]).save
325
+ end
326
+
327
+ old_ref_follow = false
328
+ old_ref_delete = false
329
+
330
+ case tg["op"]
331
+ when PL::UPDATE
332
+ new["key2"] = new["key2"].upcase
333
+ old_ref_follow = (new["key1"] != old["key1"]) ||
334
+ (new["key2"] != old["key2"])
335
+ when PL::DELETE
336
+ old_ref_delete = true
337
+ end
338
+
339
+ if old_ref_follow
340
+ n = $Plans["plan_dta2_upd"].exec([old["key1"], old["key2"], new["key1"],
341
+ new["key2"]])
342
+ warn "updated #{n} entries in T_dta2 for new key in T_pkey2" if n != 0
343
+ end
344
+
345
+ if old_ref_delete
346
+ n = $Plans["plan_dta2_del"].exec([old["key1"], old["key2"]])
347
+ warn "deleted #{n} entries from T_dta2" if n != 0
348
+ end
349
+
350
+ PL::OK
351
+ ' language 'plruby';
352
+
353
+ create trigger pkey2_after after update or delete on T_pkey2
354
+ for each row execute procedure
355
+ trig_pkey2_after();</pre>
356
+ <h2><a name="label-19" id="label-19">plruby_singleton_methods</a></h2><!-- RDLabel: "plruby_singleton_methods" -->
357
+ <p>Sometime it can be usefull to define methods (in pure Ruby) which can be
358
+ called from a PL/Ruby function or a PL/Ruby trigger.</p>
359
+ <p>In this case, you have 2 possibilities</p>
360
+ <ul>
361
+ <li>the "stupid" way <code>:-) :-) :-)</code></li>
362
+ </ul>
363
+ <p>just close the current definition of the function (or trigger) with a
364
+ <code>end</code> and define your singleton method without the final <code>end</code></p>
365
+ <p>Here a small and useless example</p>
366
+ <pre>plruby_test=# CREATE FUNCTION tutu() RETURNS int4 AS '
367
+ plruby_test'# toto(1, 3) + toto(4, 4)
368
+ plruby_test'# end
369
+ plruby_test'#
370
+ plruby_test'# def PLtemp.toto(a, b)
371
+ plruby_test'# a + b
372
+ plruby_test'# ' LANGUAGE 'plruby';
373
+ CREATE
374
+ plruby_test=# select tutu();
375
+ tutu
376
+ ----
377
+ 12
378
+ (1 row)
379
+
380
+ plruby_test=#</pre>
381
+ <ul>
382
+ <li>create a table plruby_singleton_methods with the columns (name, args, body)</li>
383
+ </ul>
384
+ <p>At load time, PL/Ruby look if it exist a table plruby_singleton_methods and if
385
+ found try, for each row, to define singleton methods with the template :</p>
386
+ <pre>def PLtemp.#{name} (#{args})
387
+ #{body}
388
+ end</pre>
389
+ <p>The previous example can be written (you have a more complete example in
390
+ test/plp/test_setup.sql)</p>
391
+ <pre>plruby_test=# SELECT * FROM plruby_singleton_methods;
392
+ name|args|body
393
+ ----+----+-----
394
+ toto|a, b|a + b
395
+ (1 row)
396
+
397
+ plruby_test=# CREATE FUNCTION tutu() RETURNS int4 AS '
398
+ plruby_test'# toto(1, 3) + toto(4, 4)
399
+ plruby_test'# ' LANGUAGE 'plruby';
400
+ CREATE
401
+ plruby_test=# select tutu();
402
+ tutu
403
+ ----
404
+ 12
405
+ (1 row)
406
+
407
+ plruby_test=#</pre>
408
+ <ul>
409
+ <li><p>Another example, if PLRuby was compiled with --enable-conversion and it
410
+ exist a column with the name '***' then it can create a singleton method
411
+ from a PLRuby function</p>
412
+ <pre>plruby_test=# select * from plruby_singleton_methods;
413
+ name | args | body
414
+ ------+------+------
415
+ *** | |
416
+ (1 row)
417
+
418
+ plruby_test=# create function add_value(int, int) returns int as '
419
+ plruby_test'# args[0] + args[1]
420
+ plruby_test'# ' language 'plruby';
421
+ CREATE FUNCTION
422
+ plruby_test=#
423
+ plruby_test=# select add_value(10, 2);
424
+ add_value
425
+ -----------
426
+ 12
427
+ (1 row)
428
+
429
+ plruby_test=#
430
+ plruby_test=# create function add_one(int) returns int as '
431
+ plruby_test'# add_value(args[0], 1)
432
+ plruby_test'# ' language 'plruby';
433
+ CREATE FUNCTION
434
+ plruby_test=#
435
+ plruby_test=# select add_one(11);
436
+ add_one
437
+ ---------
438
+ 12
439
+ (1 row)
440
+
441
+ plruby_test=# </pre></li>
442
+ </ul>
443
+ <h2><a name="label-20" id="label-20">Conversion</a></h2><!-- RDLabel: "Conversion" -->
444
+ <p>If the conversions was not disabled (--disable-conversion), the following
445
+ conversions are made</p>
446
+ <pre>PostgreSQL Ruby
447
+ ---------- ----
448
+ OID Fixnum
449
+ INT2OID Fixnum
450
+ INT4OID Fixnum
451
+ INT8OID Fixnum (or Bignum)
452
+ FLOAT4OID Float
453
+ FLOAT8OID Float
454
+ CASHOID Float
455
+ NUMERICOID Float
456
+ BOOLOID true, false
457
+ ABSTIMEOID Time
458
+ RELTIMEOID Time
459
+ TIMEOID Time
460
+ TIMETZOID Time
461
+ TIMESTAMPOID Time
462
+ TIMESTAMPTZOID Time
463
+ DATEOID Time
464
+ INTERVALOID Time
465
+ TINTERVALOID Tinterval (new Ruby class)
466
+ BITOID BitString (new Ruby class)
467
+ VARBITOID BitString (new Ruby class)
468
+ INETOID NetAddr (new Ruby class)
469
+ CIDROID NetAddr (new Ruby class)
470
+ MACADDROID MacAddr (new Ruby class)
471
+ POINTOID Point (new Ruby class)
472
+ LSEGOID Segment (new Ruby class)
473
+ BOXOID Box (new Ruby class)
474
+ PATHOID Path (new Ruby class)
475
+ POLYGONOID Polygon (new Ruby class)
476
+ CIRCLEOID Circle (new Ruby class)</pre>
477
+ <p>all others OID are converted to a String object</p>
478
+ <h2><a name="label-21" id="label-21">Class and modules</a></h2><!-- RDLabel: "Class and modules" -->
479
+ <h3><a name="label-22" id="label-22">Global</a></h3><!-- RDLabel: "Global" -->
480
+ <dl>
481
+ <dt><a name="label-23" id="label-23"><code>transaction {|<var>txn</var>| }</code></a></dt><!-- RDLabel: "transaction" -->
482
+ <dd>
483
+ create a new transaction, yield an object <kbd>PL::Transaction</kbd></dd>
484
+ <dt><a name="label-24" id="label-24"><code>warn [<var>level</var>], <var>message</var></code></a></dt><!-- RDLabel: "warn [level], message" -->
485
+ <dd>
486
+ <p>Ruby interface to PostgreSQL elog()</p>
487
+ <p>Possible value for <kbd>level</kbd> are <kbd>NOTICE</kbd>, <kbd>DEBUG</kbd> and <kbd>NOIND</kbd></p>
488
+ <p>Use <kbd>raise()</kbd> if you want to simulate <kbd>elog(ERROR, "...")</kbd></p></dd>
489
+ <dt><a name="label-25" id="label-25"><code>$Plans (<var>hash</var>, <var>tainted</var>)</code></a></dt><!-- RDLabel: "$Plans" -->
490
+ <dd>
491
+ can be used to store prepared plans.</dd>
492
+ </dl>
493
+ <h3><a name="label-26" id="label-26">module PL</a></h3><!-- RDLabel: "module PL" -->
494
+ <pre>general module</pre>
495
+ <dl>
496
+ <dt><a name="label-27" id="label-27"><code>args_type</code></a></dt><!-- RDLabel: "args_type" -->
497
+ <dd>
498
+ Return the type of the arguments given to the function</dd>
499
+ <dt><a name="label-28" id="label-28"><code>column_name(<var>table</var>)</code></a></dt><!-- RDLabel: "column_name" -->
500
+ <dd>
501
+ Return the name of the columns for the table</dd>
502
+ <dt><a name="label-29" id="label-29"><code>column_type(<var>table</var>)</code></a></dt><!-- RDLabel: "column_type" -->
503
+ <dd>
504
+ return the type of the columns for the table</dd>
505
+ <dt><a name="label-30" id="label-30"><code>context</code></a></dt><!-- RDLabel: "context" -->
506
+ <dd>
507
+ Return the context (or nil) associated with a SETOF function
508
+ (ExprMultiResult)</dd>
509
+ <dt><a name="label-31" id="label-31"><code>context=</code></a></dt><!-- RDLabel: "context=" -->
510
+ <dd>
511
+ Set the context for a SETOF function (ExprMultiResult)</dd>
512
+ <dt><a name="label-32" id="label-32"><code>quote(<var>string</var>)</code></a></dt><!-- RDLabel: "quote" -->
513
+ <dd>
514
+ Duplicates all occurences of single quote and backslash
515
+ characters. It should be used when variables are used in the query
516
+ string given to spi_exec or spi_prepare (not for the value list on
517
+ execp).</dd>
518
+ <dt><a name="label-33" id="label-33"><code>result_name</code></a></dt><!-- RDLabel: "result_name" -->
519
+ <dd>
520
+ Return the name of the columns for a function returning a SETOF</dd>
521
+ <dt><a name="label-34" id="label-34"><code>result_type</code></a></dt><!-- RDLabel: "result_type" -->
522
+ <dd>
523
+ Return the type of the columns for a function returning a SETOF
524
+ or the type of the return value</dd>
525
+ <dt><a name="label-35" id="label-35"><code>result_size</code></a></dt><!-- RDLabel: "result_size" -->
526
+ <dd>
527
+ Return the number of columns for a function returning a SETOF</dd>
528
+ <dt><a name="label-36" id="label-36"><code>result_description</code></a></dt><!-- RDLabel: "result_description" -->
529
+ <dd>
530
+ Return the table description given to a function returning a SETOF</dd>
531
+ <dt><a name="label-37" id="label-37"><code>exec(<var>string</var> [, <var>count</var> [, <var>type</var>]])</code></a></dt><!-- RDLabel: "exec" -->
532
+ <dt><a name="label-38" id="label-38"><code>spi_exec(<var>string</var> [, <var>count</var> [, <var>type</var>]])</code></a></dt><!-- RDLabel: "spi_exec" -->
533
+ <dd>
534
+ Call parser/planner/optimizer/executor for query. The optional
535
+ <kbd>count</kbd> value tells spi_exec the maximum number of rows to be
536
+ processed by the query.
537
+ <dl>
538
+ <dt><a name="label-39" id="label-39">SELECT</a></dt><!-- RDLabel: "SELECT" -->
539
+ <dd>
540
+ <p>If the query is a SELECT statement, an array is return (if count is
541
+ not specified or with a value &gt; 1). Each element of this array is an
542
+ hash where the key is the column name.</p>
543
+ <p>If type is specified it can take the value</p>
544
+ <ul>
545
+ <li>"array" return for each column an array with the element
546
+ ["name", "value", "type", "len", "typeid"]</li>
547
+ <li>"hash" return for each column an hash with the keys
548
+ {"name", "value", "type", "len", "typeid"}</li>
549
+ <li>"value" return all values</li>
550
+ </ul>
551
+ <p>For example this procedure display all rows in the table pg_table.</p>
552
+ <pre>CREATE FUNCTION pg_table_dis() RETURNS int4 AS '
553
+ res = PLruby.exec("select * from pg_class")
554
+ res.each do |x|
555
+ warn "======================"
556
+ x.each do |y, z|
557
+ warn "name = #{y} -- value = #{z}"
558
+ end
559
+ warn "======================"
560
+ end
561
+ return res.size
562
+ ' LANGUAGE 'plruby';</pre>
563
+ <p>A block can be specified, in this case a call to yield() will be
564
+ made.</p>
565
+ <p>If count is specified with the value 1, only the first row (or
566
+ FALSE if it fail) is returned as a hash. Here a little example :</p>
567
+ <pre>CREATE FUNCTION pg_table_dis() RETURNS int4 AS '
568
+ PL.exec("select * from pg_class", 1) { |y, z|
569
+ warn "name = #{y} -- value = #{z}"
570
+ }
571
+ return 1
572
+ ' LANGUAGE 'plruby';</pre>
573
+ <p>Another example with count = 1</p>
574
+ <pre>create table T_pkey1 (
575
+ skey1 int4,
576
+ skey2 varchar(20),
577
+ stxt varchar(40)
578
+ );
579
+
580
+ create function toto() returns bool as '
581
+ warn("=======")
582
+ PL.exec("select * from T_pkey1", 1, "hash") do |a|
583
+ warn(a.inspect)
584
+ end
585
+ warn("=======")
586
+ PL.exec("select * from T_pkey1", 1, "array") do |a|
587
+ warn(a.inspect)
588
+ end
589
+ warn("=======")
590
+ PL.exec("select * from T_pkey1", 1) do |a|
591
+ warn(a.inspect)
592
+ end
593
+ warn("=======")
594
+ return true
595
+ ' language 'plruby';
596
+
597
+
598
+ plruby_test=# select toto();
599
+ NOTICE: =======
600
+ NOTICE: {"name"=&gt;"skey1", "typeid"=&gt;23, "type"=&gt;"int4", "value"=&gt;"12", "len"=&gt;4}
601
+ NOTICE: {"name"=&gt;"skey2", "typeid"=&gt;1043, "type"=&gt;"varchar", "value"=&gt;"a", "len"=&gt;20}
602
+ NOTICE: {"name"=&gt;"stxt", "typeid"=&gt;1043, "type"=&gt;"varchar", "value"=&gt;"b", "len"=&gt;40}
603
+ NOTICE: =======
604
+ NOTICE: ["skey1", "12", "int4", 4, 23]
605
+ NOTICE: ["skey2", "a", "varchar", 20, 1043]
606
+ NOTICE: ["stxt", "b", "varchar", 40, 1043]
607
+ NOTICE: =======
608
+ NOTICE: ["skey1", "12"]
609
+ NOTICE: ["skey2", "a"]
610
+ NOTICE: ["stxt", "b"]
611
+ NOTICE: =======
612
+ toto
613
+ ------
614
+ t
615
+ (1 row)
616
+
617
+ plruby_test=# </pre>
618
+ </dd>
619
+ <dt><a name="label-40" id="label-40">SELECT INTO, INSERT, UPDATE, DELETE</a></dt><!-- RDLabel: "SELECT INTO, INSERT, UPDATE, DELETE" -->
620
+ <dd>
621
+ return the number of rows insered, updated, deleted, ...
622
+ </dd>
623
+ <dt><a name="label-41" id="label-41">UTILITY</a></dt><!-- RDLabel: "UTILITY" -->
624
+ <dd>
625
+ return TRUE
626
+ </dd>
627
+ </dl></dd>
628
+ <dt><a name="label-42" id="label-42"><code>prepare(<var>string</var>[, <var>types</var>])</code></a></dt><!-- RDLabel: "prepare" -->
629
+ <dt><a name="label-43" id="label-43"><code>spi_prepare(<var>string</var>[, <var>types</var>])</code></a></dt><!-- RDLabel: "spi_prepare" -->
630
+ <dt><a name="label-44" id="label-44"><code>prepare(<var>string</var>, "<var>types</var>" =&gt; <var>types</var>, "<var>count</var>" =&gt; <var>count</var>, "<var>output</var>" =&gt; <var>type</var>, "<var>tmp</var>" =&gt; <var>true</var>)</code></a></dt><!-- RDLabel: "prepare" -->
631
+ <dd>
632
+ <p>Deprecated : See <kbd>PL::Plan::new</kbd> and <kbd>PL::Plan#save</kbd></p>
633
+ <p>Prepares AND SAVES a query plan for later execution. It is a bit
634
+ different from the C level SPI_prepare in that the plan is
635
+ automatically copied to the toplevel memory context.</p>
636
+ <p>If the query references arguments, the type names must be given as a
637
+ Ruby array of strings. The return value from prepare is a
638
+ <kbd>PL::Plan</kbd> object to be used in subsequent calls to
639
+ <kbd>PL::Plan#exec</kbd>.</p>
640
+ <p>If the hash given has the keys <kbd>count</kbd>, <kbd>output</kbd> these values
641
+ will be given to the subsequent calls to <kbd>each</kbd></p></dd>
642
+ </dl>
643
+ <h3><a name="label-45" id="label-45">class PL::Plan</a></h3><!-- RDLabel: "class PL::Plan" -->
644
+ <pre>class for prepared plan</pre>
645
+ <dl>
646
+ <dt><a name="label-46" id="label-46"><code>initialize(<var>string</var>, "<var>types</var>" =&gt; <var>types</var>, "<var>count</var>" =&gt; <var>count</var>, "<var>output</var>" =&gt; <var>type</var>, "<var>save</var>" =&gt; <var>false</var>)</code></a></dt><!-- RDLabel: "initialize" -->
647
+ <dd>
648
+ <p>Prepares a query plan for later execution.</p>
649
+ <p>If the query references arguments, the type names must be given as a
650
+ Ruby array of strings.</p>
651
+ <p>If the hash given has the keys <kbd>output</kbd>, <kbd>count</kbd> these values
652
+ will be given to the subsequent calls to <kbd>each</kbd></p>
653
+ <p>If <kbd>"save"</kbd> as a true value, the plan will be saved </p></dd>
654
+ <dt><a name="label-47" id="label-47"><code>exec(<var>values</var>, [<var>count</var> [, <var>type</var>]])</code></a></dt><!-- RDLabel: "exec" -->
655
+ <dt><a name="label-48" id="label-48"><code>execp(<var>values</var>, [<var>count</var> [, <var>type</var>]])</code></a></dt><!-- RDLabel: "execp" -->
656
+ <dt><a name="label-49" id="label-49"><code>exec("<var>values</var>" =&gt; <var>values</var>, "<var>count</var>" =&gt; <var>count</var>, "<var>output</var>" =&gt; <var>type</var>)</code></a></dt><!-- RDLabel: "exec" -->
657
+ <dt><a name="label-50" id="label-50"><code>execp("<var>values</var>" =&gt; <var>values</var>, "<var>count</var>" =&gt; <var>count</var>, "<var>output</var>" =&gt; <var>type</var>)</code></a></dt><!-- RDLabel: "execp" -->
658
+ <dd>
659
+ <p>Execute a prepared plan from <kbd>PL::PLan::new</kbd> with variable
660
+ substitution. The optional <kbd>count</kbd> value tells
661
+ <kbd>PL::Plan#exec</kbd> the maximum number of rows to be processed by the
662
+ query.</p>
663
+ <p>If there was a typelist given to <kbd>PL::Plan::new</kbd>, an array
664
+ of <kbd>values</kbd> of exactly the same length must be given to
665
+ <kbd>PL::Plan#exec</kbd> as first argument. If the type list on
666
+ <kbd>PL::Plan::new</kbd> was empty, this argument must be omitted.</p>
667
+ <p>If the query is a SELECT statement, the same as described for
668
+ <kbd>PL#exec</kbd> happens for the loop-body and the variables for
669
+ the fields selected.</p>
670
+ <p>If type is specified it can take the values</p>
671
+ <ul>
672
+ <li>"array" return an array with the element ["name", "value", "type", "len", "typeid"]</li>
673
+ <li>"hash" return an hash with the keys {"name", "value", "type", "len", "typeid"}</li>
674
+ <li>"value" return an array with all values</li>
675
+ </ul>
676
+ <p>Here's an example for a PL/Ruby function using a prepared plan : </p>
677
+ <pre>CREATE FUNCTION t1_count(int4, int4) RETURNS int4 AS '
678
+ if ! $Plans.key?("plan")
679
+ # prepare the saved plan on the first call
680
+ $Plans["plan"] = PL::Plan.new("SELECT count(*) AS cnt FROM t1
681
+ WHERE num &gt;= $1 AND num &lt;= $2",
682
+ ["int4", "int4"]).save
683
+ end
684
+ n = $Plans["plan"].exec([args[0], args[1]], 1)
685
+ n["cnt"]
686
+ ' LANGUAGE 'plruby';</pre></dd>
687
+ <dt><a name="label-51" id="label-51"><code>cursor(<var>name</var> = <var>nil</var>, "<var>values</var>" =&gt; <var>values</var>, "<var>output</var>" =&gt; <var>type</var>)</code></a></dt><!-- RDLabel: "cursor" -->
688
+ <dd>
689
+ <p>Create a new object PL::Cursor</p>
690
+ <p>If output is specified it can take the values</p>
691
+ <ul>
692
+ <li>"array" return an array with the element ["name", "value", "type", "len", "typeid"]</li>
693
+ <li>"hash" return an hash with the keys {"name", "value", "type", "len", "typeid"}</li>
694
+ <li>"value" return an array with all values</li>
695
+ </ul>
696
+ <p>If there was a typelist given to <kbd>PL::Plan::new</kbd>, an array
697
+ of <kbd>values</kbd> of exactly the same length must be given to
698
+ <kbd>PL::Plan#cursor</kbd></p></dd>
699
+ <dt><a name="label-52" id="label-52"><code>each(<var>values</var>, [<var>count</var> [, <var>type</var> ]]) { ... }</code></a></dt><!-- RDLabel: "each" -->
700
+ <dt><a name="label-53" id="label-53"><code>fetch(<var>values</var>, [<var>count</var> [, <var>type</var> ]]) { ... }</code></a></dt><!-- RDLabel: "fetch" -->
701
+ <dt><a name="label-54" id="label-54"><code>each("<var>values</var>" =&gt; <var>values</var>, "<var>count</var>" =&gt; <var>count</var>, "<var>output</var>" =&gt; <var>type</var>) { ... }</code></a></dt><!-- RDLabel: "each" -->
702
+ <dt><a name="label-55" id="label-55"><code>fetch("<var>values</var>" =&gt; <var>values</var>, "<var>count</var>" =&gt; <var>count</var>, "<var>output</var>" =&gt; <var>type</var>) { ... }</code></a></dt><!-- RDLabel: "fetch" -->
703
+ <dd>
704
+ <p>Same then #exec but a call to SPI_cursor_open(), SPI_cursor_fetch() is made.</p>
705
+ <p>Can be used only with a block and a SELECT statement</p>
706
+ <pre>create function toto() returns bool as '
707
+ plan = PL::Plan.new("select * from T_pkey1")
708
+ warn "=====&gt; ALL"
709
+ plan.each do |x|
710
+ warn(x.inspect)
711
+ end
712
+ warn "=====&gt; FIRST 2"
713
+ plan.each("count" =&gt; 2) do |x|
714
+ warn(x.inspect)
715
+ end
716
+ return true
717
+ ' language 'plruby';
718
+
719
+ plruby_test=# select * from T_pkey1;
720
+ skey1 | skey2 | stxt
721
+ -------+-------+------
722
+ 12 | a | b
723
+ 24 | c | d
724
+ 36 | e | f
725
+ (3 rows)
726
+
727
+ plruby_test=#
728
+ plruby_test=# select toto();
729
+ NOTICE: =====&gt; ALL
730
+ NOTICE: {"skey1"=&gt;"12", "skey2"=&gt;"a", "stxt"=&gt;"b"}
731
+ NOTICE: {"skey1"=&gt;"24", "skey2"=&gt;"c", "stxt"=&gt;"d"}
732
+ NOTICE: {"skey1"=&gt;"36", "skey2"=&gt;"e", "stxt"=&gt;"f"}
733
+ NOTICE: =====&gt; FIRST 2
734
+ NOTICE: {"skey1"=&gt;"12", "skey2"=&gt;"a", "stxt"=&gt;"b"}
735
+ NOTICE: {"skey1"=&gt;"24", "skey2"=&gt;"c", "stxt"=&gt;"d"}
736
+ toto
737
+ ------
738
+ t
739
+ (1 row)
740
+
741
+ plruby_test=# </pre></dd>
742
+ <dt><a name="label-56" id="label-56"><code>release</code></a></dt><!-- RDLabel: "release" -->
743
+ <dd>
744
+ Release a query plan</dd>
745
+ <dt><a name="label-57" id="label-57"><code>save</code></a></dt><!-- RDLabel: "save" -->
746
+ <dd>
747
+ Save a query plan for later execution. The plan is copied to the
748
+ toplevel memory context.</dd>
749
+ </dl>
750
+ <h3><a name="label-58" id="label-58">class PL::Cursor</a></h3><!-- RDLabel: "class PL::Cursor" -->
751
+ <pre>A cursor is created with the method PL::Plan#cursor</pre>
752
+ <dl>
753
+ <dt><a name="label-59" id="label-59"><code>close</code></a></dt><!-- RDLabel: "close" -->
754
+ <dd>
755
+ Closes a cursor</dd>
756
+ <dt><a name="label-60" id="label-60"><code>each {|<var>row</var>| ... }</code></a></dt><!-- RDLabel: "each" -->
757
+ <dd>
758
+ Iterate over all rows (forward)</dd>
759
+ <dt><a name="label-61" id="label-61"><code>fetch(<var>count</var> = <var>1</var>)</code></a></dt><!-- RDLabel: "fetch" -->
760
+ <dt><a name="label-62" id="label-62"><code>row(<var>count</var> = <var>1</var>)</code></a></dt><!-- RDLabel: "row" -->
761
+ <dd>
762
+ <p>Fetches some rows from a cursor</p>
763
+ <p>if count &gt; 0 fetch forward else backward</p></dd>
764
+ <dt><a name="label-63" id="label-63"><code>move(<var>count</var>)</code></a></dt><!-- RDLabel: "move" -->
765
+ <dd>
766
+ Move a cursor : if count &gt; 0 move forward else backward</dd>
767
+ <dt><a name="label-64" id="label-64"><code>reverse_each {|<var>row</var>| ... }</code></a></dt><!-- RDLabel: "reverse_each" -->
768
+ <dd>
769
+ Iterate over all rows (backward)</dd>
770
+ <dt><a name="label-65" id="label-65"><code>rewind</code></a></dt><!-- RDLabel: "rewind" -->
771
+ <dd>
772
+ Positions the cursor at the beginning of the table</dd>
773
+ </dl>
774
+ <h3><a name="label-66" id="label-66">class PL::Transaction</a></h3><!-- RDLabel: "class PL::Transaction" -->
775
+ <p>a transaction is created with the global function <kbd>transaction()</kbd>. Only
776
+ available with PostgreSQL &gt;= 8.0</p>
777
+ <dl>
778
+ <dt><a name="label-67" id="label-67"><code>abort</code></a></dt><!-- RDLabel: "abort" -->
779
+ <dd>
780
+ Abort the transaction</dd>
781
+ <dt><a name="label-68" id="label-68"><code>commit</code></a></dt><!-- RDLabel: "commit" -->
782
+ <dd>
783
+ Commit the transaction</dd>
784
+ </dl>
785
+ <h3><a name="label-69" id="label-69">class BitString</a></h3><!-- RDLabel: "class BitString" -->
786
+ <p>The class BitString implement the PostgreSQL type <var>bit</var>
787
+ and <var>bit varying</var></p>
788
+ <p>The modules Comparable and Enumerable are included</p>
789
+ <dl>
790
+ <dt><a name="label-70" id="label-70"><code>from_string(<var>string</var>, <var>length</var> = <var>strlen</var>(<var>string</var>))</code></a></dt><!-- RDLabel: "from_string" -->
791
+ <dd>
792
+ Convert a <var>String</var> to a <var>BitString</var></dd>
793
+ <dt><a name="label-71" id="label-71"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
794
+ <dd>
795
+ <p>comparison function for 2 <var>BitString</var> objects</p>
796
+ <p>All bits are considered and additional zero bits may make one string
797
+ smaller/larger than the other, even if their zero-padded values would
798
+ be the same.</p></dd>
799
+ <dt><a name="label-72" id="label-72"><code>+(<var>other</var>)</code></a></dt><!-- RDLabel: "+" -->
800
+ <dd>
801
+ Concatenate <var>self</var> and <var>other</var></dd>
802
+ <dt><a name="label-73" id="label-73"><code>&amp;(<var>other</var>)</code></a></dt><!-- RDLabel: "&" -->
803
+ <dd>
804
+ AND operator</dd>
805
+ <dt><a name="label-74" id="label-74"><code>|(<var>other</var>)</code></a></dt><!-- RDLabel: "|" -->
806
+ <dd>
807
+ OR operator</dd>
808
+ <dt><a name="label-75" id="label-75"><code>^(<var>other</var>)</code></a></dt><!-- RDLabel: "^" -->
809
+ <dd>
810
+ XOR operator</dd>
811
+ <dt><a name="label-76" id="label-76"><code>~</code></a></dt><!-- RDLabel: "~" -->
812
+ <dd>
813
+ NOT operator</dd>
814
+ <dt><a name="label-77" id="label-77"><code>&lt;&lt;(<var>lshft</var>)</code></a></dt><!-- RDLabel: "<<" -->
815
+ <dd>
816
+ LEFT SHIFT operator</dd>
817
+ <dt><a name="label-78" id="label-78"><code>&gt;&gt;(<var>rshft</var>)</code></a></dt><!-- RDLabel: ">>" -->
818
+ <dd>
819
+ RIGHT SHIFT operator</dd>
820
+ <dt><a name="label-79" id="label-79"><code>[*<var>args</var>]</code></a></dt><!-- RDLabel: "[]" -->
821
+ <dd>
822
+ <p>Element reference with the same syntax that for a <var>String</var> object</p>
823
+ <p>Return a <var>BitString</var> or a <var>Fixnum</var> 0, 1</p>
824
+ <pre>bitstring[fixnum]
825
+ bitstring[fixnum, fixnum]
826
+ bitstring[range]
827
+ bitstring[regexp]
828
+ bitstring[regexp, fixnum]
829
+ bitstring[string]
830
+ bitstring[other_bitstring]</pre></dd>
831
+ <dt><a name="label-80" id="label-80"><code>[*<var>args</var>] = <var>val</var></code></a></dt><!-- RDLabel: "[]=" -->
832
+ <dd>
833
+ <p>Element assignment with the same syntax that for a <var>String</var> object</p>
834
+ <pre>bitstring[fixnum] = fixnum
835
+ bitstring[fixnum] = string_or_bitstring
836
+ bitstring[fixnum, fixnum] = string_or_bitstring
837
+ bitstring[range] = string_or_bitstring
838
+ bitstring[regexp] = string_or_bitstring
839
+ bitstring[regexp, fixnum] = string_or_bitstring
840
+ bitstring[other_str] = string_or_bitstring</pre></dd>
841
+ <dt><a name="label-81" id="label-81"><code>concat(<var>other</var>)</code></a></dt><!-- RDLabel: "concat" -->
842
+ <dd>
843
+ append <var>other</var> to <var>self</var></dd>
844
+ <dt><a name="label-82" id="label-82"><code>each</code></a></dt><!-- RDLabel: "each" -->
845
+ <dd>
846
+ iterate other each bit</dd>
847
+ <dt><a name="label-83" id="label-83"><code>include?(<var>other</var>)</code></a></dt><!-- RDLabel: "include?" -->
848
+ <dd>
849
+ return <var>true</var> if <var>other</var> is included in <var>self</var></dd>
850
+ <dt><a name="label-84" id="label-84"><code>index(<var>other</var>)</code></a></dt><!-- RDLabel: "index" -->
851
+ <dd>
852
+ <p>return the position of <var>other</var> in <var>self</var></p>
853
+ <p>return <var>nil</var> if <var>other</var> is not included in <var>self</var></p></dd>
854
+ <dt><a name="label-85" id="label-85"><code>initialize(<var>init</var>, <var>nbits</var> = -<var>1</var>)</code></a></dt><!-- RDLabel: "initialize" -->
855
+ <dd>
856
+ <p>create a new <var>BitString</var> object with <var>nbits</var> bits</p>
857
+ <p><var>init</var> can be a <var>Fixnum</var> or a <var>String</var></p>
858
+ <p>For a <var>String</var> the first character can be 'x', 'X' for and
859
+ hexadecimal representation, or 'b', 'B' for a binary representation.
860
+ The default is a binary representation</p></dd>
861
+ <dt><a name="label-86" id="label-86"><code>length</code></a></dt><!-- RDLabel: "length" -->
862
+ <dd>
863
+ return the length of <var>self</var> in bits</dd>
864
+ <dt><a name="label-87" id="label-87"><code>octet_length</code></a></dt><!-- RDLabel: "octet_length" -->
865
+ <dd>
866
+ return the length of <var>self</var> in octets</dd>
867
+ <dt><a name="label-88" id="label-88"><code>push(<var>other</var>)</code></a></dt><!-- RDLabel: "push" -->
868
+ <dd>
869
+ append <var>other</var> to <var>self</var></dd>
870
+ <dt><a name="label-89" id="label-89"><code>to_i</code></a></dt><!-- RDLabel: "to_i" -->
871
+ <dd>
872
+ convert <var>self</var> to a <var>Fixnum</var></dd>
873
+ <dt><a name="label-90" id="label-90"><code>to_s</code></a></dt><!-- RDLabel: "to_s" -->
874
+ <dd>
875
+ convert <var>self</var> to a <var>String</var></dd>
876
+ </dl>
877
+ <h3><a name="label-91" id="label-91">class NetAddr</a></h3><!-- RDLabel: "class NetAddr" -->
878
+ <p>The class NetAddr implement the PostgreSQL type <var>inet</var>
879
+ and <var>cidr</var></p>
880
+ <p>The module Comparable is included</p>
881
+ <dl>
882
+ <dt><a name="label-92" id="label-92"><code>from_string(<var>string</var>, <var>cidr</var> = <var>false</var>)</code></a></dt><!-- RDLabel: "from_string" -->
883
+ <dd>
884
+ Convert a <var>String</var> to a <var>NetAddr</var></dd>
885
+ <dt><a name="label-93" id="label-93"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
886
+ <dd>
887
+ <p>comparison function for 2 <var>NetAddr</var> objects</p>
888
+ <p>comparison is first on the common bits of the network part, then on
889
+ the length of the network part, and then on the whole unmasked address.</p></dd>
890
+ <dt><a name="label-94" id="label-94"><code>abbrev</code></a></dt><!-- RDLabel: "abbrev" -->
891
+ <dd>
892
+ return the abbreviated display format as a <var>String</var> object</dd>
893
+ <dt><a name="label-95" id="label-95"><code>broadcast</code></a></dt><!-- RDLabel: "broadcast" -->
894
+ <dd>
895
+ return the broadcast address from the network</dd>
896
+ <dt><a name="label-96" id="label-96"><code>contain?(<var>other</var>)</code></a></dt><!-- RDLabel: "contain?" -->
897
+ <dd>
898
+ return true if <var>other</var> is included in <var>self</var></dd>
899
+ <dt><a name="label-97" id="label-97"><code>contain_or_equal?(<var>other</var>)</code></a></dt><!-- RDLabel: "contain_or_equal?" -->
900
+ <dd>
901
+ return true if <var>other</var> is included in <var>self</var>, or equal</dd>
902
+ <dt><a name="label-98" id="label-98"><code>contained?(<var>other</var>)</code></a></dt><!-- RDLabel: "contained?" -->
903
+ <dd>
904
+ return true if <var>self</var> is included in <var>other</var></dd>
905
+ <dt><a name="label-99" id="label-99"><code>contained_or_equal?(<var>other</var>)</code></a></dt><!-- RDLabel: "contained_or_equal?" -->
906
+ <dd>
907
+ return true if <var>self</var> is included in <var>other</var>, or equal</dd>
908
+ <dt><a name="label-100" id="label-100"><code>family</code></a></dt><!-- RDLabel: "family" -->
909
+ <dd>
910
+ return the String "AF_INET" or "AF_INET6"</dd>
911
+ <dt><a name="label-101" id="label-101"><code>first</code></a></dt><!-- RDLabel: "first" -->
912
+ <dd>
913
+ return the first address in the network</dd>
914
+ <dt><a name="label-102" id="label-102"><code>host</code></a></dt><!-- RDLabel: "host" -->
915
+ <dd>
916
+ extract the IP address and return it as a <var>String</var> </dd>
917
+ <dt><a name="label-103" id="label-103"><code>hostmask</code></a></dt><!-- RDLabel: "hostmask" -->
918
+ <dd>
919
+ return the host mask for network</dd>
920
+ <dt><a name="label-104" id="label-104"><code>initialize(<var>string</var>, <var>cidr</var> = <var>false</var>)</code></a></dt><!-- RDLabel: "initialize" -->
921
+ <dd>
922
+ create a <var>NetAddr</var> from a <var>String</var></dd>
923
+ <dt><a name="label-105" id="label-105"><code>last</code></a></dt><!-- RDLabel: "last" -->
924
+ <dd>
925
+ return the last address in the network</dd>
926
+ <dt><a name="label-106" id="label-106"><code>masklen</code></a></dt><!-- RDLabel: "masklen" -->
927
+ <dd>
928
+ return the length of the netmask</dd>
929
+ <dt><a name="label-107" id="label-107"><code>netmask</code></a></dt><!-- RDLabel: "netmask" -->
930
+ <dd>
931
+ return the netmask for the network</dd>
932
+ <dt><a name="label-108" id="label-108"><code>network</code></a></dt><!-- RDLabel: "network" -->
933
+ <dd>
934
+ return the network part of the address</dd>
935
+ <dt><a name="label-109" id="label-109"><code>set_masklen(<var>len</var>)</code></a></dt><!-- RDLabel: "set_masklen" -->
936
+ <dd>
937
+ return a new <var>NetAddr</var> with netmask length <var>len</var></dd>
938
+ <dt><a name="label-110" id="label-110"><code>to_s</code></a></dt><!-- RDLabel: "to_s" -->
939
+ <dd>
940
+ return the string representation of the address</dd>
941
+ </dl>
942
+ <h3><a name="label-111" id="label-111">class MacAddr</a></h3><!-- RDLabel: "class MacAddr" -->
943
+ <p>The MacAddr implement the PostgreSQL type <var>macaddr</var></p>
944
+ <p>The module Comparable is included</p>
945
+ <dl>
946
+ <dt><a name="label-112" id="label-112"><code>from_string(<var>string</var>, <var>cidr</var> = <var>false</var>)</code></a></dt><!-- RDLabel: "from_string" -->
947
+ <dd>
948
+ Convert a <var>String</var> to a <var>MacAddr</var></dd>
949
+ <dt><a name="label-113" id="label-113"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
950
+ <dd>
951
+ comparison function for 2 <var>MacAddr</var> objects</dd>
952
+ <dt><a name="label-114" id="label-114"><code>initialize(<var>string</var>)</code></a></dt><!-- RDLabel: "initialize" -->
953
+ <dd>
954
+ create a <var>MacAddr</var> from a <var>String</var></dd>
955
+ <dt><a name="label-115" id="label-115"><code>to_s</code></a></dt><!-- RDLabel: "to_s" -->
956
+ <dd>
957
+ return the string representation of the MAC address</dd>
958
+ <dt><a name="label-116" id="label-116"><code>truncate</code></a></dt><!-- RDLabel: "truncate" -->
959
+ <dd>
960
+ return a new object with the last 3 bytes set to zero</dd>
961
+ </dl>
962
+ <h3><a name="label-117" id="label-117">class Tinterval</a></h3><!-- RDLabel: "class Tinterval" -->
963
+ <p>The Tinterval implement the PostgreSQL type <var>tinterval</var></p>
964
+ <dl>
965
+ <dt><a name="label-118" id="label-118"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
966
+ <dd>
967
+ Convert a <var>String</var> (PostgreSQL representation)
968
+ to a <var>Tinterval</var></dd>
969
+ <dt><a name="label-119" id="label-119"><code>high</code></a></dt><!-- RDLabel: "high" -->
970
+ <dd>
971
+ return a <var>Time</var> which is the high value of the interval</dd>
972
+ <dt><a name="label-120" id="label-120"><code>high=(<var>time</var>)</code></a></dt><!-- RDLabel: "high=" -->
973
+ <dd>
974
+ set the high value for the interval</dd>
975
+ <dt><a name="label-121" id="label-121"><code>initialize(<var>low</var>, <var>high</var>)</code></a></dt><!-- RDLabel: "initialize" -->
976
+ <dd>
977
+ create a <var>Tinterval</var> with the 2 <var>Time</var> objects
978
+ <var>low</var> and <var>high</var></dd>
979
+ <dt><a name="label-122" id="label-122"><code>low</code></a></dt><!-- RDLabel: "low" -->
980
+ <dd>
981
+ return a <var>Time</var> which is the low value of the interval</dd>
982
+ <dt><a name="label-123" id="label-123"><code>low=(<var>time</var>)</code></a></dt><!-- RDLabel: "low=" -->
983
+ <dd>
984
+ set the low value for the interval</dd>
985
+ <dt><a name="label-124" id="label-124"><code>to_s</code></a></dt><!-- RDLabel: "to_s" -->
986
+ <dd>
987
+ return the string representation of the object</dd>
988
+ </dl>
989
+ <h3><a name="label-125" id="label-125">class Box</a></h3><!-- RDLabel: "class Box" -->
990
+ <p>The Box implement the PostgreSQL type <var>box</var></p>
991
+ <p>The module Comparable is included</p>
992
+ <dl>
993
+ <dt><a name="label-126" id="label-126"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
994
+ <dd>
995
+ Convert a <var>String</var> (PostgreSQL representation)
996
+ to a <var>Box</var> object</dd>
997
+ <dt><a name="label-127" id="label-127"><code>+(<var>point</var>)</code></a></dt><!-- RDLabel: "+" -->
998
+ <dd>
999
+ translate (right, up) <var>self</var></dd>
1000
+ <dt><a name="label-128" id="label-128"><code>-(<var>point</var>)</code></a></dt><!-- RDLabel: "-" -->
1001
+ <dd>
1002
+ translate (left, down) <var>self</var></dd>
1003
+ <dt><a name="label-129" id="label-129"><code>*(<var>point</var>)</code></a></dt><!-- RDLabel: "*" -->
1004
+ <dd>
1005
+ scale and rotate <var>self</var></dd>
1006
+ <dt><a name="label-130" id="label-130"><code>/(<var>point</var>)</code></a></dt><!-- RDLabel: "/" -->
1007
+ <dd>
1008
+ scale and rotate <var>self</var></dd>
1009
+ <dt><a name="label-131" id="label-131"><code>===(<var>other</var>)</code></a></dt><!-- RDLabel: "===" -->
1010
+ <dd>
1011
+ return true if the 2 boxes <var>self</var> and <var>other</var> are identical</dd>
1012
+ <dt><a name="label-132" id="label-132"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
1013
+ <dd>
1014
+ comparison operator for 2 Box based on the area of the 2 objects, i.e.
1015
+ self.area &lt;=&gt; box.area</dd>
1016
+ <dt><a name="label-133" id="label-133"><code>above?(<var>other</var>)</code></a></dt><!-- RDLabel: "above?" -->
1017
+ <dd>
1018
+ return true if <var>self</var> is above <var>other</var></dd>
1019
+ <dt><a name="label-134" id="label-134"><code>area</code></a></dt><!-- RDLabel: "area" -->
1020
+ <dd>
1021
+ return the area of the Box</dd>
1022
+ <dt><a name="label-135" id="label-135"><code>below?(<var>other</var>)</code></a></dt><!-- RDLabel: "below?" -->
1023
+ <dd>
1024
+ return true if <var>self</var> is below <var>other</var></dd>
1025
+ <dt><a name="label-136" id="label-136"><code>center</code></a></dt><!-- RDLabel: "center" -->
1026
+ <dd>
1027
+ return the center point of the Box</dd>
1028
+ <dt><a name="label-137" id="label-137"><code>closest(<var>other</var>)</code></a></dt><!-- RDLabel: "closest" -->
1029
+ <dd>
1030
+ <p>closest point to <var>other</var></p>
1031
+ <p><var>other</var> can be a Point, or Segment</p></dd>
1032
+ <dt><a name="label-138" id="label-138"><code>contain?(<var>other</var>)</code></a></dt><!-- RDLabel: "contain?" -->
1033
+ <dd>
1034
+ return true if <var>self</var> contain <var>other</var></dd>
1035
+ <dt><a name="label-139" id="label-139"><code>contained?(<var>other</var>)</code></a></dt><!-- RDLabel: "contained?" -->
1036
+ <dd>
1037
+ return true if <var>self</var> is contained by <var>other</var></dd>
1038
+ <dt><a name="label-140" id="label-140"><code>diagonal</code></a></dt><!-- RDLabel: "diagonal" -->
1039
+ <dd>
1040
+ return a line Segment which happens to be the
1041
+ positive-slope diagonal of Box</dd>
1042
+ <dt><a name="label-141" id="label-141"><code>height</code></a></dt><!-- RDLabel: "height" -->
1043
+ <dd>
1044
+ return the height of the Box (vertical magnitude)</dd>
1045
+ <dt><a name="label-142" id="label-142"><code>in?(<var>other</var>)</code></a></dt><!-- RDLabel: "in?" -->
1046
+ <dd>
1047
+ return true if <var>self</var> is contained by <var>other</var></dd>
1048
+ <dt><a name="label-143" id="label-143"><code>initialize(*<var>args</var>)</code></a></dt><!-- RDLabel: "initialize" -->
1049
+ <dd>
1050
+ <p>create a new Box object</p>
1051
+ <p><var>args</var> can be 2 Point objects (low, high) or 4 Float objects
1052
+ (low.x, low.y, high.x, high.y)</p></dd>
1053
+ <dt><a name="label-144" id="label-144"><code>intersection(<var>other</var>)</code></a></dt><!-- RDLabel: "intersection" -->
1054
+ <dd>
1055
+ returns the overlapping portion of two boxes,
1056
+ or <var>nil</var> if they do not intersect.</dd>
1057
+ <dt><a name="label-145" id="label-145"><code>intersect?(<var>segment</var>)</code></a></dt><!-- RDLabel: "intersect?" -->
1058
+ <dd>
1059
+ <p>returns true if the Segment <var>segment</var>
1060
+ intersect with the Box</p>
1061
+ <p>Segment completely inside box counts as intersection.
1062
+ If you want only segments crossing box boundaries,
1063
+ try converting Box to Path first.</p></dd>
1064
+ <dt><a name="label-146" id="label-146"><code>left?(<var>other</var>)</code></a></dt><!-- RDLabel: "left?" -->
1065
+ <dd>
1066
+ return true if <var>self</var> is strictly left of <var>other</var></dd>
1067
+ <dt><a name="label-147" id="label-147"><code>overlap?(<var>other</var>)</code></a></dt><!-- RDLabel: "overlap?" -->
1068
+ <dd>
1069
+ return true if <var>self</var> overlap <var>other</var></dd>
1070
+ <dt><a name="label-148" id="label-148"><code>overleft?(<var>other</var>)</code></a></dt><!-- RDLabel: "overleft?" -->
1071
+ <dd>
1072
+ return true if the right edge of <var>self</var> is to the left of
1073
+ the right edge of <var>other</var></dd>
1074
+ <dt><a name="label-149" id="label-149"><code>overright?(<var>other</var>)</code></a></dt><!-- RDLabel: "overright?" -->
1075
+ <dd>
1076
+ return true if the left edge of <var>self</var> is to the right of
1077
+ the left edge of <var>other</var></dd>
1078
+ <dt><a name="label-150" id="label-150"><code>right?(<var>other</var>)</code></a></dt><!-- RDLabel: "right?" -->
1079
+ <dd>
1080
+ return true if <var>self</var> is strictly right of <var>other</var></dd>
1081
+ <dt><a name="label-151" id="label-151"><code>same?(<var>other</var>)</code></a></dt><!-- RDLabel: "same?" -->
1082
+ <dd>
1083
+ return true if the 2 boxes <var>self</var> and <var>other</var> are identical</dd>
1084
+ <dt><a name="label-152" id="label-152"><code>to_circle</code></a></dt><!-- RDLabel: "to_circle" -->
1085
+ <dd>
1086
+ convert a Box to a Circle</dd>
1087
+ <dt><a name="label-153" id="label-153"><code>to_point</code></a></dt><!-- RDLabel: "to_point" -->
1088
+ <dd>
1089
+ return the center Point of the Box</dd>
1090
+ <dt><a name="label-154" id="label-154"><code>to_polygon</code></a></dt><!-- RDLabel: "to_polygon" -->
1091
+ <dd>
1092
+ convert a Box to a Polygon</dd>
1093
+ <dt><a name="label-155" id="label-155"><code>to_segment</code></a></dt><!-- RDLabel: "to_segment" -->
1094
+ <dd>
1095
+ return a line Segment which happens to be the
1096
+ positive-slope diagonal of Box</dd>
1097
+ <dt><a name="label-156" id="label-156"><code>width</code></a></dt><!-- RDLabel: "width" -->
1098
+ <dd>
1099
+ return the width of the Box (horizontal magnitude)</dd>
1100
+ </dl>
1101
+ <h3><a name="label-157" id="label-157">class Path</a></h3><!-- RDLabel: "class Path" -->
1102
+ <p>The Path implement the PostgreSQL type <var>path</var></p>
1103
+ <p>The module Comparable is included</p>
1104
+ <dl>
1105
+ <dt><a name="label-158" id="label-158"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
1106
+ <dd>
1107
+ Convert a <var>String</var> (PostgreSQL representation)
1108
+ to a <var>Path</var></dd>
1109
+ <dt><a name="label-159" id="label-159"><code>&lt;&lt;(<var>path</var>)</code></a></dt><!-- RDLabel: "<<" -->
1110
+ <dd>
1111
+ concatenate the two paths (only if they are both open)</dd>
1112
+ <dt><a name="label-160" id="label-160"><code>+(<var>point</var>)</code></a></dt><!-- RDLabel: "+" -->
1113
+ <dd>
1114
+ translate (right, up) <var>self</var></dd>
1115
+ <dt><a name="label-161" id="label-161"><code>-(<var>point</var>)</code></a></dt><!-- RDLabel: "-" -->
1116
+ <dd>
1117
+ translate (left, down) <var>self</var></dd>
1118
+ <dt><a name="label-162" id="label-162"><code>*(<var>point</var>)</code></a></dt><!-- RDLabel: "*" -->
1119
+ <dd>
1120
+ scale and rotate <var>self</var></dd>
1121
+ <dt><a name="label-163" id="label-163"><code>/(<var>point</var>)</code></a></dt><!-- RDLabel: "/" -->
1122
+ <dd>
1123
+ scale and rotate <var>self</var></dd>
1124
+ <dt><a name="label-164" id="label-164"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
1125
+ <dd>
1126
+ comparison function based on the path cardinality, i.e.
1127
+ self.npoints &lt;=&gt; other.npoints</dd>
1128
+ <dt><a name="label-165" id="label-165"><code>close</code></a></dt><!-- RDLabel: "close" -->
1129
+ <dd>
1130
+ make a closed path</dd>
1131
+ <dt><a name="label-166" id="label-166"><code>closed?</code></a></dt><!-- RDLabel: "closed?" -->
1132
+ <dd>
1133
+ return true if <var>self</var> is a closed path</dd>
1134
+ <dt><a name="label-167" id="label-167"><code>concat(<var>path</var>)</code></a></dt><!-- RDLabel: "concat" -->
1135
+ <dd>
1136
+ concatenate the two paths (only if they are both open)</dd>
1137
+ <dt><a name="label-168" id="label-168"><code>initialize(<var>points</var>, <var>closed</var> = <var>false</var>)</code></a></dt><!-- RDLabel: "initialize" -->
1138
+ <dd>
1139
+ create a new Path object from the Array of Point <var>points</var></dd>
1140
+ <dt><a name="label-169" id="label-169"><code>length</code></a></dt><!-- RDLabel: "length" -->
1141
+ <dd>
1142
+ return the length of <var>self</var></dd>
1143
+ <dt><a name="label-170" id="label-170"><code>npoints</code></a></dt><!-- RDLabel: "npoints" -->
1144
+ <dd>
1145
+ return the path cardinality</dd>
1146
+ <dt><a name="label-171" id="label-171"><code>open</code></a></dt><!-- RDLabel: "open" -->
1147
+ <dd>
1148
+ make an open path</dd>
1149
+ <dt><a name="label-172" id="label-172"><code>to_polygon</code></a></dt><!-- RDLabel: "to_polygon" -->
1150
+ <dd>
1151
+ convert <var>self</var> to a Polygon object</dd>
1152
+ </dl>
1153
+ <h3><a name="label-173" id="label-173">class Point</a></h3><!-- RDLabel: "class Point" -->
1154
+ <p>The Point implement the PostgreSQL type <var>point</var></p>
1155
+ <p>The module Comparable is included</p>
1156
+ <dl>
1157
+ <dt><a name="label-174" id="label-174"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
1158
+ <dd>
1159
+ Convert a <var>String</var> (PostgreSQL representation)
1160
+ to a <var>Point</var></dd>
1161
+ <dt><a name="label-175" id="label-175"><code>+(<var>point</var>)</code></a></dt><!-- RDLabel: "+" -->
1162
+ <dd>
1163
+ translate (right, up) <var>self</var></dd>
1164
+ <dt><a name="label-176" id="label-176"><code>-(<var>point</var>)</code></a></dt><!-- RDLabel: "-" -->
1165
+ <dd>
1166
+ translate (left, down) <var>self</var></dd>
1167
+ <dt><a name="label-177" id="label-177"><code>*(<var>point</var>)</code></a></dt><!-- RDLabel: "*" -->
1168
+ <dd>
1169
+ scale and rotate <var>self</var></dd>
1170
+ <dt><a name="label-178" id="label-178"><code>/(<var>point</var>)</code></a></dt><!-- RDLabel: "/" -->
1171
+ <dd>
1172
+ scale and rotate <var>self</var></dd>
1173
+ <dt><a name="label-179" id="label-179"><code>[<var>indice</var>]</code></a></dt><!-- RDLabel: "[]" -->
1174
+ <dd>
1175
+ <p>return the coordinate</p>
1176
+ <p><var>indice</var> can have the value 0 or 1</p></dd>
1177
+ <dt><a name="label-180" id="label-180"><code>[<var>indice</var>] = <var>value</var></code></a></dt><!-- RDLabel: "[]=" -->
1178
+ <dd>
1179
+ <p>set the coordinate</p>
1180
+ <p><var>indice</var> can have the value 0 or 1</p></dd>
1181
+ <dt><a name="label-181" id="label-181"><code>==(<var>other</var>)</code></a></dt><!-- RDLabel: "==" -->
1182
+ <dd>
1183
+ return true if <var>self</var> and <var>other</var> are the same,
1184
+ i.e. self.x == other.x &amp;&amp; self.y == other.y</dd>
1185
+ <dt><a name="label-182" id="label-182"><code>above?(<var>other</var>)</code></a></dt><!-- RDLabel: "above?" -->
1186
+ <dd>
1187
+ return true if <var>self</var> is above <var>other</var>,
1188
+ i.e. self.y &gt; other.y</dd>
1189
+ <dt><a name="label-183" id="label-183"><code>below?(<var>other</var>)</code></a></dt><!-- RDLabel: "below?" -->
1190
+ <dd>
1191
+ return true if <var>self</var> is below <var>other</var>,
1192
+ i.e. self.y &lt; other.y</dd>
1193
+ <dt><a name="label-184" id="label-184"><code>contained?(<var>other</var>)</code></a></dt><!-- RDLabel: "contained?" -->
1194
+ <dd>
1195
+ <p>return true if <var>self</var> is contained in <var>other</var></p>
1196
+ <p><var>other</var> can be Point, Polygon or a Circle object</p></dd>
1197
+ <dt><a name="label-185" id="label-185"><code>horizontal?(<var>other</var>)</code></a></dt><!-- RDLabel: "horizontal?" -->
1198
+ <dd>
1199
+ return true if <var>self</var> and <var>other</var> are horizontal,
1200
+ i.e. self.y == other.y</dd>
1201
+ <dt><a name="label-186" id="label-186"><code>in?(<var>other</var>)</code></a></dt><!-- RDLabel: "in?" -->
1202
+ <dd>
1203
+ <p>return true if <var>self</var> is contained in <var>other</var></p>
1204
+ <p><var>other</var> can be Point, Polygon or a Circle object</p></dd>
1205
+ <dt><a name="label-187" id="label-187"><code>initialize(<var>x</var>, <var>y</var>)</code></a></dt><!-- RDLabel: "initialize" -->
1206
+ <dd>
1207
+ create a Point with the 2 Float object (x, y)</dd>
1208
+ <dt><a name="label-188" id="label-188"><code>left?(<var>other</var>)</code></a></dt><!-- RDLabel: "left?" -->
1209
+ <dd>
1210
+ return true if <var>self</var> is at the left of <var>other</var>,
1211
+ i.e. self.x &lt; other.x</dd>
1212
+ <dt><a name="label-189" id="label-189"><code>on?(<var>other</var>)</code></a></dt><!-- RDLabel: "on?" -->
1213
+ <dd>
1214
+ <p>return true if <var>self</var> is on <var>other</var></p>
1215
+ <p><var>other</var> can be Point, Segment, Box or Path object</p></dd>
1216
+ <dt><a name="label-190" id="label-190"><code>right?(<var>other</var>)</code></a></dt><!-- RDLabel: "right?" -->
1217
+ <dd>
1218
+ return true if <var>self</var> is at the right of <var>other</var>,
1219
+ i.e. self.x &gt; other.x</dd>
1220
+ <dt><a name="label-191" id="label-191"><code>vertical?(<var>other</var>)</code></a></dt><!-- RDLabel: "vertical?" -->
1221
+ <dd>
1222
+ return true if <var>self</var> and <var>other</var> are vertical,
1223
+ i.e. self.x == other.x</dd>
1224
+ <dt><a name="label-192" id="label-192"><code>x</code></a></dt><!-- RDLabel: "x" -->
1225
+ <dd>
1226
+ return <var>x</var> for <var>self</var></dd>
1227
+ <dt><a name="label-193" id="label-193"><code>x=(<var>value</var>)</code></a></dt><!-- RDLabel: "x=" -->
1228
+ <dd>
1229
+ set the <var>x</var> value for <var>self</var></dd>
1230
+ <dt><a name="label-194" id="label-194"><code>y</code></a></dt><!-- RDLabel: "y" -->
1231
+ <dd>
1232
+ return <var>y</var> for <var>self</var></dd>
1233
+ <dt><a name="label-195" id="label-195"><code>y=(<var>value</var>)</code></a></dt><!-- RDLabel: "y=" -->
1234
+ <dd>
1235
+ set the <var>y</var> value for <var>self</var></dd>
1236
+ </dl>
1237
+ <h3><a name="label-196" id="label-196">class Segment</a></h3><!-- RDLabel: "class Segment" -->
1238
+ <p>The Segment implement the PostgreSQL type <var>lseg</var></p>
1239
+ <p>The module Comparable is included</p>
1240
+ <dl>
1241
+ <dt><a name="label-197" id="label-197"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
1242
+ <dd>
1243
+ Convert a <var>String</var> (PostgreSQL representation)
1244
+ to a <var>Segment</var></dd>
1245
+ <dt><a name="label-198" id="label-198"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
1246
+ <dd>
1247
+ <p>comparison function for the 2 segments, returns</p>
1248
+ <pre>0 if self[0] == other[0] &amp;&amp; self[1] == other[1]
1249
+
1250
+ 1 if distance(self[0], self[1]) &gt; distance(other[0], other[1])
1251
+
1252
+ -1 if distance(self[0], self[1]) &lt; distance(other[0], other[1]) </pre></dd>
1253
+ <dt><a name="label-199" id="label-199"><code>center</code></a></dt><!-- RDLabel: "center" -->
1254
+ <dd>
1255
+ return the center of the segment</dd>
1256
+ <dt><a name="label-200" id="label-200"><code>closest(<var>other</var>)</code></a></dt><!-- RDLabel: "closest" -->
1257
+ <dd>
1258
+ <p>closest point to other</p>
1259
+ <p><var>other</var> can be a Point, Segment or Box</p>
1260
+ <p>With a point, take the closest endpoint
1261
+ if the point is left, right, above, or below the segment, otherwise
1262
+ find the intersection point of the segment and its perpendicular through
1263
+ the point.</p></dd>
1264
+ <dt><a name="label-201" id="label-201"><code>horizontal?</code></a></dt><!-- RDLabel: "horizontal?" -->
1265
+ <dd>
1266
+ returns true if <var>self</var> is a horizontal Segment</dd>
1267
+ <dt><a name="label-202" id="label-202"><code>initialize(<var>point0</var>, <var>point1</var>)</code></a></dt><!-- RDLabel: "initialize" -->
1268
+ <dd>
1269
+ create a Segment from the 2 Point p0, p1</dd>
1270
+ <dt><a name="label-203" id="label-203"><code>intersect?(<var>other</var>)</code></a></dt><!-- RDLabel: "intersect?" -->
1271
+ <dd>
1272
+ returns true if <var>self</var> and <var>other</var> intersect</dd>
1273
+ <dt><a name="label-204" id="label-204"><code>intersection(<var>other</var>)</code></a></dt><!-- RDLabel: "intersection" -->
1274
+ <dd>
1275
+ returns the Point where the 2 Segment <var>self</var> and <var>other</var>
1276
+ intersect or nil</dd>
1277
+ <dt><a name="label-205" id="label-205"><code>length</code></a></dt><!-- RDLabel: "length" -->
1278
+ <dd>
1279
+ return the length of <var>self</var>, i.e. the distnace between the 2 points</dd>
1280
+ <dt><a name="label-206" id="label-206"><code>on?(<var>other</var>)</code></a></dt><!-- RDLabel: "on?" -->
1281
+ <dd>
1282
+ <p>return true if <var>self</var> is on <var>other</var></p>
1283
+ <p><var>other</var> can be a Segment, or a Box object</p></dd>
1284
+ <dt><a name="label-207" id="label-207"><code>parallel?(<var>other</var>)</code></a></dt><!-- RDLabel: "parallel?" -->
1285
+ <dd>
1286
+ returns true if the 2 Segment <var>self</var> and <var>other</var>
1287
+ are parallel</dd>
1288
+ <dt><a name="label-208" id="label-208"><code>perpendicular?(<var>other</var>)</code></a></dt><!-- RDLabel: "perpendicular?" -->
1289
+ <dd>
1290
+ returns true if <var>self</var> is perpendicular to <var>other</var></dd>
1291
+ <dt><a name="label-209" id="label-209"><code>to_point</code></a></dt><!-- RDLabel: "to_point" -->
1292
+ <dd>
1293
+ conversion function to a Point, return the center of the segment</dd>
1294
+ <dt><a name="label-210" id="label-210"><code>vertical?</code></a></dt><!-- RDLabel: "vertical?" -->
1295
+ <dd>
1296
+ returns true if <var>self</var> is a vertical Segment</dd>
1297
+ </dl>
1298
+ <h3><a name="label-211" id="label-211">class Polygon</a></h3><!-- RDLabel: "class Polygon" -->
1299
+ <p>The Polygon implement the PostgreSQL type <var>polygon</var></p>
1300
+ <dl>
1301
+ <dt><a name="label-212" id="label-212"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
1302
+ <dd>
1303
+ Convert a <var>String</var> (PostgreSQL representation)
1304
+ to a <var>Polygon</var></dd>
1305
+ <dt><a name="label-213" id="label-213"><code>==(<var>other</var>)</code></a></dt><!-- RDLabel: "==" -->
1306
+ <dd>
1307
+ return true if <var>self</var> is the same as <var>other</var>, i.e. all
1308
+ the points are the same</dd>
1309
+ <dt><a name="label-214" id="label-214"><code>center</code></a></dt><!-- RDLabel: "center" -->
1310
+ <dd>
1311
+ return the center of <var>self</var>, i.e. create a circle and return its
1312
+ center</dd>
1313
+ <dt><a name="label-215" id="label-215"><code>contain?(<var>other</var>)</code></a></dt><!-- RDLabel: "contain?" -->
1314
+ <dd>
1315
+ <p>return true if <var>self</var> contains <var>other</var></p>
1316
+ <p><var>other</var> can be a Point or a Polygon</p></dd>
1317
+ <dt><a name="label-216" id="label-216"><code>contained?(<var>other</var>)</code></a></dt><!-- RDLabel: "contained?" -->
1318
+ <dd>
1319
+ return true if <var>self</var> is contained in <var>other</var> by determining
1320
+ if <var>self</var> bounding box is contained by <var>other</var>'s bounding box.</dd>
1321
+ <dt><a name="label-217" id="label-217"><code>in?(<var>other</var>)</code></a></dt><!-- RDLabel: "in?" -->
1322
+ <dd>
1323
+ return true if <var>self</var> is contained in <var>other</var> by determining
1324
+ if <var>self</var> bounding box is contained by <var>other</var>'s bounding box.</dd>
1325
+ <dt><a name="label-218" id="label-218"><code>initialize(<var>points</var>, <var>closed</var> = <var>false</var>)</code></a></dt><!-- RDLabel: "initialize" -->
1326
+ <dd>
1327
+ create a new Polygon object from the Array of Point <var>points</var></dd>
1328
+ <dt><a name="label-219" id="label-219"><code>left?(<var>other</var>)</code></a></dt><!-- RDLabel: "left?" -->
1329
+ <dd>
1330
+ return true if <var>self</var> is strictly left of <var>other</var>, i.e.
1331
+ the right most point of <var>self</var> is left of the left
1332
+ most point of <var>other</var></dd>
1333
+ <dt><a name="label-220" id="label-220"><code>overleft?(<var>other</var>)</code></a></dt><!-- RDLabel: "overleft?" -->
1334
+ <dd>
1335
+ return true if <var>self</var> is overlapping or left of <var>other</var>,
1336
+ i.e. the left most point of <var>self</var> is left of the right
1337
+ most point of <var>other</var></dd>
1338
+ <dt><a name="label-221" id="label-221"><code>overright?(<var>other</var>)</code></a></dt><!-- RDLabel: "overright?" -->
1339
+ <dd>
1340
+ return true if <var>self</var> is overlapping or right of <var>other</var>,
1341
+ i.e. the right most point of <var>self</var> is right of the left
1342
+ most point of <var>other</var></dd>
1343
+ <dt><a name="label-222" id="label-222"><code>overlap?(<var>other</var>)</code></a></dt><!-- RDLabel: "overlap?" -->
1344
+ <dd>
1345
+ return true if <var>self</var> and <var>other</var> overlap by determining if
1346
+ their bounding boxes overlap.</dd>
1347
+ <dt><a name="label-223" id="label-223"><code>npoints</code></a></dt><!-- RDLabel: "npoints" -->
1348
+ <dd>
1349
+ return the number of points in <var>self</var></dd>
1350
+ <dt><a name="label-224" id="label-224"><code>right?(<var>other</var>)</code></a></dt><!-- RDLabel: "right?" -->
1351
+ <dd>
1352
+ return true if <var>self</var> is strictly right of <var>other</var>, i.e.
1353
+ the left most point of <var>self</var> is right of the left
1354
+ most point of <var>other</var></dd>
1355
+ <dt><a name="label-225" id="label-225"><code>same?(<var>other</var>)</code></a></dt><!-- RDLabel: "same?" -->
1356
+ <dd>
1357
+ return true if <var>self</var> is the same as <var>other</var>, i.e. all
1358
+ the points are the same</dd>
1359
+ <dt><a name="label-226" id="label-226"><code>to_box</code></a></dt><!-- RDLabel: "to_box" -->
1360
+ <dd>
1361
+ convert <var>self</var> to a Box</dd>
1362
+ <dt><a name="label-227" id="label-227"><code>to_circle</code></a></dt><!-- RDLabel: "to_circle" -->
1363
+ <dd>
1364
+ convert <var>self</var> to a Circle</dd>
1365
+ <dt><a name="label-228" id="label-228"><code>to_path</code></a></dt><!-- RDLabel: "to_path" -->
1366
+ <dd>
1367
+ convert <var>self</var> to a Path</dd>
1368
+ <dt><a name="label-229" id="label-229"><code>to_point</code></a></dt><!-- RDLabel: "to_point" -->
1369
+ <dd>
1370
+ convert <var>self</var> to a Point by returning its center</dd>
1371
+ </dl>
1372
+ <h3><a name="label-230" id="label-230">class Circle</a></h3><!-- RDLabel: "class Circle" -->
1373
+ <p>The Circle implement the PostgreSQL type <var>circle</var></p>
1374
+ <p>The module Comparable is included</p>
1375
+ <dl>
1376
+ <dt><a name="label-231" id="label-231"><code>from_string(<var>string</var>)</code></a></dt><!-- RDLabel: "from_string" -->
1377
+ <dd>
1378
+ Convert a <var>String</var> (PostgreSQL representation)
1379
+ to a <var>Circle</var></dd>
1380
+ <dt><a name="label-232" id="label-232"><code>+(<var>point</var>)</code></a></dt><!-- RDLabel: "+" -->
1381
+ <dd>
1382
+ translate (right, up) <var>self</var></dd>
1383
+ <dt><a name="label-233" id="label-233"><code>-(<var>point</var>)</code></a></dt><!-- RDLabel: "-" -->
1384
+ <dd>
1385
+ translate (left, down) <var>self</var></dd>
1386
+ <dt><a name="label-234" id="label-234"><code>*(<var>point</var>)</code></a></dt><!-- RDLabel: "*" -->
1387
+ <dd>
1388
+ scale and rotate <var>self</var></dd>
1389
+ <dt><a name="label-235" id="label-235"><code>/(<var>point</var>)</code></a></dt><!-- RDLabel: "/" -->
1390
+ <dd>
1391
+ scale and rotate <var>self</var></dd>
1392
+ <dt><a name="label-236" id="label-236"><code>&lt;=&gt;(<var>other</var>)</code></a></dt><!-- RDLabel: "<=>" -->
1393
+ <dd>
1394
+ comparison function based on area,
1395
+ i.e. self.area &lt;=&gt; other.area</dd>
1396
+ <dt><a name="label-237" id="label-237"><code>area</code></a></dt><!-- RDLabel: "area" -->
1397
+ <dd>
1398
+ return the area</dd>
1399
+ <dt><a name="label-238" id="label-238"><code>above?(<var>other</var>)</code></a></dt><!-- RDLabel: "above?" -->
1400
+ <dd>
1401
+ return true if <var>self</var> is entirely above <var>other</var></dd>
1402
+ <dt><a name="label-239" id="label-239"><code>below?(<var>other</var>)</code></a></dt><!-- RDLabel: "below?" -->
1403
+ <dd>
1404
+ return true if <var>self</var> is entirely below <var>other</var></dd>
1405
+ <dt><a name="label-240" id="label-240"><code>contain?(<var>other</var>)</code></a></dt><!-- RDLabel: "contain?" -->
1406
+ <dd>
1407
+ return true if <var>self</var> contain <var>other</var></dd>
1408
+ <dt><a name="label-241" id="label-241"><code>contained?(<var>other</var>)</code></a></dt><!-- RDLabel: "contained?" -->
1409
+ <dd>
1410
+ return true if <var>self</var> is contained in <var>other</var></dd>
1411
+ <dt><a name="label-242" id="label-242"><code>diameter</code></a></dt><!-- RDLabel: "diameter" -->
1412
+ <dd>
1413
+ return the diameter</dd>
1414
+ <dt><a name="label-243" id="label-243"><code>initialize(<var>center</var>, <var>radius</var>)</code></a></dt><!-- RDLabel: "initialize" -->
1415
+ <dd>
1416
+ <p>create a Circle object with <var>center</var> and <var>radius</var></p>
1417
+ <p><var>center</var> can be a Point or an Array [x, y]</p></dd>
1418
+ <dt><a name="label-244" id="label-244"><code>overlap?(<var>other</var>)</code></a></dt><!-- RDLabel: "overlap?" -->
1419
+ <dd>
1420
+ return true if <var>self</var> overlap <var>other</var></dd>
1421
+ <dt><a name="label-245" id="label-245"><code>overleft?(<var>other</var>)</code></a></dt><!-- RDLabel: "overleft?" -->
1422
+ <dd>
1423
+ return true if the right edge of <var>self</var> is to the left of
1424
+ the right edge of <var>other</var></dd>
1425
+ <dt><a name="label-246" id="label-246"><code>left?(<var>other</var>)</code></a></dt><!-- RDLabel: "left?" -->
1426
+ <dd>
1427
+ return true if <var>self</var> is strictly left of <var>other</var></dd>
1428
+ <dt><a name="label-247" id="label-247"><code>overright?(<var>other</var>)</code></a></dt><!-- RDLabel: "overright?" -->
1429
+ <dd>
1430
+ return true if the left edge of <var>self</var> is to the right of
1431
+ the left edge of <var>other</var></dd>
1432
+ <dt><a name="label-248" id="label-248"><code>radius</code></a></dt><!-- RDLabel: "radius" -->
1433
+ <dd>
1434
+ return the radius</dd>
1435
+ <dt><a name="label-249" id="label-249"><code>right?(<var>other</var>)</code></a></dt><!-- RDLabel: "right?" -->
1436
+ <dd>
1437
+ return true if <var>self</var> is strictly right of <var>other</var></dd>
1438
+ <dt><a name="label-250" id="label-250"><code>same?(<var>other</var>)</code></a></dt><!-- RDLabel: "same?" -->
1439
+ <dd>
1440
+ return true if <var>self</var> is the same than <var>other</var>, i.e.
1441
+ self.center == other.center &amp;&amp; self.radius == other.radius</dd>
1442
+ <dt><a name="label-251" id="label-251"><code>to_box</code></a></dt><!-- RDLabel: "to_box" -->
1443
+ <dd>
1444
+ convert <var>self</var> to a Box</dd>
1445
+ <dt><a name="label-252" id="label-252"><code>to_point</code></a></dt><!-- RDLabel: "to_point" -->
1446
+ <dd>
1447
+ convert <var>self</var> to a Point by returning its center</dd>
1448
+ <dt><a name="label-253" id="label-253"><code>to_polygon(<var>npts</var>)</code></a></dt><!-- RDLabel: "to_polygon" -->
1449
+ <dd>
1450
+ convert <var>self</var> to a Polygon with <var>npts</var> Points</dd>
1451
+ </dl>
1452
+
1453
+ </body>
1454
+ </html>