pg_conn 0.35.0 → 0.35.1

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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pg_conn/version.rb +1 -1
  3. data/lib/pg_conn.rb +183 -102
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4c942ce055688931946e0d5a71ddc89a722b2dd98ea6d9d0edc150b39421dd9
4
- data.tar.gz: 3fea9a99e361c86b3b413845d5f319562051347afe025a27006c80548f822ff4
3
+ metadata.gz: 7c834402fcec956ffcb288fa201d7a6bade6b435002ae4758e1d86ea54f5a656
4
+ data.tar.gz: 20fafcbbe4c9f93ab426c6012e91f073e5224ab84d23948da894f4a64b5ef7c9
5
5
  SHA512:
6
- metadata.gz: aa391cc15005c51ca01503e33096dacecec5743fa3bf6f28c22d7fd2ad7e14d2e23f48dc2cc0e3e9cade6d77bc359d3b56ebb871015e2db9d08cffcedcf8988f
7
- data.tar.gz: 6fd5537fe417a8dac42ad2ac3af16c75a329bcafc93118ae2a375a3ec3368d0dc088163f8dbd87d5b56a8cb357b3bc5c76c6f9ec49618d4d4c6099bee472b423
6
+ metadata.gz: 1da57a0c7f8daffdaac879899d3bd7d9723a6512e038afda6996329717d9b0246f7b646161ee1f0a82e00d828a12b9328f212ef98b47132914e4c66dc9f1e888
7
+ data.tar.gz: 4fd13dd8b4130ebb417379dd3ec62a3476f7d721a7617d14ae2f5b88a0c1f13812dbd440931bc14c02c3db702f9ff181a8b4ab3116a08527293ae6b632c9cd0b
@@ -1,3 +1,3 @@
1
1
  module PgConn
2
- VERSION = "0.35.0"
2
+ VERSION = "0.35.1"
3
3
  end
data/lib/pg_conn.rb CHANGED
@@ -53,9 +53,9 @@ module PgConn
53
53
  # true/false, Time/Date/DateTime, and arrays. Other types may require
54
54
  # special handling
55
55
  #
56
- # Hashes are quoted as a literal JSON expression. The result is a string
57
- # and it is the application's responsibility to cast them to either 'json'
58
- # or 'jsonb'
56
+ # Hashes are quoted as a literal JSON expression converted into the given
57
+ # :json_type. If :json_type is nil, it is the application's responsibility to
58
+ # cast them to either 'json' or 'jsonb'
59
59
  #
60
60
  # Note that a tuple value (an array) must be quoted using #quote_tuple
61
61
  # because #quote_value would quote the tuple as an array value instead of a
@@ -66,7 +66,7 @@ module PgConn
66
66
  # type when the argument is an empty array. It is not needed if the array
67
67
  # is guaranteed to be non-empty. Nested arrays are not supported
68
68
  #
69
- def self.quote_value(value, elem_type: nil)
69
+ def self.quote_value(value, elem_type: nil, json_type: nil)
70
70
  case value
71
71
  when Literal; value
72
72
  when String; escape_literal(value)
@@ -82,32 +82,34 @@ module PgConn
82
82
  else
83
83
  "array[#{value.map { |elem| quote_value(elem) }.join(', ')}]"
84
84
  end
85
- when Hash; "'#{value.to_json}'"
85
+ when Hash; ["'#{value.to_json}'", json_type].compact.join('::')
86
86
  else
87
87
  escape_literal(value.to_s)
88
88
  end
89
89
  end
90
90
 
91
91
  # Quote values and concatenate them using ',' as separator
92
- def self.quote_values(values, elem_type: nil)
93
- values.map { |value| quote_value(value, elem_type: elem_type) }.join(", ")
92
+ def self.quote_values(values, **opts)
93
+ values.map { |value| quote_value(value, **opts) }.join(", ")
94
94
  end
95
95
 
96
96
  # Quote an array of values as a tuple. The element types should be in the
97
97
  # same order as the array arguments. #quote_tuples is same as #quote_values
98
98
  # except the values may have different types (this makes no difference
99
99
  # except in the case when the tuple may contain empty array(s))
100
- def self.quote_tuple(tuple, elem_types: nil)
100
+ #
101
+ # Note that it is :elem_types (plural) and not :elem_type
102
+ def self.quote_tuple(tuple, elem_types: nil, **opts)
101
103
  elem_types = Array(elem_types)
