pg 1.0.0 → 1.5.9

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 (126) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Gemfile +20 -0
  4. data/History.md +932 -0
  5. data/Manifest.txt +8 -3
  6. data/README-Windows.rdoc +4 -4
  7. data/README.ja.md +300 -0
  8. data/README.md +286 -0
  9. data/Rakefile +41 -138
  10. data/Rakefile.cross +71 -66
  11. data/certs/ged.pem +24 -0
  12. data/certs/kanis@comcard.de.pem +20 -0
  13. data/certs/larskanis-2022.pem +26 -0
  14. data/certs/larskanis-2023.pem +24 -0
  15. data/certs/larskanis-2024.pem +24 -0
  16. data/ext/errorcodes.def +84 -5
  17. data/ext/errorcodes.rb +1 -1
  18. data/ext/errorcodes.txt +23 -6
  19. data/ext/extconf.rb +109 -25
  20. data/ext/gvl_wrappers.c +4 -0
  21. data/ext/gvl_wrappers.h +23 -0
  22. data/ext/pg.c +213 -155
  23. data/ext/pg.h +89 -23
  24. data/ext/pg_binary_decoder.c +164 -16
  25. data/ext/pg_binary_encoder.c +238 -13
  26. data/ext/pg_coder.c +159 -35
  27. data/ext/pg_connection.c +1584 -967
  28. data/ext/pg_copy_coder.c +373 -43
  29. data/ext/pg_errors.c +1 -1
  30. data/ext/pg_record_coder.c +522 -0
  31. data/ext/pg_result.c +710 -217
  32. data/ext/pg_text_decoder.c +630 -43
  33. data/ext/pg_text_encoder.c +222 -72
  34. data/ext/pg_tuple.c +572 -0
  35. data/ext/pg_type_map.c +45 -11
  36. data/ext/pg_type_map_all_strings.c +21 -7
  37. data/ext/pg_type_map_by_class.c +59 -27
  38. data/ext/pg_type_map_by_column.c +80 -37
  39. data/ext/pg_type_map_by_mri_type.c +49 -20
  40. data/ext/pg_type_map_by_oid.c +62 -29
  41. data/ext/pg_type_map_in_ruby.c +56 -22
  42. data/ext/{util.c → pg_util.c} +12 -12
  43. data/ext/{util.h → pg_util.h} +2 -2
  44. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  45. data/lib/pg/basic_type_map_for_queries.rb +202 -0
  46. data/lib/pg/basic_type_map_for_results.rb +104 -0
  47. data/lib/pg/basic_type_registry.rb +311 -0
  48. data/lib/pg/binary_decoder/date.rb +9 -0
  49. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  50. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  51. data/lib/pg/coder.rb +36 -13
  52. data/lib/pg/connection.rb +769 -70
  53. data/lib/pg/exceptions.rb +22 -2
  54. data/lib/pg/result.rb +14 -2
  55. data/lib/pg/text_decoder/date.rb +21 -0
  56. data/lib/pg/text_decoder/inet.rb +9 -0
  57. data/lib/pg/text_decoder/json.rb +17 -0
  58. data/lib/pg/text_decoder/numeric.rb +9 -0
  59. data/lib/pg/text_decoder/timestamp.rb +30 -0
  60. data/lib/pg/text_encoder/date.rb +13 -0
  61. data/lib/pg/text_encoder/inet.rb +31 -0
  62. data/lib/pg/text_encoder/json.rb +17 -0
  63. data/lib/pg/text_encoder/numeric.rb +9 -0
  64. data/lib/pg/text_encoder/timestamp.rb +24 -0
  65. data/lib/pg/tuple.rb +30 -0
  66. data/lib/pg/type_map_by_column.rb +3 -2
  67. data/lib/pg/version.rb +4 -0
  68. data/lib/pg.rb +106 -39
  69. data/misc/openssl-pg-segfault.rb +31 -0
  70. data/misc/postgres/History.txt +9 -0
  71. data/misc/postgres/Manifest.txt +5 -0
  72. data/misc/postgres/README.txt +21 -0
  73. data/misc/postgres/Rakefile +21 -0
  74. data/misc/postgres/lib/postgres.rb +16 -0
  75. data/misc/ruby-pg/History.txt +9 -0
  76. data/misc/ruby-pg/Manifest.txt +5 -0
  77. data/misc/ruby-pg/README.txt +21 -0
  78. data/misc/ruby-pg/Rakefile +21 -0
  79. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  80. data/pg.gemspec +36 -0
  81. data/rakelib/task_extension.rb +46 -0
  82. data/sample/array_insert.rb +20 -0
  83. data/sample/async_api.rb +102 -0
  84. data/sample/async_copyto.rb +39 -0
  85. data/sample/async_mixed.rb +56 -0
  86. data/sample/check_conn.rb +21 -0
  87. data/sample/copydata.rb +71 -0
  88. data/sample/copyfrom.rb +81 -0
  89. data/sample/copyto.rb +19 -0
  90. data/sample/cursor.rb +21 -0
  91. data/sample/disk_usage_report.rb +177 -0
  92. data/sample/issue-119.rb +94 -0
  93. data/sample/losample.rb +69 -0
  94. data/sample/minimal-testcase.rb +17 -0
  95. data/sample/notify_wait.rb +72 -0
  96. data/sample/pg_statistics.rb +285 -0
  97. data/sample/replication_monitor.rb +222 -0
  98. data/sample/test_binary_values.rb +33 -0
  99. data/sample/wal_shipper.rb +434 -0
  100. data/sample/warehouse_partitions.rb +311 -0
  101. data.tar.gz.sig +0 -0
  102. metadata +138 -223
  103. metadata.gz.sig +0 -0
  104. data/.gemtest +0 -0
  105. data/ChangeLog +0 -6595
  106. data/History.rdoc +0 -422
  107. data/README.ja.rdoc +0 -14
  108. data/README.rdoc +0 -167
  109. data/lib/pg/basic_type_mapping.rb +0 -426
  110. data/lib/pg/constants.rb +0 -11
  111. data/lib/pg/text_decoder.rb +0 -51
  112. data/lib/pg/text_encoder.rb +0 -35
  113. data/spec/data/expected_trace.out +0 -26
  114. data/spec/data/random_binary_data +0 -0
  115. data/spec/helpers.rb +0 -348
  116. data/spec/pg/basic_type_mapping_spec.rb +0 -305
  117. data/spec/pg/connection_spec.rb +0 -1719
  118. data/spec/pg/result_spec.rb +0 -456
  119. data/spec/pg/type_map_by_class_spec.rb +0 -138
  120. data/spec/pg/type_map_by_column_spec.rb +0 -222
  121. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  122. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  123. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  124. data/spec/pg/type_map_spec.rb +0 -22
  125. data/spec/pg/type_spec.rb +0 -777
  126. data/spec/pg_spec.rb +0 -50
