pg 0.17.1 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +0 -3506
- data/History.rdoc +308 -0
- data/Manifest.txt +35 -19
- data/README-Windows.rdoc +17 -28
- data/README.ja.rdoc +1 -2
- data/README.rdoc +113 -14
- data/Rakefile +67 -30
- data/Rakefile.cross +109 -83
- data/ext/errorcodes.def +101 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +33 -2
- data/ext/extconf.rb +55 -58
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +27 -39
- data/ext/pg.c +262 -130
- data/ext/pg.h +266 -54
- data/ext/pg_binary_decoder.c +229 -0
- data/ext/pg_binary_encoder.c +163 -0
- data/ext/pg_coder.c +561 -0
- data/ext/pg_connection.c +1689 -990
- data/ext/pg_copy_coder.c +599 -0
- data/ext/pg_errors.c +6 -0
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +897 -164
- data/ext/pg_text_decoder.c +987 -0
- data/ext/pg_text_encoder.c +814 -0
- data/ext/pg_tuple.c +549 -0
- data/ext/pg_type_map.c +166 -0
- data/ext/pg_type_map_all_strings.c +116 -0
- data/ext/pg_type_map_by_class.c +244 -0
- data/ext/pg_type_map_by_column.c +313 -0
- data/ext/pg_type_map_by_mri_type.c +284 -0
- data/ext/pg_type_map_by_oid.c +356 -0
- data/ext/pg_type_map_in_ruby.c +299 -0
- data/ext/pg_util.c +149 -0
- data/ext/pg_util.h +65 -0
- data/lib/pg/basic_type_mapping.rb +522 -0
- data/lib/pg/binary_decoder.rb +23 -0
- data/lib/pg/coder.rb +104 -0
- data/lib/pg/connection.rb +153 -41
- data/lib/pg/constants.rb +2 -1
- data/lib/pg/exceptions.rb +2 -1
- data/lib/pg/result.rb +33 -6
- data/lib/pg/text_decoder.rb +46 -0
- data/lib/pg/text_encoder.rb +59 -0
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +16 -0
- data/lib/pg.rb +29 -9
- data/spec/{lib/helpers.rb → helpers.rb} +151 -64
- data/spec/pg/basic_type_mapping_spec.rb +630 -0
- data/spec/pg/connection_spec.rb +1180 -477
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +456 -120
- data/spec/pg/tuple_spec.rb +333 -0
- data/spec/pg/type_map_by_class_spec.rb +138 -0
- data/spec/pg/type_map_by_column_spec.rb +226 -0
- data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
- data/spec/pg/type_map_by_oid_spec.rb +149 -0
- data/spec/pg/type_map_in_ruby_spec.rb +164 -0
- data/spec/pg/type_map_spec.rb +22 -0
- data/spec/pg/type_spec.rb +1123 -0
- data/spec/pg_spec.rb +26 -20
- data.tar.gz.sig +0 -0
- metadata +148 -91
- metadata.gz.sig +0 -0
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -186
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -294
- data/sample/replication_monitor.rb +0 -231
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- data/sample/warehouse_partitions.rb +0 -320
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PG
|
5
|
+
module BinaryDecoder
|
6
|
+
# Convenience classes for timezone options
|
7
|
+
class TimestampUtc < Timestamp
|
8
|
+
def initialize(params={})
|
9
|
+
super(params.merge(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_UTC))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
class TimestampUtcToLocal < Timestamp
|
13
|
+
def initialize(params={})
|
14
|
+
super(params.merge(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class TimestampLocal < Timestamp
|
18
|
+
def initialize(params={})
|
19
|
+
super(params.merge(flags: PG::Coder::TIMESTAMP_DB_LOCAL | PG::Coder::TIMESTAMP_APP_LOCAL))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end # module PG
|
data/lib/pg/coder.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PG
|
5
|
+
|
6
|
+
class Coder
|
7
|
+
|
8
|
+
module BinaryFormatting
|
9
|
+
Params = { format: 1 }
|
10
|
+
def initialize( params={} )
|
11
|
+
super(params.merge(Params))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# Create a new coder object based on the attribute Hash.
|
17
|
+
def initialize(params={})
|
18
|
+
params.each do |key, val|
|
19
|
+
send("#{key}=", val)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def dup
|
24
|
+
self.class.new(to_h)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns coder attributes as Hash.
|
28
|
+
def to_h
|
29
|
+
{
|
30
|
+
oid: oid,
|
31
|
+
format: format,
|
32
|
+
flags: flags,
|
33
|
+
name: name,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(v)
|
38
|
+
self.class == v.class && to_h == v.to_h
|
39
|
+
end
|
40
|
+
|
41
|
+
def marshal_dump
|
42
|
+
Marshal.dump(to_h)
|
43
|
+
end
|
44
|
+
|
45
|
+
def marshal_load(str)
|
46
|
+
initialize Marshal.load(str)
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
str = self.to_s
|
51
|
+
oid_str = " oid=#{oid}" unless oid==0
|
52
|
+
format_str = " format=#{format}" unless format==0
|
53
|
+
name_str = " #{name.inspect}" if name
|
54
|
+
str[-1,0] = "#{name_str} #{oid_str}#{format_str}"
|
55
|
+
str
|
56
|
+
end
|
57
|
+
|
58
|
+
def inspect_short
|
59
|
+
str = case format
|
60
|
+
when 0 then "T"
|
61
|
+
when 1 then "B"
|
62
|
+
else format.to_s
|
63
|
+
end
|
64
|
+
str += "E" if respond_to?(:encode)
|
65
|
+
str += "D" if respond_to?(:decode)
|
66
|
+
|
67
|
+
"#{name || self.class.name}:#{str}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class CompositeCoder < Coder
|
72
|
+
def to_h
|
73
|
+
super.merge!({
|
74
|
+
elements_type: elements_type,
|
75
|
+
needs_quotation: needs_quotation?,
|
76
|
+
delimiter: delimiter,
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
def inspect
|
81
|
+
str = super
|
82
|
+
str[-1,0] = " elements_type=#{elements_type.inspect} #{needs_quotation? ? 'needs' : 'no'} quotation"
|
83
|
+
str
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class CopyCoder < Coder
|
88
|
+
def to_h
|
89
|
+
super.merge!({
|
90
|
+
type_map: type_map,
|
91
|
+
delimiter: delimiter,
|
92
|
+
null_string: null_string,
|
93
|
+
})
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class RecordCoder < Coder
|
98
|
+
def to_h
|
99
|
+
super.merge!({
|
100
|
+
type_map: type_map,
|
101
|
+
})
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end # module PG
|
data/lib/pg/connection.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pg' unless defined?( PG )
|
5
|
+
require 'uri'
|
4
6
|
|
5
7
|
# The PostgreSQL connection class. The interface for this class is based on
|
6
8
|
# {libpq}[http://www.postgresql.org/docs/9.2/interactive/libpq.html], the C
|
@@ -34,48 +36,57 @@ class PG::Connection
|
|
34
36
|
def self::parse_connect_args( *args )
|
35
37
|
return '' if args.empty?
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
hash_arg = args.last.is_a?( Hash ) ? args.pop : {}
|
40
|
+
option_string = ''
|
41
|
+
options = {}
|
40
42
|
|
41
43
|
# Parameter 'fallback_application_name' was introduced in PostgreSQL 9.0
|
42
44
|
# together with PQescapeLiteral().
|
43
|
-
if PG::Connection.instance_methods.find{|m| m.to_sym == :escape_literal }
|
44
|
-
|
45
|
-
appname = PG::Connection.quote_connstr( appname )
|
46
|
-
connopts = ["fallback_application_name=#{appname}"]
|
47
|
-
else
|
48
|
-
connopts = []
|
45
|
+
if PG::Connection.instance_methods.find {|m| m.to_sym == :escape_literal }
|
46
|
+
options[:fallback_application_name] = $0.sub( /^(.{30}).{4,}(.{30})$/ ){ $1+"..."+$2 }
|
49
47
|
end
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
if args.length == 1
|
50
|
+
case args.first
|
51
|
+
when URI, /\A#{URI::ABS_URI_REF}\z/
|
52
|
+
uri = URI(args.first)
|
53
|
+
options.merge!( Hash[URI.decode_www_form( uri.query )] ) if uri.query
|
54
|
+
when /=/
|
55
|
+
# Option string style
|
56
|
+
option_string = args.first.to_s
|
57
|
+
else
|
58
|
+
# Positional parameters
|
59
|
+
options[CONNECT_ARGUMENT_ORDER.first.to_sym] = args.first
|
56
60
|
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Option string style
|
60
|
-
if args.length == 1 && args.first.to_s.index( '=' )
|
61
|
-
connopts.unshift( args.first )
|
62
|
-
|
63
|
-
# Append positional parameters
|
64
61
|
else
|
65
|
-
|
66
|
-
|
62
|
+
max = CONNECT_ARGUMENT_ORDER.length
|
63
|
+
raise ArgumentError,
|
64
|
+
"Extra positional parameter %d: %p" % [ max + 1, args[max] ] if args.length > max
|
67
65
|
|
68
|
-
|
69
|
-
|
70
|
-
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val.to_s)] )
|
66
|
+
CONNECT_ARGUMENT_ORDER.zip( args ) do |(k,v)|
|
67
|
+
options[ k.to_sym ] = v if v
|
71
68
|
end
|
72
69
|
end
|
73
70
|
|
74
|
-
|
71
|
+
options.merge!( hash_arg )
|
72
|
+
|
73
|
+
if uri
|
74
|
+
uri.host = nil if options[:host]
|
75
|
+
uri.port = nil if options[:port]
|
76
|
+
uri.user = nil if options[:user]
|
77
|
+
uri.password = nil if options[:password]
|
78
|
+
uri.path = '' if options[:dbname]
|
79
|
+
uri.query = URI.encode_www_form( options )
|
80
|
+
return uri.to_s.sub( /^#{uri.scheme}:(?!\/\/)/, "#{uri.scheme}://" )
|
81
|
+
else
|
82
|
+
option_string += ' ' unless option_string.empty? && options.empty?
|
83
|
+
return option_string + options.map { |k,v| "#{k}=#{quote_connstr(v)}" }.join( ' ' )
|
84
|
+
end
|
75
85
|
end
|
76
86
|
|
87
|
+
|
77
88
|
# call-seq:
|
78
|
-
# conn.copy_data( sql ) {|sql_result| ... } -> PG::Result
|
89
|
+
# conn.copy_data( sql [, coder] ) {|sql_result| ... } -> PG::Result
|
79
90
|
#
|
80
91
|
# Execute a copy process for transfering data to or from the server.
|
81
92
|
#
|
@@ -99,13 +110,26 @@ class PG::Connection
|
|
99
110
|
# of blocking mode of operation, #copy_data is preferred to raw calls
|
100
111
|
# of #put_copy_data, #get_copy_data and #put_copy_end.
|
101
112
|
#
|
113
|
+
# _coder_ can be a PG::Coder derivation
|
114
|
+
# (typically PG::TextEncoder::CopyRow or PG::TextDecoder::CopyRow).
|
115
|
+
# This enables encoding of data fields given to #put_copy_data
|
116
|
+
# or decoding of fields received by #get_copy_data.
|
117
|
+
#
|
102
118
|
# Example with CSV input format:
|
103
|
-
# conn.exec "create table my_table (a text,b text,c text,d text
|
104
|
-
# conn.copy_data "COPY my_table FROM
|
105
|
-
# conn.put_copy_data "some,
|
106
|
-
# conn.put_copy_data "more,
|
119
|
+
# conn.exec "create table my_table (a text,b text,c text,d text)"
|
120
|
+
# conn.copy_data "COPY my_table FROM STDIN CSV" do
|
121
|
+
# conn.put_copy_data "some,data,to,copy\n"
|
122
|
+
# conn.put_copy_data "more,data,to,copy\n"
|
123
|
+
# end
|
124
|
+
# This creates +my_table+ and inserts two CSV rows.
|
125
|
+
#
|
126
|
+
# The same with text format encoder PG::TextEncoder::CopyRow
|
127
|
+
# and Array input:
|
128
|
+
# enco = PG::TextEncoder::CopyRow.new
|
129
|
+
# conn.copy_data "COPY my_table FROM STDIN", enco do
|
130
|
+
# conn.put_copy_data ['some', 'data', 'to', 'copy']
|
131
|
+
# conn.put_copy_data ['more', 'data', 'to', 'copy']
|
107
132
|
# end
|
108
|
-
# This creates +my_table+ and inserts two rows.
|
109
133
|
#
|
110
134
|
# Example with CSV output format:
|
111
135
|
# conn.copy_data "COPY my_table TO STDOUT CSV" do
|
@@ -114,14 +138,31 @@ class PG::Connection
|
|
114
138
|
# end
|
115
139
|
# end
|
116
140
|
# This prints all rows of +my_table+ to stdout:
|
117
|
-
# "some,
|
118
|
-
# "more,
|
119
|
-
|
141
|
+
# "some,data,to,copy\n"
|
142
|
+
# "more,data,to,copy\n"
|
143
|
+
#
|
144
|
+
# The same with text format decoder PG::TextDecoder::CopyRow
|
145
|
+
# and Array output:
|
146
|
+
# deco = PG::TextDecoder::CopyRow.new
|
147
|
+
# conn.copy_data "COPY my_table TO STDOUT", deco do
|
148
|
+
# while row=conn.get_copy_data
|
149
|
+
# p row
|
150
|
+
# end
|
151
|
+
# end
|
152
|
+
# This receives all rows of +my_table+ as ruby array:
|
153
|
+
# ["some", "data", "to", "copy"]
|
154
|
+
# ["more", "data", "to", "copy"]
|
155
|
+
|
156
|
+
def copy_data( sql, coder=nil )
|
120
157
|
res = exec( sql )
|
121
158
|
|
122
159
|
case res.result_status
|
123
160
|
when PGRES_COPY_IN
|
124
161
|
begin
|
162
|
+
if coder
|
163
|
+
old_coder = self.encoder_for_put_copy_data
|
164
|
+
self.encoder_for_put_copy_data = coder
|
165
|
+
end
|
125
166
|
yield res
|
126
167
|
rescue Exception => err
|
127
168
|
errmsg = "%s while copy data: %s" % [ err.class.name, err.message ]
|
@@ -131,10 +172,16 @@ class PG::Connection
|
|
131
172
|
else
|
132
173
|
put_copy_end
|
133
174
|
get_last_result
|
175
|
+
ensure
|
176
|
+
self.encoder_for_put_copy_data = old_coder if coder
|
134
177
|
end
|
135
178
|
|
136
179
|
when PGRES_COPY_OUT
|
137
180
|
begin
|
181
|
+
if coder
|
182
|
+
old_coder = self.decoder_for_get_copy_data
|
183
|
+
self.decoder_for_get_copy_data = coder
|
184
|
+
end
|
138
185
|
yield res
|
139
186
|
rescue Exception => err
|
140
187
|
cancel
|
@@ -145,7 +192,7 @@ class PG::Connection
|
|
145
192
|
raise
|
146
193
|
else
|
147
194
|
res = get_last_result
|
148
|
-
if res.result_status != PGRES_COMMAND_OK
|
195
|
+
if !res || res.result_status != PGRES_COMMAND_OK
|
149
196
|
while get_copy_data
|
150
197
|
end
|
151
198
|
while get_result
|
@@ -153,6 +200,8 @@ class PG::Connection
|
|
153
200
|
raise PG::NotAllCopyDataRetrieved, "Not all COPY data retrieved"
|
154
201
|
end
|
155
202
|
res
|
203
|
+
ensure
|
204
|
+
self.decoder_for_get_copy_data = old_coder if coder
|
156
205
|
end
|
157
206
|
|
158
207
|
else
|
@@ -172,8 +221,71 @@ class PG::Connection
|
|
172
221
|
return self.class.conndefaults
|
173
222
|
end
|
174
223
|
|
175
|
-
|
224
|
+
### Return the Postgres connection defaults structure as a Hash keyed by option
|
225
|
+
### keyword (as a Symbol).
|
226
|
+
###
|
227
|
+
### See also #conndefaults
|
228
|
+
def self.conndefaults_hash
|
229
|
+
return self.conndefaults.each_with_object({}) do |info, hash|
|
230
|
+
hash[ info[:keyword].to_sym ] = info[:val]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
### Returns a Hash with connection defaults. See ::conndefaults_hash
|
235
|
+
### for details.
|
236
|
+
def conndefaults_hash
|
237
|
+
return self.class.conndefaults_hash
|
238
|
+
end
|
239
|
+
|
240
|
+
# Method 'conninfo' was introduced in PostgreSQL 9.3.
|
241
|
+
if self.instance_methods.find{|m| m.to_sym == :conninfo }
|
176
242
|
|
177
|
-
|
178
|
-
|
243
|
+
### Return the Postgres connection info structure as a Hash keyed by option
|
244
|
+
### keyword (as a Symbol).
|
245
|
+
###
|
246
|
+
### See also #conninfo
|
247
|
+
def conninfo_hash
|
248
|
+
return self.conninfo.each_with_object({}) do |info, hash|
|
249
|
+
hash[ info[:keyword].to_sym ] = info[:val]
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
179
253
|
|
254
|
+
# Method 'ssl_attribute' was introduced in PostgreSQL 9.5.
|
255
|
+
if self.instance_methods.find{|m| m.to_sym == :ssl_attribute }
|
256
|
+
# call-seq:
|
257
|
+
# conn.ssl_attributes -> Hash<String,String>
|
258
|
+
#
|
259
|
+
# Returns SSL-related information about the connection as key/value pairs
|
260
|
+
#
|
261
|
+
# The available attributes varies depending on the SSL library being used,
|
262
|
+
# and the type of connection.
|
263
|
+
#
|
264
|
+
# See also #ssl_attribute
|
265
|
+
def ssl_attributes
|
266
|
+
ssl_attribute_names.each.with_object({}) do |n,h|
|
267
|
+
h[n] = ssl_attribute(n)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
REDIRECT_METHODS = {
|
273
|
+
:exec => [:async_exec, :sync_exec],
|
274
|
+
:query => [:async_exec, :sync_exec],
|
275
|
+
:exec_params => [:async_exec_params, :sync_exec_params],
|
276
|
+
:prepare => [:async_prepare, :sync_prepare],
|
277
|
+
:exec_prepared => [:async_exec_prepared, :sync_exec_prepared],
|
278
|
+
:describe_portal => [:async_describe_portal, :sync_describe_portal],
|
279
|
+
:describe_prepared => [:async_describe_prepared, :sync_describe_prepared],
|
280
|
+
}
|
281
|
+
|
282
|
+
def self.async_api=(enable)
|
283
|
+
REDIRECT_METHODS.each do |ali, (async, sync)|
|
284
|
+
remove_method(ali) if method_defined?(ali)
|
285
|
+
alias_method( ali, enable ? async : sync )
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# pg-1.1.0+ defaults to libpq's async API for query related blocking methods
|
290
|
+
self.async_api = true
|
291
|
+
end # class PG::Connection
|
data/lib/pg/constants.rb
CHANGED
data/lib/pg/exceptions.rb
CHANGED
data/lib/pg/result.rb
CHANGED
@@ -1,16 +1,43 @@
|
|
1
|
-
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pg' unless defined?( PG )
|
4
5
|
|
5
6
|
|
6
7
|
class PG::Result
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
# Apply a type map for all value retrieving methods.
|
10
|
+
#
|
11
|
+
# +type_map+: a PG::TypeMap instance.
|
12
|
+
#
|
13
|
+
# This method is equal to #type_map= , but returns self, so that calls can be chained.
|
14
|
+
#
|
15
|
+
# See also PG::BasicTypeMapForResults
|
16
|
+
def map_types!(type_map)
|
17
|
+
self.type_map = type_map
|
18
|
+
return self
|
19
|
+
end
|
20
|
+
|
21
|
+
# Set the data type for all field name returning methods.
|
22
|
+
#
|
23
|
+
# +type+: a Symbol defining the field name type.
|
24
|
+
#
|
25
|
+
# This method is equal to #field_name_type= , but returns self, so that calls can be chained.
|
26
|
+
def field_names_as(type)
|
27
|
+
self.field_name_type = type
|
28
|
+
return self
|
29
|
+
end
|
30
|
+
|
31
|
+
### Return a String representation of the object suitable for debugging.
|
32
|
+
def inspect
|
33
|
+
str = self.to_s
|
34
|
+
str[-1,0] = if cleared?
|
35
|
+
" cleared"
|
36
|
+
else
|
37
|
+
" status=#{res_status(result_status)} ntuples=#{ntuples} nfields=#{nfields} cmd_tuples=#{cmd_tuples}"
|
38
|
+
end
|
39
|
+
return str
|
11
40
|
end
|
12
41
|
|
13
42
|
end # class PG::Result
|
14
43
|
|
15
|
-
# Backward-compatible alias
|
16
|
-
PGresult = PG::Result
|