102
104
  tuple.map { |value|
103
105
  elem_type = value.is_a?(Array) ? elem_types&.shift : nil
104
- quote_value(value, elem_type: elem_type)
106
+ quote_value(value, **opts, elem_type: elem_type)
105
107
  }.join(", ")
106
108
  end
107
109
 
108
110
  # Quote an array of tuples
109
- def self.quote_tuples(tuples, elem_types: nil)
110
- tuples.map { |tuple| "(#{quote_tuple(tuple, elem_types: elem_types)})" }.join(", ")
111
+ def self.quote_tuples(tuples, **opts)
112
+ tuples.map { |tuple| "(#{quote_tuple(tuple, **opts)})" }.join(", ")
111
113
  end
112
114
 
113
115
  # Used to mark strings as literals that should not be quoted. This is the
@@ -125,6 +127,9 @@ module PgConn
125
127
  # The class of column names (Symbol or String). Default is Symbol
126
128
  attr_reader :field_name_class
127
129
 
130
+ # Default postgres JSON type (either 'json' or 'jsonb'). Default is 'jsonb'
131
+ attr_reader :default_json_type
132
+
128
133
  # Name of user
129
134
  def user() @pg_connection.user end
130
135
  alias_method :username, :user # Obsolete FIXME Is it?
@@ -155,28 +160,56 @@ module PgConn
155
160
  # #exec or #transaction block. The timestamp includes the current time zone
156
161
  attr_reader :timestamptz
157
162
 
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
+ # Controls error messages. It can be assigned true, false, nil, or a Proc
164
+ # object that recieves the message. True causes the message to be printed
165
+ # to standard error, false ignores it, and nil resets the state to the
166
+ # default given when the connection was initialized. #silent? returns true
167
+ # if #silent is false or a Proc object and should be used instead #silent
168
+ # to check the state because #silent returns truish when output is
169
+ # redirected to a Proc
170
+ #
171
+ # Note that #silent=, #notice=, and warning= only controls the error
172
+ # message, the exception is passed through unaltered
173
+ #
163
174
  def silent() @options[:silent] end
175
+ def silent?() @producers[:silent].nil? end # silent == false/Proc is true
164
176
  def silent=(value) set_option(:silent, value) end
165
177
 
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
178
  # Controls warnings. It can be assigned true, false, nil, or a Proc object
174
179
  # that recieves the message. True causes the message to be printed to
175
180
  # standard error, false ignores it, and nil resets the state to the default
176
- # given when the connection was initialized or false if absent
181
+ # given when the connection was initialized
177
182
  def warning() @options[:warning] end
183
+ def warning?() !warning.nil? end
178
184
  def warning=(value) set_option(:warning, value) end
179
185
 
186
+ # Controls notice messages. It can be assigned true, false, nil, or a Proc
187
+ # object that recieves the message. True causes the message to be printed
188
+ # to standard error, false ignores it, and nil resets the state to the
189
+ # default given when the connection was initialized. Default false
190
+ def notice() @options[:notice] end
191
+ def notice?() !notice.nil? end
192
+ def notice=(value) set_option(:notice, value) end
193
+
194
+ # Controls info messages. It can be assigned true, false, nil, or a Proc
195
+ # object that recieves the message. True causes the message to be printed
196
+ # to standard output, false ignores it, and nil resets the state to the
197
+ # default given when the connection was initialized. Default false. Note
198
+ # that #info is the only level that outputs to standard output
199
+ def info() @options[:info] end
200
+ def info?() !info.nil? end
201
+ def info=(value) set_option(:info, value) end
202
+
203
+ # Controls debug messages. It can be assigned true, false, nil, or a Proc
204
+ # object that recieves the message. True causes the message to be printed
205
+ # to standard error, false ignores it, and nil resets the state to the
206
+ # default given when the connection was initialized. Default false
207
+ def debug() @options[:debug] end
208
+ def debug?() !debug.nil? end
209
+ def debug=(value) set_option(:debug, value) end
210
+
211
+ DEFAULT_OPTIONS = { silent: false, warning: true, notice: false, info: false, debug: false }
212
+
180
213
  # TODO: Move error message handling into the same framework as notice and
181
214
  # warning but we have a name collision just below that would need to be
182
215
  # resolved somehow
@@ -214,8 +247,6 @@ module PgConn
214
247
  # if absent in the Postgres error message
215
248
  def errchar = err[2]
216
249
 
217
- DEFAULT_OPTIONS = { silent: false, notice: false, warning: false }
218
-
219
250
  # :call-seq:
