pg 1.2.3-x86-mingw32 → 1.3.0.rc4-x86-mingw32

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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +36 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +86 -0
  6. data/.github/workflows/source-gem.yml +130 -0
  7. data/.gitignore +13 -0
  8. data/.hgsigs +34 -0
  9. data/.hgtags +41 -0
  10. data/.irbrc +23 -0
  11. data/.pryrc +23 -0
  12. data/.tm_properties +21 -0
  13. data/.travis.yml +49 -0
  14. data/Gemfile +14 -0
  15. data/History.rdoc +77 -7
  16. data/Manifest.txt +0 -1
  17. data/README.rdoc +7 -6
  18. data/Rakefile +27 -138
  19. data/Rakefile.cross +6 -5
  20. data/certs/ged.pem +24 -0
  21. data/ext/errorcodes.def +8 -0
  22. data/ext/errorcodes.txt +3 -1
  23. data/ext/extconf.rb +91 -19
  24. data/ext/gvl_wrappers.c +4 -0
  25. data/ext/gvl_wrappers.h +23 -0
  26. data/ext/pg.c +59 -4
  27. data/ext/pg.h +18 -1
  28. data/ext/pg_coder.c +82 -28
  29. data/ext/pg_connection.c +676 -492
  30. data/ext/pg_copy_coder.c +45 -16
  31. data/ext/pg_record_coder.c +39 -11
  32. data/ext/pg_result.c +61 -31
  33. data/ext/pg_text_decoder.c +1 -1
  34. data/ext/pg_text_encoder.c +6 -6
  35. data/ext/pg_tuple.c +47 -21
  36. data/ext/pg_type_map.c +41 -8
  37. data/ext/pg_type_map_all_strings.c +14 -1
  38. data/ext/pg_type_map_by_class.c +49 -24
  39. data/ext/pg_type_map_by_column.c +64 -28
  40. data/ext/pg_type_map_by_mri_type.c +47 -18
  41. data/ext/pg_type_map_by_oid.c +52 -23
  42. data/ext/pg_type_map_in_ruby.c +50 -19
  43. data/ext/pg_util.c +2 -2
  44. data/lib/2.5/pg_ext.so +0 -0
  45. data/lib/2.6/pg_ext.so +0 -0
  46. data/lib/2.7/pg_ext.so +0 -0
  47. data/lib/3.0/pg_ext.so +0 -0
  48. data/lib/3.1/pg_ext.so +0 -0
  49. data/lib/pg/basic_type_map_based_on_result.rb +47 -0
  50. data/lib/pg/basic_type_map_for_queries.rb +193 -0
  51. data/lib/pg/basic_type_map_for_results.rb +81 -0
  52. data/lib/pg/basic_type_registry.rb +296 -0
  53. data/lib/pg/coder.rb +1 -1
  54. data/lib/pg/connection.rb +587 -58
  55. data/lib/pg/version.rb +4 -0
  56. data/lib/pg.rb +40 -27
  57. data/lib/x86-mingw32/libpq.dll +0 -0
  58. data/misc/openssl-pg-segfault.rb +31 -0
  59. data/misc/postgres/History.txt +9 -0
  60. data/misc/postgres/Manifest.txt +5 -0
  61. data/misc/postgres/README.txt +21 -0
  62. data/misc/postgres/Rakefile +21 -0
  63. data/misc/postgres/lib/postgres.rb +16 -0
  64. data/misc/ruby-pg/History.txt +9 -0
  65. data/misc/ruby-pg/Manifest.txt +5 -0
  66. data/misc/ruby-pg/README.txt +21 -0
  67. data/misc/ruby-pg/Rakefile +21 -0
  68. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  69. data/pg.gemspec +32 -0
  70. data/sample/array_insert.rb +20 -0
  71. data/sample/async_api.rb +106 -0
  72. data/sample/async_copyto.rb +39 -0
  73. data/sample/async_mixed.rb +56 -0
  74. data/sample/check_conn.rb +21 -0
  75. data/sample/copydata.rb +71 -0
  76. data/sample/copyfrom.rb +81 -0
  77. data/sample/copyto.rb +19 -0
  78. data/sample/cursor.rb +21 -0
  79. data/sample/disk_usage_report.rb +177 -0
  80. data/sample/issue-119.rb +94 -0
  81. data/sample/losample.rb +69 -0
  82. data/sample/minimal-testcase.rb +17 -0
  83. data/sample/notify_wait.rb +72 -0
  84. data/sample/pg_statistics.rb +285 -0
  85. data/sample/replication_monitor.rb +222 -0
  86. data/sample/test_binary_values.rb +33 -0
  87. data/sample/wal_shipper.rb +434 -0
  88. data/sample/warehouse_partitions.rb +311 -0
  89. data.tar.gz.sig +0 -0
  90. metadata +93 -233
  91. metadata.gz.sig +0 -0
  92. data/ChangeLog +0 -0
  93. data/lib/2.2/pg_ext.so +0 -0
  94. data/lib/2.3/pg_ext.so +0 -0
  95. data/lib/2.4/pg_ext.so +0 -0
  96. data/lib/pg/basic_type_mapping.rb +0 -522
  97. data/spec/data/expected_trace.out +0 -26
  98. data/spec/data/random_binary_data +0 -0
  99. data/spec/helpers.rb +0 -380
  100. data/spec/pg/basic_type_mapping_spec.rb +0 -630
  101. data/spec/pg/connection_spec.rb +0 -1949
  102. data/spec/pg/connection_sync_spec.rb +0 -41
  103. data/spec/pg/result_spec.rb +0 -681
  104. data/spec/pg/tuple_spec.rb +0 -333
  105. data/spec/pg/type_map_by_class_spec.rb +0 -138
  106. data/spec/pg/type_map_by_column_spec.rb +0 -226
  107. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  108. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  109. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  110. data/spec/pg/type_map_spec.rb +0 -22
  111. data/spec/pg/type_spec.rb +0 -1123
  112. data/spec/pg_spec.rb +0 -50