@@ -1,222 +0,0 @@
1
- #!/usr/bin/env rspec
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
6
- require 'pg'
7
-
8
-
9
- describe PG::TypeMapByColumn do
10
-
11
- let!(:textenc_int){ PG::TextEncoder::Integer.new name: 'INT4', oid: 23 }
12
- let!(:textdec_int){ PG::TextDecoder::Integer.new name: 'INT4', oid: 23 }
13
- let!(:textenc_float){ PG::TextEncoder::Float.new name: 'FLOAT4', oid: 700 }
14
- let!(:textdec_float){ PG::TextDecoder::Float.new name: 'FLOAT4', oid: 700 }
15
- let!(:textenc_string){ PG::TextEncoder::String.new name: 'TEXT', oid: 25 }
16
- let!(:textdec_string){ PG::TextDecoder::String.new name: 'TEXT', oid: 25 }
17
- let!(:textdec_bytea){ PG::TextDecoder::Bytea.new name: 'BYTEA', oid: 17 }
18
- let!(:binaryenc_bytea){ PG::BinaryEncoder::Bytea.new name: 'BYTEA', oid: 17, format: 1 }
19
- let!(:binarydec_bytea){ PG::BinaryDecoder::Bytea.new name: 'BYTEA', oid: 17, format: 1 }
20
- let!(:pass_through_type) do
21
- type = Class.new(PG::SimpleDecoder) do
22
- def decode(*v)
23
- v
24
- end
25
- end.new
26
- type.oid = 123456
27
- type.format = 1
28
- type.name = 'pass_through'
29
- type
30
- end
31
-
32
- it "should retrieve it's conversions" do
33
- cm = PG::TypeMapByColumn.new( [textdec_int, textenc_string, textdec_float, pass_through_type, nil] )
34
- expect( cm.coders ).to eq( [
35
- textdec_int,
36
- textenc_string,
37
- textdec_float,
38
- pass_through_type,
39
- nil
40
- ] )
41
- expect( cm.inspect ).to eq( "#<PG::TypeMapByColumn INT4:0 TEXT:0 FLOAT4:0 pass_through:1 nil>" )
42
- end
43
-
44
- it "should retrieve it's oids" do
45
- cm = PG::TypeMapByColumn.new( [textdec_int, textdec_string, textdec_float, pass_through_type, nil] )
46
- expect( cm.oids ).to eq( [23, 25, 700, 123456, nil] )
47
- end
48
-
49
- it "should gracefully handle not initialized state" do
50
- # PG::TypeMapByColumn is not initialized in allocate function, like other
51
- # type maps, but in #initialize. So it might be not called by derived classes.
52
-
53
- not_init = Class.new(PG::TypeMapByColumn) do
54
- def initialize
55
- # no super call
56
- end
57
- end.new
58
-
59
- expect{ @conn.exec_params( "SELECT $1", [ 0 ], 0, not_init ) }.to raise_error(NotImplementedError)
60
-
61
- res = @conn.exec( "SELECT 1" )
62
- expect{ res.type_map = not_init }.to raise_error(NotImplementedError)
63
-
64
- @conn.copy_data("COPY (SELECT 1) TO STDOUT") do
65
- decoder = PG::TextDecoder::CopyRow.new(type_map: not_init)
66
- expect{ @conn.get_copy_data(false, decoder) }.to raise_error(NotImplementedError)
67
- @conn.get_copy_data
68
- end
69
- end
70
-
71
-
72
- #
73
- # Encoding Examples
74
- #
75
-
76
- it "should encode integer params" do
77
- col_map = PG::TypeMapByColumn.new( [textenc_int]*3 )
78
- res = @conn.exec_params( "SELECT $1, $2, $3", [ 0, nil, "-999" ], 0, col_map )
79
- expect( res.values ).to eq( [
80
- [ "0", nil, "-999" ],
81
- ] )
82
- end
83
-
84
- it "should encode bytea params" do
85
- data = "'\u001F\\"
86
- col_map = PG::TypeMapByColumn.new( [binaryenc_bytea]*2 )
87
- res = @conn.exec_params( "SELECT $1, $2", [ data, nil ], 0, col_map )
88
- res.type_map = PG::TypeMapByColumn.new( [textdec_bytea]*2 )
89
- expect( res.values ).to eq( [
90
- [ data, nil ],
91
- ] )
92
- end
93
-
94
-
95
- it "should allow hash form parameters for default encoder" do
96
- col_map = PG::TypeMapByColumn.new( [nil, nil] )
97
- hash_param_bin = { value: ["00ff"].pack("H*"), type: 17, format: 1 }
98
- hash_param_nil = { value: nil, type: 17, format: 1 }
99
- res = @conn.exec_params( "SELECT $1, $2",
100
- [ hash_param_bin, hash_param_nil ], 0, col_map )
101
- expect( res.values ).to eq( [["\\x00ff", nil]] )
102
- expect( result_typenames(res) ).to eq( ['bytea', 'bytea'] )
103
- end
104
-
105
- it "should convert hash form parameters to string when using string encoders" do
106
- col_map = PG::TypeMapByColumn.new( [textenc_string, textenc_string] )
107
- hash_param_bin = { value: ["00ff"].pack("H*"), type: 17, format: 1 }
108
- hash_param_nil = { value: nil, type: 17, format: 1 }
109
- res = @conn.exec_params( "SELECT $1::text, $2::text",
110
- [ hash_param_bin, hash_param_nil ], 0, col_map )
111
- expect( res.values ).to eq( [["{:value=>\"\\x00\\xFF\", :type=>17, :format=>1}", "{:value=>nil, :type=>17, :format=>1}"]] )
112
- end
113
-
114
- it "shouldn't allow param mappings with different number of fields" do
115
- expect{
116
- @conn.exec_params( "SELECT $1", [ 123 ], 0, PG::TypeMapByColumn.new([]) )
117
- }.to raise_error(ArgumentError, /mapped columns/)
118
- end
119
-
120
- it "should verify the default type map for query params as well" do
121
- tm1 = PG::TypeMapByColumn.new([])
122
- expect{
123
- @conn.exec_params( "SELECT $1", [ 123 ], 0, PG::TypeMapByColumn.new([nil]).with_default_type_map(tm1) )
124
- }.to raise_error(ArgumentError, /mapped columns/)
125
- end
126
-
127
- it "forwards query param conversions to the #default_type_map" do
128
- tm1 = PG::TypeMapByClass.new
129
- tm1[Integer] = PG::TextEncoder::Integer.new name: 'INT2', oid: 21
130
-
131
- tm2 = PG::TypeMapByColumn.new( [textenc_int, nil, nil] ).with_default_type_map( tm1 )
132
- res = @conn.exec_params( "SELECT $1, $2, $3::TEXT", [1, 2, :abc], 0, tm2 )
133
-
134
- expect( res.ftype(0) ).to eq( 23 ) # tm2
135
- expect( res.ftype(1) ).to eq( 21 ) # tm1
136
- expect( res.getvalue(0,2) ).to eq( "abc" ) # TypeMapAllStrings
137
- end
138
-
139
- #
140
- # Decoding Examples
141
- #
142
-
143
- class Exception_in_decode < PG::SimpleDecoder
144
- def decode(res, tuple, field)
145
- raise "no type decoder defined for tuple #{tuple} field #{field}"
146
- end
147
- end
148
-
149
- it "should raise an error from decode method of type converter" do
150
- res = @conn.exec( "SELECT now()" )
151
- types = Array.new( res.nfields, Exception_in_decode.new )
152
- res.type_map = PG::TypeMapByColumn.new( types )
153
- expect{ res.values }.to raise_error(/no type decoder defined/)
154
- end
155
-
156
- it "should raise an error for invalid params" do
157
- expect{ PG::TypeMapByColumn.new( :WrongType ) }.to raise_error(TypeError, /wrong argument type/)
158
- expect{ PG::TypeMapByColumn.new( [123] ) }.to raise_error(ArgumentError, /invalid/)
159
- end
160
-
161
- it "shouldn't allow result mappings with different number of fields" do
162
- res = @conn.exec( "SELECT 1" )
163
- expect{ res.type_map = PG::TypeMapByColumn.new([]) }.to raise_error(ArgumentError, /mapped columns/)
164
- end
165
-
166
- it "should verify the default type map for result values as well" do
167
- res = @conn.exec( "SELECT 1" )
168
- tm1 = PG::TypeMapByColumn.new([])
169
- expect{
170
- res.type_map = PG::TypeMapByColumn.new([nil]).with_default_type_map(tm1)
171
- }.to raise_error(ArgumentError, /mapped columns/)
172
- end
173
-
174
- it "forwards result value conversions to a TypeMapByOid as #default_type_map" do
175
- # One run with implicit built TypeMapByColumn and another with online lookup
176
- [0, 10].each do |max_rows|
177
- tm1 = PG::TypeMapByOid.new
178
- tm1.add_coder PG::TextDecoder::Integer.new name: 'INT2', oid: 21
179
- tm1.max_rows_for_online_lookup = max_rows
180
-
181
- tm2 = PG::TypeMapByColumn.new( [textdec_int, nil, nil] ).with_default_type_map( tm1 )
182
- res = @conn.exec( "SELECT '1'::INT4, '2'::INT2, '3'::INT8" ).map_types!( tm2 )
183
-
184
- expect( res.getvalue(0,0) ).to eq( 1 ) # tm2
185
- expect( res.getvalue(0,1) ).to eq( 2 ) # tm1
186
- expect( res.getvalue(0,2) ).to eq( "3" ) # TypeMapAllStrings
187
- end
188
- end
189
-
190
- it "forwards get_copy_data conversions to another TypeMapByColumn as #default_type_map" do
191
- tm1 = PG::TypeMapByColumn.new( [textdec_int, nil, nil] )
192
- tm2 = PG::TypeMapByColumn.new( [nil, textdec_int, nil] ).with_default_type_map( tm1 )
193
- decoder = PG::TextDecoder::CopyRow.new(type_map: tm2)
194
- @conn.copy_data("COPY (SELECT 1, 2, 3) TO STDOUT", decoder) do
195
- expect( @conn.get_copy_data ).to eq( [1, 2, '3'] )
196
- @conn.get_copy_data
197
- end
198
- end
199
-
200
- it "will deny copy queries with different column count" do
201
- [[2, 2], [2, 3], [3, 2]].each do |cols1, cols2|
202
- tm1 = PG::TypeMapByColumn.new( [textdec_int, nil, nil][0, cols1] )
203
- tm2 = PG::TypeMapByColumn.new( [nil, textdec_int, nil][0, cols2] ).with_default_type_map( tm1 )
204
- decoder = PG::TextDecoder::CopyRow.new(type_map: tm2)
205
- @conn.copy_data("COPY (SELECT 1, 2, 3) TO STDOUT", decoder) do
206
- expect{ @conn.get_copy_data }.to raise_error(ArgumentError, /number of copy fields/)
207
- @conn.get_copy_data
208
- end
209
- end
210
- end
211
-
212
- #
213
- # Decoding Examples text format
214
- #
215
-
216
- it "should allow mixed type conversions" do
217
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, '2013-06-30'::DATE, 3" )
218
- res.type_map = PG::TypeMapByColumn.new( [textdec_int, textdec_string, textdec_float, pass_through_type, nil] )
219
- expect( res.values ).to eq( [[1, 'a', 2.0, ['2013-06-30', 0, 3], '3' ]] )
220
- end
221
-
222
- end
@@ -1,136 +0,0 @@
1
- #!/usr/bin/env rspec
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
6
- require 'pg'
7
-
8
-
9
- describe PG::TypeMapByMriType do
10
-
11
- let!(:textenc_int){ PG::TextEncoder::Integer.new name: 'INT4', oid: 23 }
12
- let!(:textenc_float){ PG::TextEncoder::Float.new name: 'FLOAT8', oid: 701 }
13
- let!(:textenc_string){ PG::TextEncoder::String.new name: 'TEXT', oid: 25 }
14
- let!(:binaryenc_int){ PG::BinaryEncoder::Int8.new name: 'INT8', oid: 20, format: 1 }
15
- let!(:pass_through_type) do
16
- type = Class.new(PG::SimpleEncoder) do
17
- def encode(*v)
18
- v.inspect
19
- end
20
- end.new
21
- type.oid = 25
22
- type.format = 0
23
- type.name = 'pass_through'
24
- type
25
- end
26
-
27
- let!(:tm) do
28
- tm = PG::TypeMapByMriType.new
29
- tm['T_FIXNUM'] = binaryenc_int
30
- tm['T_FLOAT'] = textenc_float
31
- tm['T_SYMBOL'] = pass_through_type
32
- tm
33
- end
34
-
35
- let!(:derived_tm) do
36
- tm = Class.new(PG::TypeMapByMriType) do
37
- def array_type_map_for(value)
38
- PG::TextEncoder::Array.new name: '_INT4', oid: 1007, elements_type: PG::TextEncoder::Integer.new
39
- end
40
- end.new
41
- tm['T_FIXNUM'] = proc{|value| textenc_int }
42
- tm['T_REGEXP'] = proc{|value| :invalid }
43
- tm['T_ARRAY'] = :array_type_map_for
44
- tm
45
- end
46
-
47
- it "should retrieve all conversions" do
48
- expect( tm.coders ).to eq( {
49
- "T_FIXNUM" => binaryenc_int,
50
- "T_FLOAT" => textenc_float,
51
- "T_SYMBOL" => pass_through_type,
52
- "T_HASH" => nil,
53
- "T_ARRAY" => nil,
54
- "T_BIGNUM" => nil,
55
- "T_CLASS" => nil,
56
- "T_COMPLEX" => nil,
57
- "T_DATA" => nil,
58
- "T_FALSE" => nil,
59
- "T_FILE" => nil,
60
- "T_MODULE" => nil,
61
- "T_OBJECT" => nil,
62
- "T_RATIONAL" => nil,
63
- "T_REGEXP" => nil,
64
- "T_STRING" => nil,
65
- "T_STRUCT" => nil,
66
- "T_TRUE" => nil,
67
- } )
68
- end
69
-
70
- it "should retrieve particular conversions" do
71
- expect( tm['T_FIXNUM'] ).to eq(binaryenc_int)
72
- expect( tm['T_FLOAT'] ).to eq(textenc_float)
73
- expect( tm['T_BIGNUM'] ).to be_nil
74
- expect( derived_tm['T_REGEXP'] ).to be_kind_of(Proc)
75
- expect( derived_tm['T_ARRAY'] ).to eq(:array_type_map_for)
76
- end
77
-
78
- it "should allow deletion of coders" do
79
- tm['T_FIXNUM'] = nil
80
- expect( tm['T_FIXNUM'] ).to be_nil
81
- end
82
-
83
- it "should check MRI type key" do
84
- expect{ tm['NO_TYPE'] }.to raise_error(ArgumentError)
85
- expect{ tm[123] }.to raise_error(TypeError)
86
- expect{ tm['NO_TYPE'] = textenc_float }.to raise_error(ArgumentError)
87
- expect{ tm[123] = textenc_float }.to raise_error(TypeError)
88
- end
89
-
90
- it "forwards query param conversions to the #default_type_map" do
91
- tm1 = PG::TypeMapByColumn.new( [textenc_int, nil, nil] )
92
-
93
- tm2 = PG::TypeMapByMriType.new
94
- tm2['T_FIXNUM'] = PG::TextEncoder::Integer.new name: 'INT2', oid: 21
95
- tm2.default_type_map = tm1
96
-
97
- res = @conn.exec_params( "SELECT $1, $2, $3::TEXT", ['1', 2, 3], 0, tm2 )
98
-
99
- expect( res.ftype(0) ).to eq( 23 ) # tm1
100
- expect( res.ftype(1) ).to eq( 21 ) # tm2
101
- expect( res.getvalue(0,2) ).to eq( "3" ) # TypeMapAllStrings
102
- end
103
-
104
- #
105
- # Decoding Examples
106
- #
107
-
108
- it "should raise an error when used for results" do
109
- res = @conn.exec_params( "SELECT 1", [], 1 )
110
- expect{ res.type_map = tm }.to raise_error(NotImplementedError, /not suitable to map result values/)
111
- end
112
-
113
- #
114
- # Encoding Examples
115
- #
116
-
117
- it "should allow mixed type conversions" do
118
- res = @conn.exec_params( "SELECT $1, $2, $3", [5, 1.23, :TestSymbol], 0, tm )
119
- expect( res.values ).to eq([['5', '1.23', "[:TestSymbol, #{@conn.internal_encoding.inspect}]"]])
120
- expect( res.ftype(0) ).to eq(20)
121
- end
122
-
123
- it "should allow mixed type conversions with derived type map" do
124
- res = @conn.exec_params( "SELECT $1, $2", [6, [7]], 0, derived_tm )
125
- expect( res.values ).to eq([['6', '{7}']])
126
- expect( res.ftype(0) ).to eq(23)
127
- expect( res.ftype(1) ).to eq(1007)
128
- end
129
-
130
- it "should raise TypeError with derived type map" do
131
- expect{
132
- @conn.exec_params( "SELECT $1", [//], 0, derived_tm )
133
- }.to raise_error(TypeError, /argument 1/)
134
- end
135
-
136
- end
@@ -1,149 +0,0 @@
1
- #!/usr/bin/env rspec
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
6
- require 'pg'
7
-
8
-
9
- describe PG::TypeMapByOid do
10
-
11
- let!(:textdec_int){ PG::TextDecoder::Integer.new name: 'INT4', oid: 23 }
12
- let!(:textdec_float){ PG::TextDecoder::Float.new name: 'FLOAT8', oid: 701 }
13
- let!(:textdec_string){ PG::TextDecoder::String.new name: 'TEXT', oid: 25 }
14
- let!(:textdec_bytea){ PG::TextDecoder::Bytea.new name: 'BYTEA', oid: 17 }
15
- let!(:binarydec_float){ PG::BinaryDecoder::Float.new name: 'FLOAT8', oid: 701, format: 1 }
16
- let!(:pass_through_type) do
17
- type = Class.new(PG::SimpleDecoder) do
18
- def decode(*v)
19
- v
20
- end
21
- end.new
22
- type.oid = 1082
23
- type.format = 0
24
- type.name = 'pass_through'
25
- type
26
- end
27
-
28
- let!(:tm) do
29
- tm = PG::TypeMapByOid.new
30
- tm.add_coder textdec_int
31
- tm.add_coder textdec_float
32
- tm.add_coder binarydec_float
33
- tm.add_coder pass_through_type
34
- tm
35
- end
36
-
37
- it "should retrieve it's conversions" do
38
- expect( tm.coders ).to eq( [
39
- textdec_int,
40
- textdec_float,
41
- pass_through_type,
42
- binarydec_float,
43
- ] )
44
- end
45
-
46
- it "should allow deletion of coders" do
47
- expect( tm.rm_coder 0, 701 ).to eq(textdec_float)
48
- expect( tm.rm_coder 0, 701 ).to eq(nil)
49
- expect( tm.rm_coder 1, 701 ).to eq(binarydec_float)
50
- expect( tm.coders ).to eq( [
51
- textdec_int,
52
- pass_through_type,
53
- ] )
54
- end
55
-
56
- it "should check format when deleting coders" do
57
- expect{ tm.rm_coder 2, 123 }.to raise_error(ArgumentError)
58
- expect{ tm.rm_coder -1, 123 }.to raise_error(ArgumentError)
59
- end
60
-
61
- it "should check format when adding coders" do
62
- textdec_int.format = 2
63
- expect{ tm.add_coder textdec_int }.to raise_error(ArgumentError)
64
- textdec_int.format = -1
65
- expect{ tm.add_coder textdec_int }.to raise_error(ArgumentError)
66
- end
67
-
68
- it "should check coder type when adding coders" do
69
- expect{ tm.add_coder :dummy }.to raise_error(ArgumentError)
70
- end
71
-
72
- it "should allow reading and writing max_rows_for_online_lookup" do
73
- expect( tm.max_rows_for_online_lookup ).to eq(10)
74
- tm.max_rows_for_online_lookup = 5
75
- expect( tm.max_rows_for_online_lookup ).to eq(5)
76
- end
77
-
78
- it "should allow building new TypeMapByColumn for a given result" do
79
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, '2013-06-30'::DATE" )
80
- tm2 = tm.build_column_map(res)
81
- expect( tm2 ).to be_a_kind_of(PG::TypeMapByColumn)
82
- expect( tm2.coders ).to eq( [textdec_int, nil, textdec_float, pass_through_type] )
83
- end
84
-
85
- it "forwards result value conversions to another TypeMapByOid as #default_type_map" do
86
- # One run with implicit built TypeMapByColumn and another with online lookup
87
- # for each type map.
88
- [[0, 0], [0, 10], [10, 0], [10, 10]].each do |max_rows1, max_rows2|
89
- tm1 = PG::TypeMapByOid.new
90
- tm1.add_coder PG::TextDecoder::Integer.new name: 'INT2', oid: 21
91
- tm1.max_rows_for_online_lookup = max_rows1
92
-
93
- tm2 = PG::TypeMapByOid.new
94
- tm2.add_coder PG::TextDecoder::Integer.new name: 'INT4', oid: 23
95
- tm2.max_rows_for_online_lookup = max_rows2
96
- tm2.default_type_map = tm1
97
-
98
- res = @conn.exec( "SELECT '1'::INT4, '2'::INT2, '3'::INT8" ).map_types!( tm2 )
99
-
100
- expect( res.getvalue(0,0) ).to eq( 1 ) # tm2
101
- expect( res.getvalue(0,1) ).to eq( 2 ) # tm1
102
- expect( res.getvalue(0,2) ).to eq( "3" ) # TypeMapAllStrings
103
- end
104
- end
105
-
106
- #
107
- # Decoding Examples text format
108
- #
109
-
110
- it "should allow mixed type conversions in text format" do
111
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, '2013-06-30'::DATE" )
112
- res.type_map = tm
113
- expect( res.values ).to eq( [[1, 'a', 2.0, ['2013-06-30', 0, 3] ]] )
114
- end
115
-
116
- it "should build a TypeMapByColumn when assigned and the number of rows is high enough" do
117
- res = @conn.exec( "SELECT generate_series(1,20), 'a', 2.0::FLOAT, '2013-06-30'::DATE" )
118
- res.type_map = tm
119
- expect( res.type_map ).to be_kind_of( PG::TypeMapByColumn )
120
- expect( res.type_map.coders ).to eq( [textdec_int, nil, textdec_float, pass_through_type] )
121
- end
122
-
123
- it "should use TypeMapByOid for online lookup and the number of rows is low enough" do
124
- res = @conn.exec( "SELECT 1, 'a', 2.0::FLOAT, '2013-06-30'::DATE" )
125
- res.type_map = tm
126
- expect( res.type_map ).to be_kind_of( PG::TypeMapByOid )
127
- end
128
-
129
- #
130
- # Decoding Examples binary format
131
- #
132
-
133
- it "should allow mixed type conversions in binary format" do
134
- res = @conn.exec_params( "SELECT 1, 2.0::FLOAT", [], 1 )
135
- res.type_map = tm
136
- expect( res.values ).to eq( [["\x00\x00\x00\x01", 2.0 ]] )
137
- end
138
-
139
- #
140
- # Encoding Examples
141
- #
142
-
143
- it "should raise an error used for query params" do
144
- expect{
145
- @conn.exec_params( "SELECT $1", [5], 0, tm )
146
- }.to raise_error(NotImplementedError, /not suitable to map query params/)
147
- end
148
-
149
- end
@@ -1,164 +0,0 @@
1
- #!/usr/bin/env rspec
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
6
- require 'pg'
7
-
8
-
9
- describe PG::TypeMapInRuby do
10
-
11
- context "result values" do
12
- it "should be usable non-derived" do
13
- tm = PG::TypeMapInRuby.new
14
- res = @conn.exec("select 5").map_types!(tm)
15
- expect( res.getvalue(0,0) ).to eq( "5" )
16
- end
17
-
18
- it "should call derived result mapping methods" do
19
- tm = Class.new(PG::TypeMapInRuby) do
20
- attr_reader :fit_to_result_args
21
-
22
- def fit_to_result(*args)
23
- @fit_to_result_args = args
24
- self
25
- end
26
-
27
- def typecast_result_value(*args)
28
- [args, super]
29
- end
30
- end.new
31
-
32
- res = @conn.exec("select 5,6").map_types!(tm)
33
- expect( res.getvalue(0,1) ).to eq( [[res, 0, 1], "6"] )
34
- expect( tm.fit_to_result_args ).to eq( [res] )
35
- end
36
-
37
- it "should accept only a type map object from fit_to_result" do
38
- tm = Class.new(PG::TypeMapInRuby) do
39
- def fit_to_result(*args)
40
- :invalid
41
- end
42
- end.new
43
-
44
- res = @conn.exec("select 5,6")
45
- expect{ res.map_types!(tm) }.to raise_error(TypeError, /kind of PG::TypeMap/)
46
- end
47
- end
48
-
49
- context "query bind params" do
50
- it "should be usable non-derived" do
51
- tm = PG::TypeMapInRuby.new
52
- res = @conn.exec_params("select $1::int, $2::text", [5, 6], 0, tm)
53
- expect( res.values ).to eq( [["5", "6"]] )
54
- end
55
-
56
- it "should call derived param mapping methods" do
57
- tm = Class.new(PG::TypeMapInRuby) do
58
- attr_reader :fit_to_query_args
59
- attr_reader :typecast_query_param_args
60
-
61
- def fit_to_query(params)
62
- @fit_to_query_args = params
63
- @typecast_query_param_args = []
64
- self
65
- end
66
-
67
- def typecast_query_param(*args)
68
- @typecast_query_param_args << [args, super]
69
- PG::TextEncoder::Integer.new name: 'INT4', oid: 23
70
- end
71
- end.new
72
-
73
- res = @conn.exec_params("select $1, $2", [5, 6], 0, tm)
74
- expect( res.ftype(0) ).to eq( 23 )
75
- expect( tm.fit_to_query_args ).to eq( [5, 6] )
76
- expect( tm.typecast_query_param_args ).to eq( [[[5, 0], nil], [[6, 1], nil]] )
77
- end
78
- end
79
-
80
- context "put_copy_data" do
81
- it "should be usable non-derived" do
82
- tm = PG::TypeMapInRuby.new
83
- ce = PG::TextEncoder::CopyRow.new type_map: tm
84
- res = ce.encode([5, 6])
85
- expect( res ).to eq( "5\t6\n" )
86
- end
87
-
88
- it "should call derived data mapping methods" do
89
- tm = Class.new(PG::TypeMapInRuby) do
90
- attr_reader :fit_to_query_args
91
- attr_reader :typecast_query_param_args
92
-
93
- def fit_to_query(params)
94
- @fit_to_query_args = params
95
- @typecast_query_param_args = []
96
- self
97
- end
98
-
99
- def typecast_query_param(*args)
100
- @typecast_query_param_args << [args, super]
101
- PG::TextEncoder::Integer.new name: 'INT4', oid: 23
102
- end
103
- end.new
104
-
105
- ce = PG::TextEncoder::CopyRow.new type_map: tm
106
- res = ce.encode([5, 6])
107
- expect( res ).to eq( "5\t6\n" )
108
- expect( tm.fit_to_query_args ).to eq( [5, 6] )
109
- expect( tm.typecast_query_param_args ).to eq( [[[5, 0], nil], [[6, 1], nil]] )
110
- end
111
-
112
- it "shouldn't accept invalid return from typecast_query_param" do
113
- tm = Class.new(PG::TypeMapInRuby) do
114
- def typecast_query_param(*args)
115
- :invalid
116
- end
117
- end.new
118
-
119
- ce = PG::TextEncoder::CopyRow.new type_map: tm
120
- expect{ ce.encode([5, 6]) }.to raise_error(TypeError, /nil or kind of PG::Coder/)
121
- end
122
- end
123
-
124
- context "get_copy_data" do
125
- it "should be usable non-derived" do
126
- tm = PG::TypeMapInRuby.new
127
- ce = PG::TextDecoder::CopyRow.new type_map: tm
128
- res = ce.decode("5\t6\n")
129
- expect( res ).to eq( ["5", "6"] )
130
- end
131
-
132
- it "should call derived data mapping methods" do
133
- tm = Class.new(PG::TypeMapInRuby) do
134
- attr_reader :fit_to_copy_get_args
135
-
136
- def fit_to_copy_get(*args)
137
- @fit_to_copy_get_args = args
138
- 0
139
- end
140
-
141
- def typecast_copy_get(field_str, fieldno, format, enc)
142
- [field_str, fieldno, format, enc, super]
143
- end
144
- end.new
145
-
146
- ce = PG::TextDecoder::CopyRow.new type_map: tm
147
- res = ce.decode("5\t6\n")
148
- expect( tm.fit_to_copy_get_args ).to eq( [] )
149
- expect( res ).to eq( [["5", 0, 0, Encoding::UTF_8, "5"], ["6", 1, 0, Encoding::UTF_8, "6"]] )
150
- end
151
-
152
- it "shouldn't accept invalid return from fit_to_copy_get" do
153
- tm = Class.new(PG::TypeMapInRuby) do
154
- def fit_to_copy_get
155
- :invalid
156
- end
157
- end.new
158
-
159
- ce = PG::TextDecoder::CopyRow.new type_map: tm
160
- expect{ ce.decode("5\t6\n") }.to raise_error(TypeError, /kind of Integer/)
161
- end
162
- end
163
-
164
- end
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env rspec
2
- # encoding: utf-8
3
-
4
- require_relative '../helpers'
5
-
6
- require 'pg'
7
-
8
-
9
- describe PG::TypeMap do
10
- let!(:tm){ PG::TypeMap.new }
11
-
12
- it "should raise an error when used for param type casts" do
13
- expect{
14
- @conn.exec_params( "SELECT $1", [5], 0, tm )
15
- }.to raise_error(NotImplementedError, /not suitable to map query params/)
16
- end
17
-
18
- it "should raise an error when used for result type casts" do
19
- res = @conn.exec( "SELECT 1" )
20
- expect{ res.map_types!(tm) }.to raise_error(NotImplementedError, /not suitable to map result values/)
21
- end
22
- end