220
251
  # initialize(dbname = nil, user = nil, **options)
221
252
  # initialize(connection_hash, **options)
@@ -247,8 +278,10 @@ module PgConn
247
278
  # Symbol (the default) or String. The :timestamp option is used
248
279
  # internally to set the timestamp for transactions
249
280
  #
250
- # The :notice and :warning options sets the default output handling this
251
- # connection (FIXME fails on copied connections)
281
+ # The :notice and :warning options sets the default output handling for this
282
+ # connection (FIXME fails on copied connections). Default is to suppress
283
+ # notices and lower - this is diffent from postgres that by default include
284
+ # notices
252
285
  #
253
286
  # Note that the connection hash and the connection string may support more
254
287
  # parameters than documented here. Consult
@@ -263,7 +296,17 @@ module PgConn
263
296
  if args.last.is_a?(Hash)
264
297
  opts = args.last
265
298
  @field_name_class = opts.delete(:field_name_class) || Symbol
266
- options = DEFAULT_OPTIONS.transform_values! { |k,v| opts.key?(k) ? opts.delete(k) : v }
299
+
300
+ # Extract options from arguments
301
+ options = DEFAULT_OPTIONS.to_h { |k,v|
302
+ r = if opts.key?(k)
303
+ value = opts.delete(k)
304
+ value.nil? ? v : value
305
+ else
306
+ v
307
+ end
308
+ [k, r]
309
+ }
267
310
 
268
311
  # FIXME: Is this used?
269
312
  @timestamp = opts.delete(:timestamp)
@@ -272,7 +315,7 @@ module PgConn
272
315
  args.pop if opts.empty?
273
316
  else
274
317
  @field_name_class = Symbol
275
- options = DEFAULT_OPTIONS
318
+ options = DEFAULT_OPTIONS.dup
276
319
  end
277
320
 
278
321
  # else # We assume that the current user is a postgres superuser
@@ -340,11 +383,17 @@ module PgConn
340
383
  @pg_connection.field_name_type = @field_name_class.to_s.downcase.to_sym # Use symbol field names
341
384
  end
342
385
 
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
-
386
+ # Set options. The initial options also serves as default values and are
387
+ # themselves initialized using DEFAULT_VALUES
388
+ #
389
+ # Note that options is initialized even if there is no connection to
390
+ # avoid special casing
391
+ @default_options = options
392
+ @options = {}
393
+ @producers = {} # Map from message level to Proc or nil
394
+ set_options(@default_options) if @pg_connection
395
+
396
+ @default_json_type = :jsonb
348
397
  @schema = SchemaMethods.new(self)
349
398
  @role = RoleMethods.new(self)
350
399
  @rdbms = RdbmsMethods.new(self)
@@ -385,12 +434,13 @@ module PgConn
385
434
  def literal(arg) Literal.new(arg) end
386
435
 
387
436
  # Connection member method variations of the PgConn quote class methods
437
+ # with at least a default value for :json_type
388
438
  def quote_identifier(s) = PgConn.quote_identifier(s)
389
439
  def quote_identifiers(idents) = PgConn.quote_identifiers(idents)
390
- def quote_value(value, **opts) = PgConn.quote_value(value, **opts)
391
- def quote_values(values, **opts) = PgConn.quote_values(values, **opts)
392
- def quote_tuple(tuple, **opts) = PgConn.quote_tuple(tuple, **opts)
393
- def quote_tuples(tuples, **opts) = PgConn.quote_tuples(tuples, **opts)
440
+ def quote_value(value, **opts) = PgConn.quote_value(value, json_type: self.default_json_type, **opts)
441
+ def quote_values(values, **opts) = PgConn.quote_values(values, json_type: self.default_json_type, **opts)
442
+ def quote_tuple(tuple, **opts) = PgConn.quote_tuple(tuple, json_type: self.default_json_type, **opts)
443
+ def quote_tuples(tuples, **opts) = PgConn.quote_tuples(tuples, json_type: self.default_json_type, **opts)
394
444
 
395
445
  # Quote a record and cast it into the given type, the type can also be a
396
446
  # table or view. 'data' is an array, hash, or struct representation of the
@@ -403,14 +453,14 @@ module PgConn
403
453
  #
404
454
  # Also note that there is not class-method variant of this method because
405
455
  # it requires a connection