@@ -1,681 +0,0 @@
1
- # -*- rspec -*-
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
6
- require 'pg'
7
- require 'objspace'
8
-
9
-
10
- describe PG::Result do
11
-
12
- describe :field_name_type do
13
- let!(:res) { @conn.exec('SELECT 1 AS a, 2 AS "B"') }
14
-
15
- it "uses string field names per default" do
16
- expect(res.field_name_type).to eq(:string)
17
- end
18
-
19
- it "can set string field names" do
20
- res.field_name_type = :string
21
- expect(res.field_name_type).to eq(:string)
22
- end
23
-
24
- it "can set symbol field names" do
25
- res.field_name_type = :symbol
26
- expect(res.field_name_type).to eq(:symbol)
27
- end
28
-
29
- it "can set static_symbol field names" do
30
- res.field_name_type = :static_symbol
31
- expect(res.field_name_type).to eq(:static_symbol)
32
- end
33
-
34
- it "can't set symbol field names after #fields" do
35
- res.fields
36
- expect{ res.field_name_type = :symbol }.to raise_error(ArgumentError, /already materialized/)
37
- expect(res.field_name_type).to eq(:string)
38
- end
39
-
40
- it "can't set invalid values" do
41
- expect{ res.field_name_type = :sym }.to raise_error(ArgumentError, /invalid argument :sym/)
42
- expect{ res.field_name_type = "symbol" }.to raise_error(ArgumentError, /invalid argument "symbol"/)
43
- end
44
- end
45
-
46
- it "acts as an array of hashes" do
47
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
48
- expect( res[0]['a'] ).to eq( '1' )
49
- expect( res[0]['b'] ).to eq( '2' )
50
- end
51
-
52
- it "acts as an array of hashes with symbols" do
53
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
54
- res.field_name_type = :symbol
55
- expect( res[0][:a] ).to eq( '1' )
56
- expect( res[0][:b] ).to eq( '2' )
57
- end
58
-
59
- it "acts as an array of hashes with static_symbols" do
60
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
61
- res.field_name_type = :static_symbol
62
- expect( res[0][:a] ).to eq( '1' )
63
- expect( res[0][:b] ).to eq( '2' )
64
- end
65
-
66
- it "yields a row as an array" do
67
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
68
- list = []
69
- res.each_row { |r| list << r }
70
- expect( list ).to eq [['1', '2']]
71
- end
72
-
73
- it "yields a row as an Enumerator" do
74
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
75
- e = res.each_row
76
- expect( e ).to be_a_kind_of(Enumerator)
77
- expect( e.size ).to eq( 1 )
78
- expect( e.to_a ).to eq [['1', '2']]
79
- end
80
-
81
- it "yields a row as an Enumerator of hashs" do
82
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
83
- e = res.each
84
- expect( e ).to be_a_kind_of(Enumerator)
85
- expect( e.size ).to eq( 1 )
86
- expect( e.to_a ).to eq [{'a'=>'1', 'b'=>'2'}]
87
- end
88
-
89
- it "yields a row as an Enumerator of hashs with symbols" do
90
- res = @conn.exec("SELECT 1 AS a, 2 AS b")
91
- res.field_name_type = :symbol
92
- expect( res.each.to_a ).to eq [{:a=>'1', :b=>'2'}]
93
- end
94
-
95
- context "result streaming in single row mode" do
96
- let!(:textdec_int){ PG::TextDecoder::Integer.new name: 'INT4', oid: 23 }
97
-
98
- it "can iterate over all rows as Hash" do
99
- @conn.send_query( "SELECT generate_series(2,4) AS a; SELECT 1 AS b, generate_series(5,6) AS c" )
100
- @conn.set_single_row_mode
101
- expect(
102
- @conn.get_result.stream_each.to_a
103
- ).to eq(
104
- [{'a'=>"2"}, {'a'=>"3"}, {'a'=>"4"}]
105
- )
106
- expect(
107
- @conn.get_result.enum_for(:stream_each).to_a
108
- ).to eq(
109
- [{'b'=>"1", 'c'=>"5"}, {'b'=>"1", 'c'=>"6"}]
110
- )
111
- expect( @conn.get_result ).to be_nil
112
- end
113
-
114
- it "can iterate over all rows as Hash with symbols and typemap" do
115
- @conn.send_query( "SELECT generate_series(2,4) AS a" )
116
- @conn.set_single_row_mode
117
- res = @conn.get_result.field_names_as(:symbol)
118
- res.type_map = PG::TypeMapByColumn.new [textdec_int]
119
- expect(
120
- res.stream_each.to_a
121
- ).to eq(
122
- [{:a=>2}, {:a=>3}, {:a=>4}]
123
- )
124
- expect( @conn.get_result ).to be_nil
125
- end
126
-
127
- it "keeps last result on error while iterating stream_each" do
128
- @conn.send_query( "SELECT generate_series(2,4) AS a" )
129
- @conn.set_single_row_mode
130
- res = @conn.get_result
131
- expect do
132
- res.stream_each_row do
133
- raise ZeroDivisionError
134
- end
135
- end.to raise_error(ZeroDivisionError)
136
- expect( res.values ).to eq([["2"]])
137
- end
138
-
139
- it "can iterate over all rows as Array" do
140
- @conn.send_query( "SELECT generate_series(2,4) AS a; SELECT 1 AS b, generate_series(5,6) AS c" )
141
- @conn.set_single_row_mode
142
- expect(
143
- @conn.get_result.enum_for(:stream_each_row).to_a
144
- ).to eq(
145
- [["2"], ["3"], ["4"]]
146
- )
147
- expect(
148
- @conn.get_result.stream_each_row.to_a
149
- ).to eq(
150
- [["1", "5"], ["1", "6"]]
151
- )
152
- expect( @conn.get_result ).to be_nil
153
- end
154
-
155
- it "keeps last result on error while iterating stream_each_row" do
156
- @conn.send_query( "SELECT generate_series(2,4) AS a" )
157
- @conn.set_single_row_mode
158
- res = @conn.get_result
159
- expect do
160
- res.stream_each_row do
161
- raise ZeroDivisionError
162
- end
163
- end.to raise_error(ZeroDivisionError)
164
- expect( res.values ).to eq([["2"]])
165
- end
166
-
167
- it "can iterate over all rows as PG::Tuple" do
168
- @conn.send_query( "SELECT generate_series(2,4) AS a; SELECT 1 AS b, generate_series(5,6) AS c" )
169
- @conn.set_single_row_mode
170
- tuples = @conn.get_result.stream_each_tuple.to_a
171
- expect( tuples[0][0] ).to eq( "2" )
172
- expect( tuples[1]["a"] ).to eq( "3" )
173
- expect( tuples.size ).to eq( 3 )
174
-
175
- tuples = @conn.get_result.enum_for(:stream_each_tuple).to_a
176
- expect( tuples[-1][-1] ).to eq( "6" )
177
- expect( tuples[-2]["b"] ).to eq( "1" )
178
- expect( tuples.size ).to eq( 2 )
179
-
180
- expect( @conn.get_result ).to be_nil
181
- end
182
-
183
- it "clears result on error while iterating stream_each_tuple" do
184
- @conn.send_query( "SELECT generate_series(2,4) AS a" )
185
- @conn.set_single_row_mode
186
- res = @conn.get_result
187
- expect do
188
- res.stream_each_tuple do
189
- raise ZeroDivisionError
190
- end
191
- end.to raise_error(ZeroDivisionError)
192
- expect( res.cleared? ).to eq(true)
193
- end
194
-
195
- it "should reuse field names in stream_each_tuple" do
196
- @conn.send_query( "SELECT generate_series(2,3) AS a" )
197
- @conn.set_single_row_mode
198
- tuple1, tuple2 = *@conn.get_result.stream_each_tuple.to_a
199
- expect( tuple1.keys[0].object_id ).to eq(tuple2.keys[0].object_id)
200
- end
201
-
202
- it "can iterate over all rows as PG::Tuple with symbols and typemap" do
203
- @conn.send_query( "SELECT generate_series(2,4) AS a" )
204
- @conn.set_single_row_mode
205
- res = @conn.get_result.field_names_as(:symbol)
206
- res.type_map = PG::TypeMapByColumn.new [textdec_int]
207
- tuples = res.stream_each_tuple.to_a
208
- expect( tuples[0][0] ).to eq( 2 )
209
- expect( tuples[1][:a] ).to eq( 3 )
210
- expect( @conn.get_result ).to be_nil
211
- end
212
-
213
- it "complains when not in single row mode" do
214
- @conn.send_query( "SELECT generate_series(2,4)" )
215
- expect{
216
- @conn.get_result.stream_each_row.to_a
217
- }.to raise_error(PG::InvalidResultStatus, /not in single row mode/)
218
- end
219
-
220
- it "complains when intersected with get_result" do
221
- @conn.send_query( "SELECT 1" )
222
- @conn.set_single_row_mode
223
- expect{
224
- @conn.get_result.stream_each_row.each{ @conn.get_result }
225
- }.to raise_error(PG::NoResultError, /no result received/)
226
- end
227
-
228
- it "raises server errors" do
229
- @conn.send_query( "SELECT 0/0" )
230
- expect{
231
- @conn.get_result.stream_each_row.to_a
232
- }.to raise_error(PG::DivisionByZero)
233
- end
234
- end
235
-
236
- it "inserts nil AS NULL and return NULL as nil" do
237
- res = @conn.exec_params("SELECT $1::int AS n", [nil])
238
- expect( res[0]['n'] ).to be_nil()
239
- end
240
-
241
- it "encapsulates errors in a PG::Error object" do
242
- exception = nil
243
- begin
244
- @conn.exec( "SELECT * FROM nonexistant_table" )
245
- rescue PG::Error => err
246
- exception = err
247
- end
248
-
249
- result = exception.result
250
-
251
- expect( result ).to be_a( described_class() )
252
- expect( result.error_field(PG::PG_DIAG_SEVERITY) ).to eq( 'ERROR' )
253
- expect( result.error_field(PG::PG_DIAG_SQLSTATE) ).to eq( '42P01' )
254
- expect(
255
- result.error_field(PG::PG_DIAG_MESSAGE_PRIMARY)
256
- ).to eq( 'relation "nonexistant_table" does not exist' )
257
- expect( result.error_field(PG::PG_DIAG_MESSAGE_DETAIL) ).to be_nil()
258
- expect( result.error_field(PG::PG_DIAG_MESSAGE_HINT) ).to be_nil()
259
- expect( result.error_field(PG::PG_DIAG_STATEMENT_POSITION) ).to eq( '15' )
260
- expect( result.error_field(PG::PG_DIAG_INTERNAL_POSITION) ).to be_nil()
261
- expect( result.error_field(PG::PG_DIAG_INTERNAL_QUERY) ).to be_nil()
262
- expect( result.error_field(PG::PG_DIAG_CONTEXT) ).to be_nil()
263
- expect(
264
- result.error_field(PG::PG_DIAG_SOURCE_FILE)
265
- ).to match( /parse_relation\.c$|namespace\.c$/ )
266
- expect( result.error_field(PG::PG_DIAG_SOURCE_LINE) ).to match( /^\d+$/ )
267
- expect(
268
- result.error_field(PG::PG_DIAG_SOURCE_FUNCTION)
269
- ).to match( /^parserOpenTable$|^RangeVarGetRelid$/ )
270
- end
271
-
272
- it "encapsulates PG_DIAG_SEVERITY_NONLOCALIZED error in a PG::Error object", :postgresql_96 do
273
- result = nil
274
- begin
275
- @conn.exec( "SELECT * FROM nonexistant_table" )
276
- rescue PG::Error => err
277
- result = err.result
278
- end
279
-
280
- expect( result.error_field(PG::PG_DIAG_SEVERITY_NONLOCALIZED) ).to eq( 'ERROR' )
281
- end
282
-
283
- it "encapsulates database object names for integrity constraint violations", :postgresql_93 do
284
- @conn.exec( "CREATE TABLE integrity (id SERIAL PRIMARY KEY)" )
285
- exception = nil
286
- begin
287
- @conn.exec( "INSERT INTO integrity VALUES (NULL)" )
288
- rescue PG::Error => err
289
- exception = err
290
- end
291
- result = exception.result
292
-
293
- expect( result.error_field(PG::PG_DIAG_SCHEMA_NAME) ).to eq( 'public' )
294
- expect( result.error_field(PG::PG_DIAG_TABLE_NAME) ).to eq( 'integrity' )
295
- expect( result.error_field(PG::PG_DIAG_COLUMN_NAME) ).to eq( 'id' )
296
- expect( result.error_field(PG::PG_DIAG_DATATYPE_NAME) ).to be_nil
297
- expect( result.error_field(PG::PG_DIAG_CONSTRAINT_NAME) ).to be_nil
298
- end
299
-
300
- it "detects division by zero as SQLSTATE 22012" do
301
- sqlstate = nil
302
- begin
303
- @conn.exec("SELECT 1/0")
304
- rescue PG::Error => e
305
- sqlstate = e.result.result_error_field( PG::PG_DIAG_SQLSTATE ).to_i
306
- end
307
- expect( sqlstate ).to eq( 22012 )
308
- end
309
-
310
- it "provides the error message" do
311
- @conn.send_query("SELECT xyz")
312
- res = @conn.get_result; @conn.get_result
313
- expect( res.error_message ).to match(/"xyz"/)
314
- expect( res.result_error_message ).to match(/"xyz"/)
315
- end
316
-
317
- it "provides a verbose error message", :postgresql_96 do
318
- @conn.send_query("SELECT xyz")
319
- res = @conn.get_result; @conn.get_result
320
- # PQERRORS_TERSE should give a single line result
321
- expect( res.verbose_error_message(PG::PQERRORS_TERSE, PG::PQSHOW_CONTEXT_ALWAYS) ).to match(/\A.*\n\z/)
322
- # PQERRORS_VERBOSE should give a multi line result
323
- expect( res.result_verbose_error_message(PG::PQERRORS_VERBOSE, PG::PQSHOW_CONTEXT_NEVER) ).to match(/\n.*\n/)
324
- end
325
-
326
- it "provides a verbose error message with SQLSTATE", :postgresql_12 do
327
- @conn.send_query("SELECT xyz")
328
- res = @conn.get_result; @conn.get_result
329
- expect( res.verbose_error_message(PG::PQERRORS_SQLSTATE, PG::PQSHOW_CONTEXT_NEVER) ).to match(/42703/)
330
- end
331
-
332
- it "returns the same bytes in binary format that are sent in binary format" do
333
- binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
334
- bytes = File.open(binary_file, 'rb').read
335
- res = @conn.exec_params('VALUES ($1::bytea)',
336
- [ { :value => bytes, :format => 1 } ], 1)
337
- expect( res[0]['column1'] ).to eq( bytes )
338
- expect( res.getvalue(0,0) ).to eq( bytes )
339
- expect( res.values[0][0] ).to eq( bytes )
340
- expect( res.column_values(0)[0] ).to eq( bytes )
341
- end
342
-
343
- it "returns the same bytes in binary format that are sent as inline text" do
344
- binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
345
- bytes = File.open(binary_file, 'rb').read
346
- @conn.exec("SET standard_conforming_strings=on")
347
- res = @conn.exec_params("VALUES ('#{PG::Connection.escape_bytea(bytes)}'::bytea)", [], 1)
348
- expect( res[0]['column1'] ).to eq( bytes )
349
- expect( res.getvalue(0,0) ).to eq( bytes )
350
- expect( res.values[0][0] ).to eq( bytes )
351
- expect( res.column_values(0)[0] ).to eq( bytes )
352
- end
353
-
354
- it "returns the same bytes in text format that are sent in binary format" do
355
- binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
356
- bytes = File.open(binary_file, 'rb').read
357
- res = @conn.exec_params('VALUES ($1::bytea)',
358
- [ { :value => bytes, :format => 1 } ])
359
- expect( PG::Connection.unescape_bytea(res[0]['column1']) ).to eq( bytes )
360
- end
361
-
362
- it "returns the same bytes in text format that are sent as inline text" do
363
- binary_file = File.join(Dir.pwd, 'spec/data', 'random_binary_data')
364
- in_bytes = File.open(binary_file, 'rb').read
365
-
366
- out_bytes = nil
367
- @conn.exec("SET standard_conforming_strings=on")
368
- res = @conn.exec_params("VALUES ('#{PG::Connection.escape_bytea(in_bytes)}'::bytea)", [], 0)
369
- out_bytes = PG::Connection.unescape_bytea(res[0]['column1'])
370
- expect( out_bytes ).to eq( in_bytes )
371
- end
372
-
373
- it "returns the parameter type of the specified prepared statement parameter" do
374
- query = 'SELECT * FROM pg_stat_activity WHERE user = $1::name AND query = $2::text'
375
- @conn.prepare( 'queryfinder', query )
376
- res = @conn.describe_prepared( 'queryfinder' )
377
-
378
- expect(
379
- @conn.exec_params( 'SELECT format_type($1, -1)', [res.paramtype(0)] ).getvalue( 0, 0 )
380
- ).to eq( 'name' )
381
- expect(
382
- @conn.exec_params( 'SELECT format_type($1, -1)', [res.paramtype(1)] ).getvalue( 0, 0 )
383
- ).to eq( 'text' )
384
- end
385
-
386
- it "raises an exception when a negative index is given to #fformat" do
387
- res = @conn.exec('SELECT * FROM pg_stat_activity')
388
- expect {
389
- res.fformat( -1 )
390
- }.to raise_error( ArgumentError, /column number/i )
391
- end
392
-
393
- it "raises an exception when a negative index is given to #fmod" do
394
- res = @conn.exec('SELECT * FROM pg_stat_activity')
395
- expect {
396
- res.fmod( -1 )
397
- }.to raise_error( ArgumentError, /column number/i )
398
- end
399
-
400
- it "raises an exception when a negative index is given to #[]" do
401
- res = @conn.exec('SELECT * FROM pg_stat_activity')
402
- expect {
403
- res[ -1 ]
404
- }.to raise_error( IndexError, /-1 is out of range/i )
405
- end
406
-
407
- it "raises allow for conversion to an array of arrays" do
408
- @conn.exec( 'CREATE TABLE valuestest ( foo varchar(33) )' )
409
- @conn.exec( 'INSERT INTO valuestest ("foo") values (\'bar\')' )
410
- @conn.exec( 'INSERT INTO valuestest ("foo") values (\'bar2\')' )
411
-
412
- res = @conn.exec( 'SELECT * FROM valuestest' )
413
- expect( res.values ).to eq( [ ["bar"], ["bar2"] ] )
414
- end
415
-
416
- it "can retrieve field names" do
417
- res = @conn.exec('SELECT 1 AS a, 2 AS "B"')
418
- expect(res.fields).to eq(["a", "B"])
419
- end
420
-
421
- it "can retrieve field names as symbols" do
422
- res = @conn.exec('SELECT 1 AS a, 2 AS "B"')
423
- res.field_name_type = :symbol
424
- expect(res.fields).to eq([:a, :B])
425
- end
426
-
427
- it "can retrieve single field names" do
428
- res = @conn.exec('SELECT 1 AS a, 2 AS "B"')
429
- expect(res.fname(0)).to eq("a")
430
- expect(res.fname(1)).to eq("B")
431
- expect{res.fname(2)}.to raise_error(ArgumentError)
432
- end
433
-
434
- it "can retrieve single field names as symbol" do
435
- res = @conn.exec('SELECT 1 AS a, 2 AS "B"')
436
- res.field_name_type = :symbol
437
- expect(res.fname(0)).to eq(:a)
438
- expect(res.fname(1)).to eq(:B)
439
- expect{res.fname(2)}.to raise_error(ArgumentError)
440
- end
441
-
442
- # PQfmod
443
- it "can return the type modifier for a result column" do
444
- @conn.exec( 'CREATE TABLE fmodtest ( foo varchar(33) )' )
445
- res = @conn.exec( 'SELECT * FROM fmodtest' )
446
- expect( res.fmod(0) ).to eq( 33 + 4 ) # Column length + varlena size (4)
447
- end
448
-
449
- it "raises an exception when an invalid index is passed to PG::Result#fmod" do
450
- @conn.exec( 'CREATE TABLE fmodtest ( foo varchar(33) )' )
451
- res = @conn.exec( 'SELECT * FROM fmodtest' )
452
- expect { res.fmod(1) }.to raise_error( ArgumentError )
453
- end
454
-
455
- it "raises an exception when an invalid (negative) index is passed to PG::Result#fmod" do
456
- @conn.exec( 'CREATE TABLE fmodtest ( foo varchar(33) )' )
457
- res = @conn.exec( 'SELECT * FROM fmodtest' )
458
- expect { res.fmod(-11) }.to raise_error( ArgumentError )
459
- end
460
-
461
- it "doesn't raise an exception when a valid index is passed to PG::Result#fmod for a" +
462
- " column with no typemod" do
463
- @conn.exec( 'CREATE TABLE fmodtest ( foo text )' )
464
- res = @conn.exec( 'SELECT * FROM fmodtest' )
465
- expect( res.fmod(0) ).to eq( -1 )
466
- end
467
-
468
- # PQftable
469
- it "can return the oid of the table from which a result column was fetched" do
470
- @conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
471
- res = @conn.exec( 'SELECT * FROM ftabletest' )
472
-
473
- expect( res.ftable(0) ).to be_nonzero()
474
- end
475
-
476
- it "raises an exception when an invalid index is passed to PG::Result#ftable" do
477
- @conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
478
- res = @conn.exec( 'SELECT * FROM ftabletest' )
479
-
480
- expect { res.ftable(18) }.to raise_error( ArgumentError )
481
- end
482
-
483
- it "raises an exception when an invalid (negative) index is passed to PG::Result#ftable" do
484
- @conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
485
- res = @conn.exec( 'SELECT * FROM ftabletest' )
486
-
487
- expect { res.ftable(-2) }.to raise_error( ArgumentError )
488
- end
489
-
490
- it "doesn't raise an exception when a valid index is passed to PG::Result#ftable for a " +
491
- "column with no corresponding table" do
492
- @conn.exec( 'CREATE TABLE ftabletest ( foo text )' )
493
- res = @conn.exec( 'SELECT foo, LENGTH(foo) as length FROM ftabletest' )
494
- expect( res.ftable(1) ).to eq( PG::INVALID_OID )
495
- end
496
-
497
- # PQftablecol
498
- it "can return the column number (within its table) of a column in a result" do
499
- @conn.exec( 'CREATE TABLE ftablecoltest ( foo text, bar numeric )' )
500
- res = @conn.exec( 'SELECT * FROM ftablecoltest' )
501
-
502
- expect( res.ftablecol(0) ).to eq( 1 )
503
- expect( res.ftablecol(1) ).to eq( 2 )
504
- end
505
-
506
- it "raises an exception when an invalid index is passed to PG::Result#ftablecol" do
507
- @conn.exec( 'CREATE TABLE ftablecoltest ( foo text, bar numeric )' )
508
- res = @conn.exec( 'SELECT * FROM ftablecoltest' )
509
-
510
- expect { res.ftablecol(32) }.to raise_error( ArgumentError )
511
- end
512
-
513
- it "raises an exception when an invalid (negative) index is passed to PG::Result#ftablecol" do
514
- @conn.exec( 'CREATE TABLE ftablecoltest ( foo text, bar numeric )' )
515
- res = @conn.exec( 'SELECT * FROM ftablecoltest' )
516
-
517
- expect { res.ftablecol(-1) }.to raise_error( ArgumentError )
518
- end
519
-
520
- it "doesnn't raise an exception when a valid index is passed to PG::Result#ftablecol for a " +
521
- "column with no corresponding table" do
522
- @conn.exec( 'CREATE TABLE ftablecoltest ( foo text )' )
523
- res = @conn.exec( 'SELECT foo, LENGTH(foo) as length FROM ftablecoltest' )
524
- expect( res.ftablecol(1) ).to eq( 0 )
525
- end
526
-
527
- it "can be manually checked for failed result status (async API)" do
528
- @conn.send_query( "SELECT * FROM nonexistant_table" )
529
- res = @conn.get_result
530
- expect {
531
- res.check
532
- }.to raise_error( PG::Error, /relation "nonexistant_table" does not exist/ )
533
- end
534
-
535
- it "can return the values of a single field" do
536
- res = @conn.exec( "SELECT 1 AS x, 'a' AS y UNION ALL SELECT 2, 'b'" )
537
- expect( res.field_values('x') ).to eq( ['1', '2'] )
538
- expect( res.field_values('y') ).to eq( ['a', 'b'] )
539
- expect( res.field_values(:x) ).to eq( ['1', '2'] )
540
- expect{ res.field_values('') }.to raise_error(IndexError)
541
- expect{ res.field_values(0) }.to raise_error(TypeError)
542
- end
543
-
544
- it "can return the values of a single tuple" do
545
- res = @conn.exec( "SELECT 1 AS x, 'a' AS y UNION ALL SELECT 2, 'b'" )
546
- expect( res.tuple_values(0) ).to eq( ['1', 'a'] )
547
- expect( res.tuple_values(1) ).to eq( ['2', 'b'] )
548
- expect{ res.tuple_values(2) }.to raise_error(IndexError)
549
- expect{ res.tuple_values(-1) }.to raise_error(IndexError)
550
- expect{ res.tuple_values("x") }.to raise_error(TypeError)
551
- end
552
-
553
- it "can return the values of a single vary lazy tuple" do
554
- res = @conn.exec( "VALUES(1),(2)" )
555
- expect( res.tuple(0) ).to be_kind_of( PG::Tuple )
556
- expect( res.tuple(1) ).to be_kind_of( PG::Tuple )
557
- expect{ res.tuple(2) }.to raise_error(IndexError)
558
- expect{ res.tuple(-1) }.to raise_error(IndexError)
559
- expect{ res.tuple("x") }.to raise_error(TypeError)
560
- end
561
-
562
- it "raises a proper exception for a nonexistant table" do
563
- expect {
564
- @conn.exec( "SELECT * FROM nonexistant_table" )
565
- }.to raise_error( PG::UndefinedTable, /relation "nonexistant_table" does not exist/ )
566
- end
567
-
568
- it "raises a more generic exception for an unknown SQLSTATE" do
569
- old_error = PG::ERROR_CLASSES.delete('42P01')
570
- begin
571
- expect {
572
- @conn.exec( "SELECT * FROM nonexistant_table" )
573
- }.to raise_error{|error|
574
- expect( error ).to be_an_instance_of(PG::SyntaxErrorOrAccessRuleViolation)
575
- expect( error.to_s ).to match(/relation "nonexistant_table" does not exist/)
576
- }
577
- ensure
578
- PG::ERROR_CLASSES['42P01'] = old_error
579
- end
580
- end
581
-
582
- it "raises a ServerError for an unknown SQLSTATE class" do
583
- old_error1 = PG::ERROR_CLASSES.delete('42P01')
584
- old_error2 = PG::ERROR_CLASSES.delete('42')
585
- begin
586
- expect {
587
- @conn.exec( "SELECT * FROM nonexistant_table" )
588
- }.to raise_error{|error|
589
- expect( error ).to be_an_instance_of(PG::ServerError)
590
- expect( error.to_s ).to match(/relation "nonexistant_table" does not exist/)
591
- }
592
- ensure
593
- PG::ERROR_CLASSES['42P01'] = old_error1
594
- PG::ERROR_CLASSES['42'] = old_error2
595
- end
596
- end
597
-
598
- it "raises a proper exception for a nonexistant schema" do
599
- expect {
600
- @conn.exec( "DROP SCHEMA nonexistant_schema" )
601
- }.to raise_error( PG::InvalidSchemaName, /schema "nonexistant_schema" does not exist/ )
602
- end
603
-
604
- it "the raised result is nil in case of a connection error" do
605
- c = PG::Connection.connect_start( '127.0.0.1', 54320, "", "", "me", "xxxx", "somedb" )
606
- expect {
607
- c.exec "select 1"
608
- }.to raise_error {|error|
609
- expect( error ).to be_an_instance_of(PG::UnableToSend)
610
- expect( error.result ).to eq( nil )
611
- }
612
- end
613
-
614
- it "does not clear the result itself" do
615
- r = @conn.exec "select 1"
616
- expect( r.autoclear? ).to eq(false)
617
- expect( r.cleared? ).to eq(false)
618
- r.clear
619
- expect( r.cleared? ).to eq(true)
620
- end
621
-
622
- it "can be inspected before and after clear" do
623
- r = @conn.exec "select 1"
624
- expect( r.inspect ).to match(/status=PGRES_TUPLES_OK/)
625
- r.clear
626
- expect( r.inspect ).to match(/cleared/)
627
- end
628
-
629
- it "should give account about memory usage" do
630
- r = @conn.exec "select 1"
631
- expect( ObjectSpace.memsize_of(r) ).to be > 1000
632
- r.clear
633
- expect( ObjectSpace.memsize_of(r) ).to be < 100
634
- end
635
-
636
- context 'result value conversions with TypeMapByColumn' do
637
- let!(:textdec_int){ PG::TextDecoder::Integer.new name: 'INT4', oid: 23 }
638
- let!(:textdec_float){ PG::TextDecoder::Float.new name: 'FLOAT4', oid: 700 }
639
-
640
- it "should allow reading, assigning and diabling type conversions" do
641
- res = @conn.exec( "SELECT 123" )
642
- expect( res.type_map ).to be_kind_of(PG::TypeMapAllStrings)
643
- res.type_map = PG::TypeMapByColumn.new [textdec_int]
644
- expect( res.type_map ).to be_an_instance_of(PG::TypeMapByColumn)
645
- expect( res.type_map.coders ).to eq( [textdec_int] )
646
- res.type_map = PG::TypeMapByColumn.new [textdec_float]
647
- expect( res.type_map.coders ).to eq( [textdec_float] )
648
- res.type_map = PG::TypeMapAllStrings.new
649
- expect( res.type_map ).to be_kind_of(PG::TypeMapAllStrings)
650
- end
651
-
652
- it "should be applied to all value retrieving methods" do
653
- res = @conn.exec( "SELECT 123 as f" )
654
- res.type_map = PG::TypeMapByColumn.new [textdec_int]
655
- expect( res.values ).to eq( [[123]] )
656
- expect( res.getvalue(0,0) ).to eq( 123 )
657
- expect( res[0] ).to eq( {'f' => 123 } )
658
- expect( res.enum_for(:each_row).to_a ).to eq( [[123]] )
659
- expect( res.enum_for(:each).to_a ).to eq( [{'f' => 123}] )
660
- expect( res.column_values(0) ).to eq( [123] )
661
- expect( res.field_values('f') ).to eq( [123] )
662
- expect( res.field_values(:f) ).to eq( [123] )
663
- expect( res.tuple_values(0) ).to eq( [123] )
664
- end
665
-
666
- it "should be usable for several querys" do
667
- colmap = PG::TypeMapByColumn.new [textdec_int]
668
- res = @conn.exec( "SELECT 123" )
669
- res.type_map = colmap
670
- expect( res.values ).to eq( [[123]] )
671
- res = @conn.exec( "SELECT 456" )
672
- res.type_map = colmap
673
- expect( res.values ).to eq( [[456]] )
674
- end
675
-
676
- it "shouldn't allow invalid type maps" do
677
- res = @conn.exec( "SELECT 1" )
678
- expect{ res.type_map = 1 }.to raise_error(TypeError)
679
- end
680
- end
681
- end