pg 0.9.0.pre156-x86-mswin32
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.
- data/BSD +23 -0
- data/ChangeLog +471 -0
- data/Contributors +30 -0
- data/GPL +340 -0
- data/LICENSE +58 -0
- data/README +68 -0
- data/README.OS_X +19 -0
- data/README.ja +183 -0
- data/README.windows +72 -0
- data/Rakefile.local +239 -0
- data/ext/compat.c +541 -0
- data/ext/compat.h +180 -0
- data/ext/extconf.rb +126 -0
- data/ext/pg.c +4250 -0
- data/ext/pg.h +49 -0
- data/lib/1.8/pg_ext.so +0 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/pg.rb +11 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/helpers.rb +435 -0
- data/rake/hg.rb +273 -0
- data/rake/manual.rb +782 -0
- data/rake/packaging.rb +123 -0
- data/rake/publishing.rb +274 -0
- data/rake/rdoc.rb +30 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/lib/helpers.rb +216 -0
- data/spec/m17n_spec.rb +139 -0
- data/spec/pgconn_spec.rb +291 -0
- data/spec/pgresult_spec.rb +218 -0
- metadata +113 -0
data/spec/m17n_spec.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
#!/usr/bin/env spec
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
require 'rbconfig'
|
7
|
+
|
8
|
+
basedir = Pathname( __FILE__ ).dirname.parent
|
9
|
+
libdir = basedir + 'lib'
|
10
|
+
archlib = libdir + Config::CONFIG['sitearch']
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
13
|
+
$LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
|
14
|
+
}
|
15
|
+
|
16
|
+
require 'pg'
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'spec'
|
20
|
+
require 'spec/lib/helpers'
|
21
|
+
|
22
|
+
describe "multinationalization support" do
|
23
|
+
include PgTestingHelpers
|
24
|
+
|
25
|
+
RUBY_VERSION_VEC = RUBY_VERSION.split('.').map {|c| c.to_i }.pack("N*")
|
26
|
+
MIN_RUBY_VERSION_VEC = [1,9,1].pack('N*')
|
27
|
+
|
28
|
+
|
29
|
+
before( :all ) do
|
30
|
+
@conn = nil
|
31
|
+
if RUBY_VERSION_VEC >= MIN_RUBY_VERSION_VEC
|
32
|
+
@conn = setup_testing_db( "m17n" )
|
33
|
+
@conn.exec( 'BEGIN' )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
before( :each ) do
|
38
|
+
pending "depends on m17n support in Ruby >= 1.9.1" if @conn.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
it "should return the same bytes in text format that are sent as inline text" do
|
43
|
+
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
44
|
+
in_bytes = File.open(binary_file, 'r:ASCII-8BIT').read
|
45
|
+
|
46
|
+
out_bytes = nil
|
47
|
+
@conn.transaction do |conn|
|
48
|
+
conn.exec("SET standard_conforming_strings=on")
|
49
|
+
res = conn.exec("VALUES ('#{PGconn.escape_bytea(in_bytes)}'::bytea)", [], 0)
|
50
|
+
out_bytes = PGconn.unescape_bytea(res[0]['column1'])
|
51
|
+
end
|
52
|
+
out_bytes.should== in_bytes
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "rubyforge #22925: m17n support" do
|
56
|
+
it "should return results in the same encoding as the client (iso-8859-1)" do
|
57
|
+
out_string = nil
|
58
|
+
@conn.transaction do |conn|
|
59
|
+
conn.internal_encoding = 'iso8859-1'
|
60
|
+
res = conn.exec("VALUES ('fantasia')", [], 0)
|
61
|
+
out_string = res[0]['column1']
|
62
|
+
end
|
63
|
+
out_string.should == 'fantasia'
|
64
|
+
out_string.encoding.should == Encoding::ISO8859_1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return results in the same encoding as the client (utf-8)" do
|
68
|
+
out_string = nil
|
69
|
+
@conn.transaction do |conn|
|
70
|
+
conn.internal_encoding = 'utf-8'
|
71
|
+
res = conn.exec("VALUES ('世界線航跡蔵')", [], 0)
|
72
|
+
out_string = res[0]['column1']
|
73
|
+
end
|
74
|
+
out_string.should == '世界線航跡蔵'
|
75
|
+
out_string.encoding.should == Encoding::UTF_8
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should return results in the same encoding as the client (EUC-JP)" do
|
79
|
+
out_string = nil
|
80
|
+
@conn.transaction do |conn|
|
81
|
+
conn.internal_encoding = 'EUC-JP'
|
82
|
+
stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
|
83
|
+
res = conn.exec(stmt, [], 0)
|
84
|
+
out_string = res[0]['column1']
|
85
|
+
end
|
86
|
+
out_string.should == '世界線航跡蔵'.encode('EUC-JP')
|
87
|
+
out_string.encoding.should == Encoding::EUC_JP
|
88
|
+
end
|
89
|
+
|
90
|
+
it "returns the results in the correct encoding even if the client_encoding has " +
|
91
|
+
"changed since the results were fetched" do
|
92
|
+
out_string = nil
|
93
|
+
@conn.transaction do |conn|
|
94
|
+
conn.internal_encoding = 'EUC-JP'
|
95
|
+
stmt = "VALUES ('世界線航跡蔵')".encode('EUC-JP')
|
96
|
+
res = conn.exec(stmt, [], 0)
|
97
|
+
conn.internal_encoding = 'utf-8'
|
98
|
+
out_string = res[0]['column1']
|
99
|
+
end
|
100
|
+
out_string.should == '世界線航跡蔵'.encode('EUC-JP')
|
101
|
+
out_string.encoding.should == Encoding::EUC_JP
|
102
|
+
end
|
103
|
+
|
104
|
+
it "the connection should return ASCII-8BIT when the server encoding is SQL_ASCII" do
|
105
|
+
@conn.external_encoding.should == Encoding::ASCII_8BIT
|
106
|
+
end
|
107
|
+
|
108
|
+
it "works around the unsupported JOHAB encoding by returning stuff in 'ASCII_8BIT'" do
|
109
|
+
pending "figuring out how to create a string in the JOHAB encoding" do
|
110
|
+
out_string = nil
|
111
|
+
@conn.transaction do |conn|
|
112
|
+
conn.exec( "set client_encoding = 'JOHAB';" )
|
113
|
+
stmt = "VALUES ('foo')".encode('JOHAB')
|
114
|
+
res = conn.exec( stmt, [], 0 )
|
115
|
+
out_string = res[0]['column1']
|
116
|
+
end
|
117
|
+
out_string.should == 'foo'.encode(Encoding::ASCII_8BIT)
|
118
|
+
out_string.encoding.should == Encoding::ASCII_8BIT
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should use client encoding for escaped string" do
|
123
|
+
original = "string to escape".force_encoding("euc-jp")
|
124
|
+
@conn.set_client_encoding("euc_jp")
|
125
|
+
escaped = @conn.escape(original)
|
126
|
+
escaped.encoding.should == Encoding::EUC_JP
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
after( :each ) do
|
133
|
+
@conn.exec( 'ROLLBACK' ) if @conn
|
134
|
+
end
|
135
|
+
|
136
|
+
after( :all ) do
|
137
|
+
teardown_testing_db( @conn ) if @conn
|
138
|
+
end
|
139
|
+
end
|
data/spec/pgconn_spec.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
#!/usr/bin/env spec
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
require 'rbconfig'
|
7
|
+
|
8
|
+
basedir = Pathname( __FILE__ ).dirname.parent
|
9
|
+
libdir = basedir + 'lib'
|
10
|
+
archlib = libdir + Config::CONFIG['sitearch']
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
13
|
+
$LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
|
14
|
+
}
|
15
|
+
|
16
|
+
require 'pg'
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'spec'
|
20
|
+
require 'spec/lib/helpers'
|
21
|
+
require 'timeout'
|
22
|
+
|
23
|
+
describe PGconn do
|
24
|
+
include PgTestingHelpers
|
25
|
+
|
26
|
+
before( :all ) do
|
27
|
+
@conn = setup_testing_db( "PGconn" )
|
28
|
+
end
|
29
|
+
|
30
|
+
before( :each ) do
|
31
|
+
@conn.exec( 'BEGIN' )
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
it "should connect successfully with connection string" do
|
36
|
+
tmpconn = PGconn.connect(@conninfo)
|
37
|
+
tmpconn.status.should== PGconn::CONNECTION_OK
|
38
|
+
tmpconn.finish
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should connect using 7 arguments converted to strings" do
|
42
|
+
tmpconn = PGconn.connect('localhost', @port, nil, nil, :test, nil, nil)
|
43
|
+
tmpconn.status.should== PGconn::CONNECTION_OK
|
44
|
+
tmpconn.finish
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should connect using hash" do
|
48
|
+
tmpconn = PGconn.connect(
|
49
|
+
:host => 'localhost',
|
50
|
+
:port => @port,
|
51
|
+
:dbname => :test)
|
52
|
+
tmpconn.status.should== PGconn::CONNECTION_OK
|
53
|
+
tmpconn.finish
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should connect asynchronously" do
|
57
|
+
tmpconn = PGconn.connect_start(@conninfo)
|
58
|
+
socket = IO.for_fd(tmpconn.socket)
|
59
|
+
status = tmpconn.connect_poll
|
60
|
+
while(status != PGconn::PGRES_POLLING_OK) do
|
61
|
+
if(status == PGconn::PGRES_POLLING_READING)
|
62
|
+
if(not select([socket],[],[],5.0))
|
63
|
+
raise "Asynchronous connection timed out!"
|
64
|
+
end
|
65
|
+
elsif(status == PGconn::PGRES_POLLING_WRITING)
|
66
|
+
if(not select([],[socket],[],5.0))
|
67
|
+
raise "Asynchronous connection timed out!"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
status = tmpconn.connect_poll
|
71
|
+
end
|
72
|
+
tmpconn.status.should== PGconn::CONNECTION_OK
|
73
|
+
tmpconn.finish
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not leave stale server connections after finish" do
|
77
|
+
PGconn.connect(@conninfo).finish
|
78
|
+
sleep 0.5
|
79
|
+
res = @conn.exec(%[SELECT COUNT(*) AS n FROM pg_stat_activity
|
80
|
+
WHERE usename IS NOT NULL])
|
81
|
+
# there's still the global @conn, but should be no more
|
82
|
+
res[0]['n'].should == '1'
|
83
|
+
end
|
84
|
+
|
85
|
+
unless RUBY_PLATFORM =~ /mswin|mingw/
|
86
|
+
it "should trace and untrace client-server communication" do
|
87
|
+
# be careful to explicitly close files so that the
|
88
|
+
# directory can be removed and we don't have to wait for
|
89
|
+
# the GC to run.
|
90
|
+
expected_trace_file = File.join(Dir.getwd, "spec/data", "expected_trace.out")
|
91
|
+
expected_trace_data = open(expected_trace_file, 'rb').read
|
92
|
+
trace_file = open(File.join(@test_directory, "test_trace.out"), 'wb')
|
93
|
+
@conn.trace(trace_file)
|
94
|
+
trace_file.close
|
95
|
+
res = @conn.exec("SELECT 1 AS one")
|
96
|
+
@conn.untrace
|
97
|
+
res = @conn.exec("SELECT 2 AS two")
|
98
|
+
trace_file = open(File.join(@test_directory, "test_trace.out"), 'rb')
|
99
|
+
trace_data = trace_file.read
|
100
|
+
trace_file.close
|
101
|
+
trace_data.should == expected_trace_data
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should cancel a query" do
|
106
|
+
error = false
|
107
|
+
@conn.send_query("SELECT pg_sleep(1000)")
|
108
|
+
@conn.cancel
|
109
|
+
tmpres = @conn.get_result
|
110
|
+
if(tmpres.result_status != PGresult::PGRES_TUPLES_OK)
|
111
|
+
error = true
|
112
|
+
end
|
113
|
+
error.should == true
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should not read past the end of a large object" do
|
117
|
+
@conn.transaction do
|
118
|
+
oid = @conn.lo_create( 0 )
|
119
|
+
fd = @conn.lo_open( oid, PGconn::INV_READ|PGconn::INV_WRITE )
|
120
|
+
@conn.lo_write( fd, "foobar" )
|
121
|
+
@conn.lo_read( fd, 10 ).should be_nil()
|
122
|
+
@conn.lo_lseek( fd, 0, PGconn::SEEK_SET )
|
123
|
+
@conn.lo_read( fd, 10 ).should == 'foobar'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
it "should wait for NOTIFY events via select()" do
|
129
|
+
@conn.exec( 'ROLLBACK' )
|
130
|
+
@conn.exec( 'LISTEN woo' )
|
131
|
+
|
132
|
+
pid = fork do
|
133
|
+
conn = PGconn.connect( @conninfo )
|
134
|
+
sleep 1
|
135
|
+
conn.exec( 'NOTIFY woo' )
|
136
|
+
conn.finish
|
137
|
+
exit!
|
138
|
+
end
|
139
|
+
|
140
|
+
@conn.wait_for_notify( 10 ).should == 'woo'
|
141
|
+
@conn.exec( 'UNLISTEN woo' )
|
142
|
+
|
143
|
+
Process.wait( pid )
|
144
|
+
end
|
145
|
+
|
146
|
+
it "yields the result if block is given to exec" do
|
147
|
+
rval = @conn.exec( "select 1234::int as a union select 5678::int as a" ) do |result|
|
148
|
+
values = []
|
149
|
+
result.should be_kind_of( PGresult )
|
150
|
+
result.ntuples.should == 2
|
151
|
+
result.each do |tuple|
|
152
|
+
values << tuple['a']
|
153
|
+
end
|
154
|
+
values
|
155
|
+
end
|
156
|
+
|
157
|
+
rval.should have( 2 ).members
|
158
|
+
rval.should include( '5678', '1234' )
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
it "correctly finishes COPY queries passed to #async_exec" do
|
163
|
+
@conn.async_exec( "COPY (SELECT 1 UNION ALL SELECT 2) TO STDOUT" )
|
164
|
+
|
165
|
+
results = []
|
166
|
+
begin
|
167
|
+
data = @conn.get_copy_data( true )
|
168
|
+
if false == data
|
169
|
+
@conn.block( 2.0 )
|
170
|
+
data = @conn.get_copy_data( true )
|
171
|
+
end
|
172
|
+
results << data if data
|
173
|
+
end until data.nil?
|
174
|
+
|
175
|
+
results.should have( 2 ).members
|
176
|
+
results.should include( "1\n", "2\n" )
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
it "PGconn#block shouldn't block a second thread" do
|
181
|
+
t = Thread.new do
|
182
|
+
@conn.send_query( "select pg_sleep(3)" )
|
183
|
+
@conn.block
|
184
|
+
end
|
185
|
+
|
186
|
+
# :FIXME: There's a race here, but hopefully it's pretty small.
|
187
|
+
t.should be_alive()
|
188
|
+
|
189
|
+
@conn.cancel
|
190
|
+
t.join
|
191
|
+
end
|
192
|
+
|
193
|
+
it "PGconn#block should allow a timeout" do
|
194
|
+
@conn.send_query( "select pg_sleep(3)" )
|
195
|
+
|
196
|
+
start = Time.now
|
197
|
+
@conn.block( 0.1 )
|
198
|
+
finish = Time.now
|
199
|
+
|
200
|
+
(finish - start).should be_close( 0.1, 0.05 )
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
it "can encrypt a string given a password and username" do
|
205
|
+
PGconn.encrypt_password("postgres", "postgres").
|
206
|
+
should =~ /\S+/
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
it "raises an appropriate error if either of the required arguments for encrypt_password " +
|
211
|
+
"is not valid" do
|
212
|
+
expect {
|
213
|
+
PGconn.encrypt_password( nil, nil )
|
214
|
+
}.to raise_error( TypeError )
|
215
|
+
expect {
|
216
|
+
PGconn.encrypt_password( "postgres", nil )
|
217
|
+
}.to raise_error( TypeError )
|
218
|
+
expect {
|
219
|
+
PGconn.encrypt_password( nil, "postgres" )
|
220
|
+
}.to raise_error( TypeError )
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
it "allows fetching a column of values from a result by column number" do
|
225
|
+
res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
|
226
|
+
res.column_values( 0 ).should == %w[1 2 3]
|
227
|
+
res.column_values( 1 ).should == %w[2 3 4]
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
it "allows fetching a column of values from a result by field name" do
|
232
|
+
res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
|
233
|
+
res.field_values( 'column1' ).should == %w[1 2 3]
|
234
|
+
res.field_values( 'column2' ).should == %w[2 3 4]
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
it "raises an error if selecting an invalid column index" do
|
239
|
+
res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
|
240
|
+
expect {
|
241
|
+
res.column_values( 20 )
|
242
|
+
}.to raise_error( IndexError )
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
it "raises an error if selecting an invalid field name" do
|
247
|
+
res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
|
248
|
+
expect {
|
249
|
+
res.field_values( 'hUUuurrg' )
|
250
|
+
}.to raise_error( IndexError )
|
251
|
+
end
|
252
|
+
|
253
|
+
|
254
|
+
it "raises an error if column index is not a number" do
|
255
|
+
res = @conn.exec( 'VALUES (1,2),(2,3),(3,4)' )
|
256
|
+
expect {
|
257
|
+
res.column_values( 'hUUuurrg' )
|
258
|
+
}.to raise_error( TypeError )
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
it "can connect asynchronously" do
|
263
|
+
serv = TCPServer.new( '127.0.0.1', 54320 )
|
264
|
+
conn = PGconn.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
|
265
|
+
conn.connect_poll.should == PGconn::PGRES_POLLING_WRITING
|
266
|
+
select( nil, [IO.for_fd(conn.socket)], nil, 0.2 )
|
267
|
+
serv.close
|
268
|
+
if conn.connect_poll == PGconn::PGRES_POLLING_READING
|
269
|
+
select( [IO.for_fd(conn.socket)], nil, nil, 0.2 )
|
270
|
+
end
|
271
|
+
conn.connect_poll.should == PGconn::PGRES_POLLING_FAILED
|
272
|
+
end
|
273
|
+
|
274
|
+
it "discards previous results (if any) before waiting on an #async_exec"
|
275
|
+
|
276
|
+
it "calls the block if one is provided to #async_exec" do
|
277
|
+
result = nil
|
278
|
+
@conn.async_exec( "select 47 as one" ) do |pg_res|
|
279
|
+
result = pg_res[0]
|
280
|
+
end
|
281
|
+
result.should == { 'one' => '47' }
|
282
|
+
end
|
283
|
+
|
284
|
+
after( :each ) do
|
285
|
+
@conn.exec( 'ROLLBACK' )
|
286
|
+
end
|
287
|
+
|
288
|
+
after( :all ) do
|
289
|
+
teardown_testing_db( @conn )
|
290
|
+
end
|
291
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
#!/usr/bin/env spec
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
require 'rbconfig'
|
7
|
+
|
8
|
+
basedir = Pathname( __FILE__ ).dirname.parent
|
9
|
+
libdir = basedir + 'lib'
|
10
|
+
archlib = libdir + Config::CONFIG['sitearch']
|
11
|
+
|
12
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
13
|
+
$LOAD_PATH.unshift( archlib.to_s ) unless $LOAD_PATH.include?( archlib.to_s )
|
14
|
+
}
|
15
|
+
|
16
|
+
require 'pg'
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'spec'
|
20
|
+
require 'spec/lib/helpers'
|
21
|
+
|
22
|
+
describe PGresult do
|
23
|
+
include PgTestingHelpers
|
24
|
+
|
25
|
+
before( :all ) do
|
26
|
+
@conn = setup_testing_db( "PGresult" )
|
27
|
+
end
|
28
|
+
|
29
|
+
before( :each ) do
|
30
|
+
@conn.exec( 'BEGIN' )
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it "should act as an array of hashes" do
|
35
|
+
res = @conn.exec("SELECT 1 AS a, 2 AS b")
|
36
|
+
res[0]['a'].should== '1'
|
37
|
+
res[0]['b'].should== '2'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should insert nil AS NULL and return NULL as nil" do
|
41
|
+
res = @conn.exec("SELECT $1::int AS n", [nil])
|
42
|
+
res[0]['n'].should == nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should detect division by zero as SQLSTATE 22012" do
|
46
|
+
sqlstate = nil
|
47
|
+
begin
|
48
|
+
res = @conn.exec("SELECT 1/0")
|
49
|
+
rescue PGError => e
|
50
|
+
sqlstate = e.result.result_error_field(
|
51
|
+
PGresult::PG_DIAG_SQLSTATE).to_i
|
52
|
+
end
|
53
|
+
sqlstate.should == 22012
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should return the same bytes in binary format that are sent in binary format" do
|
57
|
+
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
58
|
+
bytes = File.open(binary_file, 'rb').read
|
59
|
+
res = @conn.exec('VALUES ($1::bytea)',
|
60
|
+
[ { :value => bytes, :format => 1 } ], 1)
|
61
|
+
res[0]['column1'].should== bytes
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should return the same bytes in binary format that are sent as inline text" do
|
65
|
+
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
66
|
+
in_bytes = File.open(binary_file, 'rb').read
|
67
|
+
out_bytes = nil
|
68
|
+
@conn.exec("SET standard_conforming_strings=on")
|
69
|
+
res = @conn.exec("VALUES ('#{PGconn.escape_bytea(in_bytes)}'::bytea)", [], 1)
|
70
|
+
out_bytes = res[0]['column1']
|
71
|
+
out_bytes.should == in_bytes
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return the same bytes in text format that are sent in binary format" do
|
75
|
+
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
76
|
+
bytes = File.open(binary_file, 'rb').read
|
77
|
+
res = @conn.exec('VALUES ($1::bytea)',
|
78
|
+
[ { :value => bytes, :format => 1 } ])
|
79
|
+
PGconn.unescape_bytea(res[0]['column1']).should== bytes
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return the same bytes in text format that are sent as inline text" do
|
83
|
+
binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
|
84
|
+
in_bytes = File.open(binary_file, 'rb').read
|
85
|
+
|
86
|
+
out_bytes = nil
|
87
|
+
@conn.exec("SET standard_conforming_strings=on")
|
88
|
+
res = @conn.exec("VALUES ('#{PGconn.escape_bytea(in_bytes)}'::bytea)", [], 0)
|
89
|
+
out_bytes = PGconn.unescape_bytea(res[0]['column1'])
|
90
|
+
out_bytes.should == in_bytes
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return the parameter type of the specified prepared statment parameter" do
|
94
|
+
query = 'SELECT * FROM pg_stat_activity WHERE user = $1::name AND current_query = $2::text'
|
95
|
+
@conn.prepare( 'queryfinder', query )
|
96
|
+
res = @conn.describe_prepared( 'queryfinder' )
|
97
|
+
|
98
|
+
@conn.exec( 'SELECT format_type($1, -1)', [res.paramtype(0)] ).getvalue( 0, 0 ).
|
99
|
+
should == 'name'
|
100
|
+
@conn.exec( 'SELECT format_type($1, -1)', [res.paramtype(1)] ).getvalue( 0, 0 ).
|
101
|
+
should == 'text'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should raise an exception when a negative index is given to #fformat" do
|
105
|
+
res = @conn.exec('SELECT * FROM pg_stat_activity')
|
106
|
+
expect {
|
107
|
+
res.fformat( -1 )
|
108
|
+
}.to raise_error( ArgumentError, /column number/i )
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should raise an exception when a negative index is given to #fmod" do
|
112
|
+
res = @conn.exec('SELECT * FROM pg_stat_activity')
|
113
|
+
expect {
|
114
|
+
res.fmod( -1 )
|
115
|
+
}.to raise_error( ArgumentError, /column number/i )
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should raise an exception when a negative index is given to #[]" do
|
119
|
+
res = @conn.exec('SELECT * FROM pg_stat_activity')
|
120
|
+
expect {
|
121
|
+
res[ -1 ]
|
122
|
+
}.to raise_error( IndexError, /-1 is out of range/i )
|
123
|
+
end
|
124
|
+
|
125
|
+
# PQfmod
|
126
|
+
it "can return the type modifier for a result column" do
|
127
|
+
@conn.exec( 'CREATE TABLE fmodtest ( foo varchar(33) )' )
|
128
|
+
res = @conn.exec( 'SELECT * FROM fmodtest' )
|
129
|
+
res.fmod( 0 ).should == 33 + 4 # Column length + varlena size (4)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should raise an exception when an invalid index is passed to PGresult#fmod" do
|
133
|
+
@conn.exec( 'CREATE TABLE fmodtest ( foo varchar(33) )' )
|
134
|
+
res = @conn.exec( 'SELECT * FROM fmodtest' )
|
135
|
+
expect { res.fmod(1) }.to raise_error( ArgumentError )
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should raise an exception when an invalid (negative) index is passed to PGresult#fmod" do
|
139
|
+
@conn.exec( 'CREATE TABLE fmodtest ( foo varchar(33) )' )
|
140
|
+
res = @conn.exec( 'SELECT * FROM fmodtest' )
|
141
|
+
expect { res.fmod(-11) }.to raise_error( ArgumentError )
|
142
|
+
end
|
143
|
+
|
144
|
+
it "shouldn't raise an exception when a valid index is passed to PGresult#fmod for a column with no typemod" do
|
145
|
+
@conn.exec( 'CREATE TABLE fmodtest ( foo text )' )
|
146
|
+
res = @conn.exec( 'SELECT * FROM fmodtest' )
|
147
|
+
res.fmod( 0 ).should == -1 # and it shouldn't raise an exception, either
|
148
|
+
end
|
149
|
+
|
150
|
+
# PQftable
|
151
|
+
it "can return the oid of the table from which a result column was fetched" do
|
152
|
+
@conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
|
153
|
+
res = @conn.exec( 'SELECT * FROM ftabletest' )
|
154
|
+
|
155
|
+
res.ftable( 0 ).should == be_nonzero()
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should raise an exception when an invalid index is passed to PGresult#ftable" do
|
159
|
+
@conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
|
160
|
+
res = @conn.exec( 'SELECT * FROM ftabletest' )
|
161
|
+
|
162
|
+
expect { res.ftable(18) }.to raise_error( ArgumentError )
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should raise an exception when an invalid (negative) index is passed to PGresult#ftable" do
|
166
|
+
@conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
|
167
|
+
res = @conn.exec( 'SELECT * FROM ftabletest' )
|
168
|
+
|
169
|
+
expect { res.ftable(-2) }.to raise_error( ArgumentError )
|
170
|
+
end
|
171
|
+
|
172
|
+
it "shouldn't raise an exception when a valid index is passed to PGresult#ftable for a " +
|
173
|
+
"column with no corresponding table" do
|
174
|
+
@conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
|
175
|
+
res = @conn.exec( 'SELECT foo, LENGTH(foo) as length FROM ftabletest' )
|
176
|
+
res.ftable( 1 ).should == PGresult::InvalidOid # and it shouldn't raise an exception, either
|
177
|
+
end
|
178
|
+
|
179
|
+
# PQftablecol
|
180
|
+
it "can return the column number (within its table) of a column in a result" do
|
181
|
+
@conn.exec( 'CREATE TABLE ftablecoltest ( foo text, bar numeric )' )
|
182
|
+
res = @conn.exec( 'SELECT * FROM ftablecoltest' )
|
183
|
+
|
184
|
+
res.ftablecol( 0 ).should == 1
|
185
|
+
res.ftablecol( 1 ).should == 2
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should raise an exception when an invalid index is passed to PGresult#ftablecol" do
|
189
|
+
@conn.exec( 'CREATE TABLE ftablecoltest ( foo text, bar numeric )' )
|
190
|
+
res = @conn.exec( 'SELECT * FROM ftablecoltest' )
|
191
|
+
|
192
|
+
expect { res.ftablecol(32) }.to raise_error( ArgumentError )
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should raise an exception when an invalid (negative) index is passed to PGresult#ftablecol" do
|
196
|
+
@conn.exec( 'CREATE TABLE ftablecoltest ( foo text, bar numeric )' )
|
197
|
+
res = @conn.exec( 'SELECT * FROM ftablecoltest' )
|
198
|
+
|
199
|
+
expect { res.ftablecol(-1) }.to raise_error( ArgumentError )
|
200
|
+
end
|
201
|
+
|
202
|
+
it "shouldn't raise an exception when a valid index is passed to PGresult#ftablecol for a " +
|
203
|
+
"column with no corresponding table" do
|
204
|
+
@conn.exec( 'CREATE TABLE ftablecoltest ( foo text )' )
|
205
|
+
res = @conn.exec( 'SELECT foo, LENGTH(foo) as length FROM ftablecoltest' )
|
206
|
+
res.ftablecol(1).should == 0 # and it shouldn't raise an exception, either
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
|
211
|
+
after( :each ) do
|
212
|
+
@conn.exec( 'ROLLBACK' )
|
213
|
+
end
|
214
|
+
|
215
|
+
after( :all ) do
|
216
|
+
teardown_testing_db( @conn )
|
217
|
+
end
|
218
|
+
end
|