406
- def quote_record(data, schema_name = nil, type, elem_types: nil)
407
- quote_record_impl(data, schema_name, type, elem_types: elem_types, array: false)
456
+ def quote_record(data, schema_name = nil, type, **opts)
457
+ quote_record_impl(data, schema_name, type, array: false, **opts)
408
458
  end
409
459
 
410
460
  # Quote an array of records. The type is the record type, not the type of
411
461
  # the enclosing array
412
- def quote_records(data, schema_name = nil, type, elem_types: nil)
413
- quote_record_impl(data, schema_name, type, elem_types: elem_types, array: true)
462
+ def quote_records(data, schema_name = nil, type, **opts)
463
+ quote_record_impl(data, schema_name, type, array: true, **opts)
414
464
  end
415
465
 
416
466
  # :call-seq:
@@ -692,11 +742,11 @@ module PgConn
692
742
  # columns (like #tuples).
693
743
  #
694
744
  # The name argument can be a String or a Symbol that may contain the schema
695
- # of the function. If the :proc option is true the "function" is assumed
745
+ # of the function. If the :proc option is true the "function" is assumed
696
746
  # to be a procedure
697
747
  #
698
- def call(name, *args, elem_type: nil, silent: self.silent, proc: false) # :proc may interfere with hashes
699
- args_seq = quote_values(args, elem_type: elem_type)
748
+ def call(name, *args, silent: self.silent, proc: false, **opts) # :proc may interfere with hashes
749
+ args_seq = quote_values(args, **opts)
700
750
  if proc
701
751
  pg_exec "call #{name}(#{args_seq})", silent: silent
702
752
  return nil
@@ -719,8 +769,8 @@ module PgConn
719
769
  end
720
770
 
721
771
  # Like #call with :proc set to true
722
- def proc(name, *args, silent: self.silent)
723
- call(name, *args, silent: silent, proc: true)
772
+ def proc(name, *args, json_type: self.default_json_type, silent: self.silent)
773
+ call(name, *args, silent: silent, proc: true, json_type: json_type)
724
774
  end
725
775
 
726
776
  # :call-seq:
@@ -859,7 +909,14 @@ module PgConn
859
909
  #
860
910
  # TODO: Make sure the transaction stack is emptied on postgres errors
861
911
  def exec(sql, commit: true, fail: true, silent: self.silent)
862
- transaction(commit: commit) { execute(sql, fail: fail, silent: silent) }
912
+ transaction(commit: commit) {
913
+ begin
914
+ execute(sql, fail: fail, silent: silent)
915
+ rescue PG::Error
916
+ cancel_transaction
917
+ raise
918
+ end
919
+ }
863
920
  end
864
921
 
865
922
  # Like #exec but returns true/false depending on if the command succeeded,
@@ -888,7 +945,6 @@ module PgConn
888
945
  begin
889
946
  pg_exec(sql, silent: silent)&.cmd_tuples
890
947
  rescue PG::Error
891
- cancel_transaction
892
948
  raise if fail
893
949
  return nil
894
950
  end
@@ -954,9 +1010,9 @@ module PgConn
954
1010
  # file instead of being executed. Maybe remove logging (or execute always
955
1011
  # and log as a side-effect)
956
1012
  if @pg_connection
957
- @timestamp, @timestamptz = @pg_connection.exec(
958
- 'select current_timestamp::timestamp without time zone, current_timestamp'
959
- ).tuple_values(0)
1013
+ @timestamp, @timestamptz = @pg_connection.exec(
1014
+ 'select current_timestamp::timestamp without time zone, current_timestamp'
1015
+ ).tuple_values(0)
960
1016
  end
961
1017
  end
962
1018
  end
@@ -987,9 +1043,16 @@ module PgConn
987
1043
  # progress, the method always succeeds
988
1044
  def cancel_transaction
989
1045
  begin
990
- pg_exec("rollback")
1046
+ # The transaction may be invalid to we can't use #set_option to silence
1047
+ # warnings when the transaction is rolled back. Instead we manipulate the
1048
+ # procudure method
1049
+ saved_producer = @producers[:warning]
1050
+ @producers[:warning] = nil
1051
+ pg_exec("rollback", silent: true)
991
1052
  rescue PG::Error
992
1053
  ;
1054
+ ensure
1055
+ @producers[:warning] = saved_producer
993
1056
  end
994
1057
  @savepoints = nil
995
1058
  true
@@ -1018,7 +1081,6 @@ module PgConn
1018
1081
  return nil
1019
1082
  rescue PG::Error
1020
1083
  cancel_transaction
1021
- @savepoints = nil
1022
1084
  raise
