pg_conn 0.33.1 → 0.35.0
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 +4 -4
- data/lib/pg_conn/version.rb +1 -1
- data/lib/pg_conn.rb +163 -32
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4c942ce055688931946e0d5a71ddc89a722b2dd98ea6d9d0edc150b39421dd9
|
4
|
+
data.tar.gz: 3fea9a99e361c86b3b413845d5f319562051347afe025a27006c80548f822ff4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa391cc15005c51ca01503e33096dacecec5743fa3bf6f28c22d7fd2ad7e14d2e23f48dc2cc0e3e9cade6d77bc359d3b56ebb871015e2db9d08cffcedcf8988f
|
7
|
+
data.tar.gz: 6fd5537fe417a8dac42ad2ac3af16c75a329bcafc93118ae2a375a3ec3368d0dc088163f8dbd87d5b56a8cb357b3bc5c76c6f9ec49618d4d4c6099bee472b423
|
data/lib/pg_conn/version.rb
CHANGED
data/lib/pg_conn.rb
CHANGED
@@ -147,13 +147,40 @@ module PgConn
|
|
147
147
|
attr_reader :session
|
148
148
|
|
149
149
|
# The transaction timestamp of the most recent SQL statement executed by
|
150
|
-
# #exec or #transaction block. The timestamp is without time zone
|
150
|
+
# #exec or #transaction block. The timestamp is without time zone and WRONG
|
151
|
+
# in most cases
|
151
152
|
attr_reader :timestamp
|
152
153
|
|
153
154
|
# The transaction timestamp of the most recent SQL statement executed by
|
154
155
|
# #exec or #transaction block. The timestamp includes the current time zone
|
155
156
|
attr_reader :timestamptz
|
156
157
|
|
158
|
+
# Controls error messages. It can be assigned true, false, nil. True causes
|
159
|
+
# the error message to be printed to standard error, false ignores it, and
|
160
|
+
# nil resets the state to the default given when the connection was
|
161
|
+
# initialized or false if absent. Note that #silent only controls the error
|
162
|
+
# message, the exception is not affected
|
163
|
+
def silent() @options[:silent] end
|
164
|
+
def silent=(value) set_option(:silent, value) end
|
165
|
+
|
166
|
+
# Controls notices. It can be assigned true, false, nil, or a Proc object
|
167
|
+
# that recieves the message. True causes the message to be printed to
|
168
|
+
# standard output, false ignores it, and nil resets the state to the
|
169
|
+
# default given when the connection was initialized or false if absent
|
170
|
+
def notice() @options[:notice] end
|
171
|
+
def notice=(value) set_option(:notice, value) end
|
172
|
+
|
173
|
+
# Controls warnings. It can be assigned true, false, nil, or a Proc object
|
174
|
+
# that recieves the message. True causes the message to be printed to
|
175
|
+
# standard error, false ignores it, and nil resets the state to the default
|
176
|
+
# given when the connection was initialized or false if absent
|
177
|
+
def warning() @options[:warning] end
|
178
|
+
def warning=(value) set_option(:warning, value) end
|
179
|
+
|
180
|
+
# TODO: Move error message handling into the same framework as notice and
|
181
|
+
# warning but we have a name collision just below that would need to be
|
182
|
+
# resolved somehow
|
183
|
+
|
157
184
|
# PG::Error object of the first failed statement in the transaction;
|
158
185
|
# otherwise nil. It is cleared at the beginning of a transaction so be sure
|
159
186
|
# to save it before you run any cleanup code that may initiate new
|
@@ -163,7 +190,7 @@ module PgConn
|
|
163
190
|
# True if the transaction is in a error state
|
164
191
|
def error?() !@error.nil? end
|
165
192
|
|
166
|
-
# Tuple of error message, lineno, and charno of the error object
|
193
|
+
# Tuple of error message, lineno, and charno of the error object. Each
|
167
194
|
# element defaults to nil if not found
|
168
195
|
def err
|
169
196
|
@err ||=
|
@@ -187,13 +214,17 @@ module PgConn
|
|
187
214
|
# if absent in the Postgres error message
|
188
215
|
def errchar = err[2]
|
189
216
|
|
217
|
+
DEFAULT_OPTIONS = { silent: false, notice: false, warning: false }
|
218
|
+
|
190
219
|
# :call-seq:
|
191
|
-
# initialize(dbname = nil, user = nil,
|
192
|
-
# initialize(connection_hash,
|
193
|
-
# initialize(connection_string,
|
194
|
-
# initialize(host, port, dbname, user, password,
|
195
|
-
# initialize(array,
|
196
|
-
# initialize(pg_connection_object)
|
220
|
+
# initialize(dbname = nil, user = nil, **options)
|
221
|
+
# initialize(connection_hash, **options)
|
222
|
+
# initialize(connection_string, **options)
|
223
|
+
# initialize(host, port, dbname, user, password, **options)
|
224
|
+
# initialize(array, **options)
|
225
|
+
# initialize(pg_connection_object, **options)
|
226
|
+
#
|
227
|
+
# options can be :notice, :warning, :field_name_class, :timestamp, :timestamptz
|
197
228
|
#
|
198
229
|
# Initialize a connection object and connect to the database
|
199
230
|
#
|
@@ -216,6 +247,9 @@ module PgConn
|
|
216
247
|
# Symbol (the default) or String. The :timestamp option is used
|
217
248
|
# internally to set the timestamp for transactions
|
218
249
|
#
|
250
|
+
# The :notice and :warning options sets the default output handling this
|
251
|
+
# connection (FIXME fails on copied connections)
|
252
|
+
#
|
219
253
|
# Note that the connection hash and the connection string may support more
|
220
254
|
# parameters than documented here. Consult
|
221
255
|
# https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING
|
@@ -223,13 +257,22 @@ module PgConn
|
|
223
257
|
#
|
224
258
|
# TODO: Change to 'initialize(*args, **opts)'
|
225
259
|
def initialize(*args)
|
260
|
+
# Extract connection level options and leave other options (that should
|
261
|
+
# be the postgres authentication hash - postgres will emit an error if
|
262
|
+
# not)
|
226
263
|
if args.last.is_a?(Hash)
|
227
|
-
|
228
|
-
@
|
229
|
-
|
230
|
-
|
264
|
+
opts = args.last
|
265
|
+
@field_name_class = opts.delete(:field_name_class) || Symbol
|
266
|
+
options = DEFAULT_OPTIONS.transform_values! { |k,v| opts.key?(k) ? opts.delete(k) : v }
|
267
|
+
|
268
|
+
# FIXME: Is this used?
|
269
|
+
@timestamp = opts.delete(:timestamp)
|
270
|
+
@timestamptz = opts.delete(:timestamptz)
|
271
|
+
|
272
|
+
args.pop if opts.empty?
|
231
273
|
else
|
232
274
|
@field_name_class = Symbol
|
275
|
+
options = DEFAULT_OPTIONS
|
233
276
|
end
|
234
277
|
|
235
278
|
# else # We assume that the current user is a postgres superuser
|
@@ -265,12 +308,12 @@ module PgConn
|
|
265
308
|
elsif args.size == 5
|
266
309
|
make_connection args[0], args[1], nil, nil, args[2], args[3], args[4]
|
267
310
|
else
|
268
|
-
raise Error, "Illegal number of
|
311
|
+
raise Error, "Illegal number of arguments: #{args.size}"
|
269
312
|
end
|
270
313
|
|
271
|
-
if @pg_connection
|
272
|
-
# Set a
|
273
|
-
@pg_connection.set_notice_processor { |message|
|
314
|
+
if @pg_connection #&& !using_existing_connection
|
315
|
+
# Set a notice processor that separates notices and warnings
|
316
|
+
@pg_connection.set_notice_processor { |message| message_processor(message) }
|
274
317
|
|
275
318
|
# Auto-convert to ruby types
|
276
319
|
type_map = PG::BasicTypeMapForResults.new(@pg_connection)
|
@@ -279,23 +322,29 @@ module PgConn
|
|
279
322
|
# type "uuid" with oid 2950..' warnings
|
280
323
|
type_map.default_type_map = PG::TypeMapAllStrings.new
|
281
324
|
|
282
|
-
# Timestamp decoder
|
325
|
+
# Timestamp decoder. FIXME What is this? Why only Timestamp and not
|
326
|
+
# Timestamptz?
|
283
327
|
type_map.add_coder PG::TextDecoder::Timestamp.new( # Timestamp without time zone
|
284
328
|
oid: 1114,
|
285
329
|
flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_UTC)
|
286
330
|
|
287
|
-
# Decode anonymous records but note that this is only useful to convert
|
288
|
-
# outermost structure into an array, the elements are not decoded
|
289
|
-
# returned as strings. It is best to avoid anonymous records if
|
331
|
+
# Decode anonymous records but note that this is only useful to convert
|
332
|
+
# the outermost structure into an array, the elements are not decoded
|
333
|
+
# and are returned as strings. It is best to avoid anonymous records if
|
334
|
+
# possible
|
290
335
|
type_map.add_coder PG::TextDecoder::Record.new(
|
291
336
|
oid: 2249
|
292
337
|
)
|
293
338
|
|
294
339
|
@pg_connection.type_map_for_results = type_map
|
295
340
|
@pg_connection.field_name_type = @field_name_class.to_s.downcase.to_sym # Use symbol field names
|
296
|
-
@pg_connection.exec "set client_min_messages to warning;" # Silence warnings
|
297
341
|
end
|
298
342
|
|
343
|
+
# Set options even if there is no connection to avoid special casing
|
344
|
+
# absent options
|
345
|
+
@options, @default_options = {}, DEFAULT_OPTIONS.merge(options)
|
346
|
+
set_options(options) if @pg_connection
|
347
|
+
|
299
348
|
@schema = SchemaMethods.new(self)
|
300
349
|
@role = RoleMethods.new(self)
|
301
350
|
@rdbms = RdbmsMethods.new(self)
|
@@ -307,6 +356,8 @@ module PgConn
|
|
307
356
|
# per-session settings in #initialize? Are they cleared by #reset too?)
|
308
357
|
def reset
|
309
358
|
@pg_connection.reset
|
359
|
+
self.warning = false
|
360
|
+
self.notice = false
|
310
361
|
@pg_connection.exec "set client_min_messages to warning;" # Silence warnings
|
311
362
|
end
|
312
363
|
|
@@ -644,7 +695,7 @@ module PgConn
|
|
644
695
|
# of the function. If the :proc option is true the "function" is assumed
|
645
696
|
# to be a procedure
|
646
697
|
#
|
647
|
-
def call(name, *args, elem_type: nil, silent:
|
698
|
+
def call(name, *args, elem_type: nil, silent: self.silent, proc: false) # :proc may interfere with hashes
|
648
699
|
args_seq = quote_values(args, elem_type: elem_type)
|
649
700
|
if proc
|
650
701
|
pg_exec "call #{name}(#{args_seq})", silent: silent
|
@@ -668,7 +719,7 @@ module PgConn
|
|
668
719
|
end
|
669
720
|
|
670
721
|
# Like #call with :proc set to true
|
671
|
-
def proc(name, *args, silent:
|
722
|
+
def proc(name, *args, silent: self.silent)
|
672
723
|
call(name, *args, silent: silent, proc: true)
|
673
724
|
end
|
674
725
|
|
@@ -776,6 +827,21 @@ module PgConn
|
|
776
827
|
exec %(delete from #{table} where #{constraint})
|
777
828
|
end
|
778
829
|
|
830
|
+
# Execute block with global options and resets afterwards. Currently only
|
831
|
+
# :silent, :notice and :warning is supported. Very useful in RSpec tests
|
832
|
+
#
|
833
|
+
# TODO: :error, :fail, :symbol, :schema, :search_path
|
834
|
+
#
|
835
|
+
def with(**options, &block)
|
836
|
+
begin
|
837
|
+
saved_options = @options.dup
|
838
|
+
set_options(options)
|
839
|
+
yield
|
840
|
+
ensure
|
841
|
+
set_options(saved_options)
|
842
|
+
end
|
843
|
+
end
|
844
|
+
|
779
845
|
# Execute SQL statement(s) in a transaction and return the number of
|
780
846
|
# affected records (if any). Also sets #timestamp unless a transaction is
|
781
847
|
# already in progress. The +sql+ argument can be a command (String) or an
|
@@ -783,8 +849,8 @@ module PgConn
|
|
783
849
|
# that span multiple lines. The empty array is a NOP but the empty string
|
784
850
|
# is not.
|
785
851
|
#
|
786
|
-
# #exec pass Postgres exceptions to the caller unless :fail is false in
|
787
|
-
# it returns nil
|
852
|
+
# #exec pass Postgres exceptions to the caller unless :fail is false in
|
853
|
+
# which case it returns nil if an error occurred
|
788
854
|
#
|
789
855
|
# Note that postgres crashes the whole transaction stack if any error is
|
790
856
|
# met so if you're inside a transaction, the transaction will be in an
|
@@ -792,14 +858,14 @@ module PgConn
|
|
792
858
|
# transaction stack has collapsed
|
793
859
|
#
|
794
860
|
# TODO: Make sure the transaction stack is emptied on postgres errors
|
795
|
-
def exec(sql, commit: true, fail: true, silent:
|
861
|
+
def exec(sql, commit: true, fail: true, silent: self.silent)
|
796
862
|
transaction(commit: commit) { execute(sql, fail: fail, silent: silent) }
|
797
863
|
end
|
798
864
|
|
799
|
-
# Like #exec but returns true/false depending on if the command succeeded
|
800
|
-
#
|
801
|
-
#
|
802
|
-
# should be captured
|
865
|
+
# Like #exec but returns true/false depending on if the command succeeded,
|
866
|
+
# error messages are suppressed by default. There is no corresponding
|
867
|
+
# #execute? method because any failure rolls back the whole transaction
|
868
|
+
# stack. TODO: Check which exceptions that should be captured
|
803
869
|
def exec?(sql, commit: true, silent: true)
|
804
870
|
begin
|
805
871
|
exec(sql, commit: commit, fail: true, silent: silent)
|
@@ -817,7 +883,7 @@ module PgConn
|
|
817
883
|
# unless :fail is false in which case it returns nil
|
818
884
|
#
|
819
885
|
# TODO: Handle postgres exceptions wrt transaction state and stack
|
820
|
-
def execute(sql, fail: true, silent:
|
886
|
+
def execute(sql, fail: true, silent: self.silent)
|
821
887
|
if @pg_connection
|
822
888
|
begin
|
823
889
|
pg_exec(sql, silent: silent)&.cmd_tuples
|
@@ -938,6 +1004,9 @@ module PgConn
|
|
938
1004
|
# PgConn::Rollback exception in which case #transaction returns nil. Note
|
939
1005
|
# that the transaction timestamp is set to the start of the first
|
940
1006
|
# transaction even if transactions are nested
|
1007
|
+
#
|
1008
|
+
# FIXME: There is some strange problem in rspec where an #insert handles
|
1009
|
+
# an exception correctly while #exec, #execute, and #transaction does not
|
941
1010
|
def transaction(commit: true, &block)
|
942
1011
|
if block_given?
|
943
1012
|
result = nil
|
@@ -1102,6 +1171,68 @@ module PgConn
|
|
1102
1171
|
"select #{field_list} from #{table} where #{where_clause}"
|
1103
1172
|
end
|
1104
1173
|
|
1174
|
+
STDOUT_PRODUCER = lambda { |msg| $stdout.puts msg }
|
1175
|
+
STDERR_PRODUCER = lambda { |msg| $stderr.puts msg }
|
1176
|
+
|
1177
|
+
# FIXME Fails if connection is copied - requires a common options object
|
1178
|
+
# that is shared between all connection copies
|
1179
|
+
def set_option(option, value)
|
1180
|
+
case option
|
1181
|
+
when :silent
|
1182
|
+
@options[:silent] =
|
1183
|
+
case value
|
1184
|
+
when true, false; value
|
1185
|
+
when nil; @default_options[:silent]
|
1186
|
+
else
|
1187
|
+
raise ArgumentError, "Illegal value #{value.inspect}"
|
1188
|
+
end
|
1189
|
+
when :notice, :warning
|
1190
|
+
@options[option] =
|
1191
|
+
case value
|
1192
|
+
when true; option == :notice ? STDOUT_PRODUCER : STDERR_PRODUCER
|
1193
|
+
when false; nil
|
1194
|
+
when nil; @default_options[option]
|
1195
|
+
when Proc; value
|
1196
|
+
else
|
1197
|
+
raise ArgumentError, "Illegal value #{value.inspect}"
|
1198
|
+
end
|
1199
|
+
enabled = !@options[option].nil?
|
1200
|
+
if option == :notice
|
1201
|
+
if enabled
|
1202
|
+
@pg_connection.exec "set client_min_messages to notice"
|
1203
|
+
elsif warning
|
1204
|
+
@pg_connection.exec "set client_min_messages to warning"
|
1205
|
+
else
|
1206
|
+
@pg_connection.exec "set client_min_messages to error"
|
1207
|
+
end
|
1208
|
+
elsif !notice
|
1209
|
+
if enabled
|
1210
|
+
@pg_connection.exec "set client_min_messages to notice"
|
1211
|
+
else
|
1212
|
+
@pg_connection.exec "set client_min_messages to error"
|
1213
|
+
end
|
1214
|
+
end
|
1215
|
+
else
|
1216
|
+
raise ArgumentError, "Illegal option: #{option.inspect}"
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def set_options(opts)
|
1221
|
+
opts.each { |k,v| set_option(k,v) if !@options.key?(k) || @options[k] != v }
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
def get_options() @options.dup end
|
1225
|
+
|
1226
|
+
# Called from postgres. Installed in #initialize
|
1227
|
+
def message_processor(message)
|
1228
|
+
case message
|
1229
|
+
when /^NOTICE:\s*(.*)$/; @options[:notice]&.call($1)
|
1230
|
+
when /^WARNING:\s*(.*)$/; @options[:warning]&.call($1)
|
1231
|
+
else
|
1232
|
+
raise "Oops"
|
1233
|
+
end
|
1234
|
+
end
|
1235
|
+
|
1105
1236
|
# :call-seq:
|
1106
1237
|
# pg_exec(string)
|
1107
1238
|
# pg_exec(array)
|
@@ -1121,7 +1252,7 @@ module PgConn
|
|
1121
1252
|
# though
|
1122
1253
|
#
|
1123
1254
|
# TODO: Fix silent by not handling exceptions
|
1124
|
-
def pg_exec(arg, silent:
|
1255
|
+
def pg_exec(arg, silent: self.silent)
|
1125
1256
|
if @pg_connection
|
1126
1257
|
begin
|
1127
1258
|
last_stmt = nil # To make the current SQL statement visible to the rescue clause. FIXME Not used?
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_conn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.35.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|