1023
1085
  end
1024
1086
  pop_transaction(commit: commit, fail: false)
@@ -1102,7 +1164,10 @@ module PgConn
1102
1164
  #
1103
1165
  # Note that #quote_record_impl queries the database for information about
1104
1166
  # the type. TODO Cache this information?
1105
- def quote_record_impl(datas, schema_name = nil, type, elem_types: nil, array: nil)
1167
+ def quote_record_impl(
1168
+ datas, schema_name = nil, type, elem_types: nil, array: nil, **opts)
1169
+ datas = [datas] if !array
1170
+
1106
1171
  pg_type = [schema_name, type].compact.join('.')
1107
1172
  fields = self.values(%(
1108
1173
  select attname
@@ -1114,8 +1179,6 @@ module PgConn
1114
1179
  order by attnum
1115
1180
  )).map(&:to_sym)
1116
1181
 
1117
- datas = [datas] if !array
1118
-
1119
1182
  literals = datas.map { |data|
1120
1183
  values =
1121
1184
  case data
@@ -1125,10 +1188,11 @@ module PgConn
1125
1188
  else
1126
1189
  raise Error, "Illegal value #{data.inspect}"
1127
1190
  end
1128
- "(#{quote_tuple(values, elem_types: elem_types)})::#{pg_type}"
1191
+ "(#{quote_tuple(values, elem_types: elem_types, **opts)})::#{pg_type}"
1129
1192
  }
1130
1193
 
1131
1194
  if array
1195
+ # papg_type(table, where_clause, fields...)
1132
1196
  "array[#{literals.join(', ')}]::#{pg_type}[]"
1133
1197
  else
1134
1198
  literals.first
@@ -1138,7 +1202,6 @@ module PgConn
1138
1202
  # :call-seq
1139
1203
  # parse_query(query)
1140
1204
  # parse_query(table, id, fields...)
1141
- # parse_query(table, where_clause, fields...)
1142
1205
  # parse_query(table, hash, fields...)
1143
1206
  # parse_query(table, fields...)
1144
1207
  #
@@ -1173,44 +1236,57 @@ module PgConn
1173
1236
 
1174
1237
  STDOUT_PRODUCER = lambda { |msg| $stdout.puts msg }
1175
1238
  STDERR_PRODUCER = lambda { |msg| $stderr.puts msg }
1239
+ ERROR_PRODUCER = lambda { |msg, stmt| $stderr.puts stmt, nil, msg; $stderr.flush }
1240
+
1241
+ # Map from message level to default producer. Note that we rely on the key
1242
+ # order to determine the minimum message level in #set_option below
1243
+ DEFAULT_PRODUCER = {
1244
+ debug: STDERR_PRODUCER,
1245
+ info: STDOUT_PRODUCER,
1246
+ notice: STDERR_PRODUCER,
1247
+ warning: STDERR_PRODUCER,
1248
+ error: STDERR_PRODUCER
1249
+ }
1176
1250
 
1177
1251
  # FIXME Fails if connection is copied - requires a common options object
1178
1252
  # that is shared between all connection copies
1179
1253
  def set_option(option, value)
1254
+ # Assign default
1255
+ value = @default_options[option] if value.nil?
1256
+
1257
+ # Find current message level
1258
+ old_level = DEFAULT_PRODUCER.keys.find { |level| @producers[level] } || :error
1259
+
1260
+ # Set new value. Can be true, false, or a Proc object
1261
+ @options[option] = value
1262
+
1263
+ # Set producer
1180
1264
  case option
1181
1265
  when :silent
1182
- @options[:silent] =
1266
+ @producers[:silent] =
1183
1267
  case value
1184
- when true, false; value
1185
- when nil; @default_options[:silent]
1268
+ when true; nil
1269
+ when false; ERROR_PRODUCER
1270
+ when Proc; value
1186
1271
  else
1187
- raise ArgumentError, "Illegal value #{value.inspect}"
1272
+ raise ArgumentError, "Illegal value: #{value.inspect}"
1188
1273
  end
1189
- when :notice, :warning
1190
- @options[option] =
1274
+ when :debug, :info, :notice, :warning
1275
+ @producers[option] =
1191
1276
  case value
1192
- when true; option == :notice ? STDOUT_PRODUCER : STDERR_PRODUCER
1277
+ when true; DEFAULT_PRODUCER[option]
1193
1278
  when false; nil
1194
- when nil; @default_options[option]
1195
1279
  when Proc; value
1196
1280
  else
1197
1281
  raise ArgumentError, "Illegal value #{value.inspect}"
1198
1282
  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
1283
+
1284
+ # Find new message level
1285
+ new_level = DEFAULT_PRODUCER.keys.find { |level| @producers[level] } || :error
1286
+
1287
+ # Adjust postgres message level if changed
1288
+ if old_level != new_level
1289
+ @pg_connection.exec "set client_min_messages to #{new_level}"
1214
1290
  end
1215
1291
  else
1216
1292
  raise ArgumentError, "Illegal option: #{option.inspect}"
@@ -1224,10 +1300,13 @@ module PgConn
1224
1300
  def get_options() @options.dup end
1225
1301
 
1226
1302
  # Called from postgres. Installed in #initialize
1227
- def message_processor(message)
1303
+ def message_processor(message, stmt = nil)
1228
1304
  case message
1229
- when /^NOTICE:\s*(.*)$/; @options[:notice]&.call($1)
1230
- when /^WARNING:\s*(.*)$/; @options[:warning]&.call($1)
1305
+ when /^DEBUG:\s*(.*)$/; @producers[:debug]&.call($1)
1306
+ when /^INFO:\s*(.*)$/; @producers[:info]&.call($1)
1307
+ when /^NOTICE:\s*(.*)$/; @producers[:notice]&.call($1)
1308
+ when /^WARNING:\s*(.*)$/; @producers[:warning]&.call($1)
1309
+ when /^ERROR:\s*(.*)$/m; @producers[:silent]&.call($1, stmt)
1231
1310
  else
1232
1311
  raise "Oops"
1233
1312
  end
@@ -1255,6 +1334,10 @@ module PgConn
1255
1334
  def pg_exec(arg, silent: self.silent)
1256
1335
  if @pg_connection
1257
1336
  begin
1337
+ # Set silent state
1338
+ saved_silent = self.silent
1339
+ self.silent = silent
1340
+
1258
1341
  last_stmt = nil # To make the current SQL statement visible to the rescue clause. FIXME Not used?
1259
1342
  if arg.is_a?(String)
1260
1343
  return nil if arg == ""
@@ -1272,12 +1355,11 @@ module PgConn
1272
1355
  @error = ex
1273
1356
  @err = nil
1274
1357
  end
1275
- if !silent # FIXME Why do we handle this?
1276
- $stderr.puts arg
1277
- $stderr.puts
1278
- $stderr.puts ex.message
1279
- $stderr.flush
1280
- end
1358
+
1359
+ # Process message before resetting silent state
1360
+ message_processor(@error.message, arg)
1361
+ self.silent = saved_silent
1362
+
1281
1363
  raise
1282
1364
  end
1283
1365
 
@@ -1313,16 +1395,15 @@ module PgConn
1313
1395
  def self.sql_values(values) "'" + values.join("', '") + "'" end
1314
1396
  def self.sql_idents(values) '"' + values.join('", "') + '"' end
1315
1397
 
1316
- # Same as postgres PG#escape_literal but do not need a connection
1317
- def self.escape_literal(s) = s.nil? ? 'NULL' : "'#{s.gsub("'", "''")}'"
1318
-
1319
- # Same as postgres PG#escape_identifier but do not need a connection
1320
- def self.escape_identifier(s)
1321
- !s.nil? or raise TypeError, "Identifier can't be nil"
1322
- s.is_a?(String) or raise TypeError, "Identifier can't be a #{s.class}"
1323
- s !~ /\A\s*\z/ or raise TypeError, "Identifier be blank"
1324
- %("#{s.gsub('"', '""')}")
1325
- end
1398
+ # Same as postgres PG#escape_literal but do not need a connection
1399
+ def self.escape_literal(s) = s.nil? ? 'NULL' : "'#{s.gsub("'", "''")}'"
1326
1400
 
1401
+ # Same as postgres PG#escape_identifier but do not need a connection
1402
+ def self.escape_identifier(s)
1403
+ !s.nil? or raise TypeError, "Identifier can't be nil"
1404
+ s.is_a?(String) or raise TypeError, "Identifier can't be a #{s.class}"
1405
+ s !~ /\A\s*\z/ or raise TypeError, "Identifier be blank"
1406
+ %("#{s.gsub('"', '""')}")
1407
+ end
1327
1408
  end
1328
1409
 
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.35.0
4
+ version: 0.35.1
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 00:00:00.000000000 Z
11
+ date: 2025-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg