cipherstash-pg 1.0.0.beta.4-x86_64-darwin

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 (90) hide show
  1. checksums.yaml +7 -0
  2. data/.appveyor.yml +42 -0
  3. data/.gems +6 -0
  4. data/.gemtest +0 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +19 -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/BSDL +22 -0
  15. data/Contributors.rdoc +46 -0
  16. data/Gemfile +14 -0
  17. data/Gemfile.lock +45 -0
  18. data/History.md +804 -0
  19. data/LICENSE +56 -0
  20. data/Manifest.txt +72 -0
  21. data/POSTGRES +23 -0
  22. data/README-OS_X.rdoc +68 -0
  23. data/README-Windows.rdoc +56 -0
  24. data/README.ja.md +266 -0
  25. data/README.md +272 -0
  26. data/Rakefile +76 -0
  27. data/Rakefile.cross +298 -0
  28. data/certs/ged.pem +24 -0
  29. data/certs/larskanis-2022.pem +26 -0
  30. data/certs/larskanis-2023.pem +24 -0
  31. data/cipherstash-pg.gemspec +0 -0
  32. data/lib/2.7/pg_ext.bundle +0 -0
  33. data/lib/3.0/pg_ext.bundle +0 -0
  34. data/lib/3.1/pg_ext.bundle +0 -0
  35. data/lib/3.2/pg_ext.bundle +0 -0
  36. data/lib/cipherstash-pg/basic_type_map_based_on_result.rb +11 -0
  37. data/lib/cipherstash-pg/basic_type_map_for_queries.rb +113 -0
  38. data/lib/cipherstash-pg/basic_type_map_for_results.rb +30 -0
  39. data/lib/cipherstash-pg/basic_type_registry.rb +206 -0
  40. data/lib/cipherstash-pg/binary_decoder.rb +21 -0
  41. data/lib/cipherstash-pg/coder.rb +82 -0
  42. data/lib/cipherstash-pg/connection.rb +467 -0
  43. data/lib/cipherstash-pg/constants.rb +3 -0
  44. data/lib/cipherstash-pg/exceptions.rb +19 -0
  45. data/lib/cipherstash-pg/result.rb +22 -0
  46. data/lib/cipherstash-pg/text_decoder.rb +43 -0
  47. data/lib/cipherstash-pg/text_encoder.rb +67 -0
  48. data/lib/cipherstash-pg/tuple.rb +24 -0
  49. data/lib/cipherstash-pg/type_map_by_column.rb +11 -0
  50. data/lib/cipherstash-pg/version.rb +3 -0
  51. data/lib/cipherstash-pg.rb +60 -0
  52. data/lib/libpq.5.dylib +0 -0
  53. data/misc/openssl-pg-segfault.rb +21 -0
  54. data/misc/postgres/History.txt +9 -0
  55. data/misc/postgres/Manifest.txt +5 -0
  56. data/misc/postgres/README.txt +21 -0
  57. data/misc/postgres/Rakefile +14 -0
  58. data/misc/postgres/lib/postgres.rb +12 -0
  59. data/misc/ruby-pg/History.txt +9 -0
  60. data/misc/ruby-pg/Manifest.txt +5 -0
  61. data/misc/ruby-pg/README.txt +21 -0
  62. data/misc/ruby-pg/Rakefile +14 -0
  63. data/misc/ruby-pg/lib/ruby/pg.rb +12 -0
  64. data/rakelib/task_extension.rb +32 -0
  65. data/sample/array_insert.rb +7 -0
  66. data/sample/async_api.rb +60 -0
  67. data/sample/async_copyto.rb +24 -0
  68. data/sample/async_mixed.rb +28 -0
  69. data/sample/check_conn.rb +9 -0
  70. data/sample/copydata.rb +21 -0
  71. data/sample/copyfrom.rb +29 -0
  72. data/sample/copyto.rb +13 -0
  73. data/sample/cursor.rb +11 -0
  74. data/sample/disk_usage_report.rb +92 -0
  75. data/sample/issue-119.rb +46 -0
  76. data/sample/losample.rb +51 -0
  77. data/sample/minimal-testcase.rb +6 -0
  78. data/sample/notify_wait.rb +26 -0
  79. data/sample/pg_statistics.rb +104 -0
  80. data/sample/replication_monitor.rb +123 -0
  81. data/sample/test_binary_values.rb +17 -0
  82. data/sample/wal_shipper.rb +202 -0
  83. data/sample/warehouse_partitions.rb +161 -0
  84. data/translation/.po4a-version +7 -0
  85. data/translation/po/all.pot +875 -0
  86. data/translation/po/ja.po +868 -0
  87. data/translation/po4a.cfg +9 -0
  88. data/vendor/database-extensions/install.sql +317 -0
  89. data/vendor/database-extensions/uninstall.sql +20 -0
  90. metadata +140 -0
@@ -0,0 +1,467 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ require("uri")
3
+ require("io/wait")
4
+ require("socket")
5
+ class CipherStashPG::Connection
6
+ CONNECT_ARGUMENT_ORDER = ["host", "port", "options", "tty", "dbname", "user", "password"]
7
+
8
+ def self.quote_connstr(value)
9
+ return (("'" + value.to_s.gsub(/[\\']/) { |m| ("\\" + m) }) + "'")
10
+ end
11
+
12
+ def self.connect_hash_to_string(hash)
13
+ hash.map { |k, v| "#{k}=#{quote_connstr(v)}" }.join(" ")
14
+ end
15
+
16
+ def self.parse_connect_args(*args)
17
+ hash_arg = args.last.is_a?(Hash) ? (args.pop.transform_keys(&:to_sym)) : ({})
18
+ iopts = {}
19
+ if (args.length == 1) then
20
+ case args.first
21
+ when URI, /=/, /:\/\// then
22
+ conn_string = args.first.to_s
23
+ iopts = CipherStashPG::Connection.conninfo_parse(conn_string).each_with_object({}) do |h, o|
24
+ o[h[:keyword].to_sym] = h[:val] if h[:val]
25
+ end
26
+ else
27
+ iopts[CONNECT_ARGUMENT_ORDER.first.to_sym] = args.first
28
+ end
29
+ else
30
+ max = CONNECT_ARGUMENT_ORDER.length
31
+ if (args.length > max) then
32
+ raise(ArgumentError, ("Extra positional parameter %d: %p" % [(max + 1), args[max]]))
33
+ end
34
+ CONNECT_ARGUMENT_ORDER.zip(args) { |(k, v)| iopts[k.to_sym] = v if v }
35
+ iopts.delete(:tty)
36
+ end
37
+ iopts.merge!(hash_arg)
38
+ unless iopts[:fallback_application_name] then
39
+ iopts[:fallback_application_name] = $0.sub(/^(.{30}).{4,}(.{30})$/) { (($1 + "...") + $2) }
40
+ end
41
+ return connect_hash_to_string(iopts)
42
+ end
43
+
44
+ def inspect
45
+ str = self.to_s
46
+ str[-1, 0] = if finished? then
47
+ " finished"
48
+ else
49
+ stats = []
50
+ if (status != CONNECTION_OK) then
51
+ (stats << " status=#{CipherStashPG.constants.grep(/CONNECTION_/).find do |c|
52
+ (CipherStashPG.const_get(c) == status)
53
+ end}")
54
+ end
55
+ if (transaction_status != CipherStashPG::PQTRANS_IDLE) then
56
+ (stats << " transaction_status=#{CipherStashPG.constants.grep(/PQTRANS_/).find do |c|
57
+ (CipherStashPG.const_get(c) == transaction_status)
58
+ end}")
59
+ end
60
+ (stats << " nonblocking=#{isnonblocking}") if isnonblocking
61
+ if respond_to?(:pipeline_status) and (pipeline_status != CipherStashPG::PQ_PIPELINE_OFF) then
62
+ (stats << " pipeline_status=#{CipherStashPG.constants.grep(/PQ_PIPELINE_/).find do |c|
63
+ (CipherStashPG.const_get(c) == pipeline_status)
64
+ end}")
65
+ end
66
+ if (get_client_encoding != "UTF8") then
67
+ (stats << " client_encoding=#{get_client_encoding}")
68
+ end
69
+ unless type_map_for_results.is_a?(CipherStashPG::TypeMapAllStrings) then
70
+ (stats << " type_map_for_results=#{type_map_for_results.to_s}")
71
+ end
72
+ unless type_map_for_queries.is_a?(CipherStashPG::TypeMapAllStrings) then
73
+ (stats << " type_map_for_queries=#{type_map_for_queries.to_s}")
74
+ end
75
+ if encoder_for_put_copy_data then
76
+ (stats << " encoder_for_put_copy_data=#{encoder_for_put_copy_data.to_s}")
77
+ end
78
+ if decoder_for_get_copy_data then
79
+ (stats << " decoder_for_get_copy_data=#{decoder_for_get_copy_data.to_s}")
80
+ end
81
+ " host=#{host} port=#{port} user=#{user}#{stats.join}"
82
+ end
83
+ return str
84
+ end
85
+
86
+ def copy_data(sql, coder = nil)
87
+ if nonblocking? then
88
+ raise(CipherStashPG::NotInBlockingMode.new("copy_data can not be used in nonblocking mode", :connection => (self)))
89
+ end
90
+ res = exec(sql)
91
+ case res.result_status
92
+ when PGRES_COPY_IN then
93
+ begin
94
+ (if coder then
95
+ old_coder = self.encoder_for_put_copy_data
96
+ self.encoder_for_put_copy_data = coder
97
+ end
98
+ yield(res))
99
+ rescue Exception => err
100
+ errmsg = ("%s while copy data: %s" % [err.class.name, err.message])
101
+ begin
102
+ put_copy_end(errmsg)
103
+ rescue CipherStashPG::Error
104
+ # do nothing
105
+ end
106
+ discard_results
107
+ raise(err)
108
+ else
109
+ (begin
110
+ put_copy_end
111
+ rescue CipherStashPG::Error => err
112
+ raise(CipherStashPG::LostCopyState.new("#{err} (probably by executing another SQL query while running a COPY command)", :connection => (self)))
113
+ end
114
+ get_last_result)
115
+ ensure
116
+ self.encoder_for_put_copy_data = old_coder if coder
117
+ end
118
+ when PGRES_COPY_OUT then
119
+ begin
120
+ (if coder then
121
+ old_coder = self.decoder_for_get_copy_data
122
+ self.decoder_for_get_copy_data = coder
123
+ end
124
+ yield(res))
125
+ rescue Exception
126
+ cancel
127
+ discard_results
128
+ raise
129
+ else
130
+ (res = get_last_result
131
+ if res then
132
+ if (res.result_status != PGRES_COMMAND_OK) then
133
+ discard_results
134
+ raise(CipherStashPG::NotAllCopyDataRetrieved.new("Not all COPY data retrieved", :connection => (self)))
135
+ end
136
+ else
137
+ discard_results
138
+ raise(CipherStashPG::LostCopyState.new("Lost COPY state (probably by executing another SQL query while running a COPY command)", :connection => (self)))
139
+ end
140
+ res)
141
+ ensure
142
+ self.decoder_for_get_copy_data = old_coder if coder
143
+ end
144
+ else
145
+ raise(ArgumentError, "SQL command is no COPY statement: #{sql}")
146
+ end
147
+ end
148
+
149
+ class << self
150
+ define_method(:isthreadsafe, &CipherStashPG.method(:isthreadsafe))
151
+ end
152
+
153
+ def transaction
154
+ (rollback = false
155
+ exec("BEGIN")
156
+ yield(self))
157
+ rescue Exception
158
+ rollback = true
159
+ cancel if (transaction_status == CipherStashPG::PQTRANS_ACTIVE)
160
+ block
161
+ exec("ROLLBACK")
162
+ raise
163
+ ensure
164
+ exec("COMMIT") unless rollback
165
+ end
166
+
167
+ def conndefaults
168
+ return self.class.conndefaults
169
+ end
170
+
171
+ def self.conndefaults_hash
172
+ return self.conndefaults.each_with_object({}) do |info, hash|
173
+ hash[info[:keyword].to_sym] = info[:val]
174
+ end
175
+ end
176
+
177
+ def conndefaults_hash
178
+ return self.class.conndefaults_hash
179
+ end
180
+
181
+ def conninfo_hash
182
+ return self.conninfo.each_with_object({}) do |info, hash|
183
+ hash[info[:keyword].to_sym] = info[:val]
184
+ end
185
+ end
186
+
187
+ if self.instance_methods.find { |m| (m.to_sym == :ssl_attribute) } then
188
+ def ssl_attributes
189
+ ssl_attribute_names.each.with_object({}) { |n, h| h[n] = ssl_attribute(n) }
190
+ end
191
+ end
192
+
193
+ def get_result
194
+ block
195
+ sync_get_result
196
+ end
197
+
198
+ alias :async_get_result :get_result
199
+
200
+ def get_copy_data(async = false, decoder = nil)
201
+ if async then
202
+ return sync_get_copy_data(async, decoder)
203
+ else
204
+ while ((res = sync_get_copy_data(true, decoder)) == false) do
205
+ socket_io.wait_readable
206
+ consume_input
207
+ end
208
+ return res
209
+ end
210
+ end
211
+
212
+ alias :async_get_copy_data :get_copy_data
213
+
214
+ def setnonblocking(enabled)
215
+ singleton_class.async_send_api = (not enabled)
216
+ self.flush_data = (not enabled)
217
+ sync_setnonblocking(true)
218
+ end
219
+
220
+ alias :async_setnonblocking :setnonblocking
221
+
222
+ def isnonblocking
223
+ false
224
+ end
225
+
226
+ alias :async_isnonblocking :isnonblocking
227
+
228
+ alias :nonblocking? :isnonblocking
229
+
230
+ def put_copy_data(buffer, encoder = nil)
231
+ until res = sync_put_copy_data(buffer, encoder) do
232
+ res = flush
233
+ end
234
+ if (@calls_to_put_copy_data = (@calls_to_put_copy_data + 1) > 100) then
235
+ @calls_to_put_copy_data = 0
236
+ res = flush
237
+ end
238
+ res
239
+ end
240
+
241
+ alias :async_put_copy_data :put_copy_data
242
+
243
+ def put_copy_end(*args)
244
+ until sync_put_copy_end(*args) do
245
+ flush
246
+ end
247
+ @calls_to_put_copy_data = 0
248
+ flush
249
+ end
250
+
251
+ alias :async_put_copy_end :put_copy_end
252
+
253
+ if method_defined?(:sync_encrypt_password) then
254
+ def encrypt_password(password, username, algorithm = nil)
255
+ algorithm ||= exec("SHOW password_encryption").getvalue(0, 0)
256
+ sync_encrypt_password(password, username, algorithm)
257
+ end
258
+ (alias :async_encrypt_password :encrypt_password)
259
+ end
260
+
261
+ def reset
262
+ reset_start
263
+ async_connect_or_reset(:reset_poll)
264
+ self
265
+ end
266
+
267
+ alias :async_reset :reset
268
+
269
+ def cancel
270
+ (be_pid = backend_pid
271
+ be_key = backend_key
272
+ cancel_request = [16, 1234, 5678, be_pid, be_key].pack("NnnNN")
273
+ if Fiber.respond_to?(:scheduler) and (Fiber.scheduler and RUBY_PLATFORM =~ /mingw|mswin/) then
274
+ cl = Thread.new(socket_io.remote_address) { |ra| ra.connect }.value
275
+ begin
276
+ cl.write_nonblock(cancel_request)
277
+ rescue IO::WaitReadable, Errno::EINTR
278
+ cl.wait_writable
279
+ retry
280
+ end
281
+ begin
282
+ cl.read_nonblock(1)
283
+ rescue IO::WaitReadable, Errno::EINTR
284
+ cl.wait_readable
285
+ retry
286
+ rescue EOFError
287
+ # do nothing
288
+ end
289
+ else
290
+ if (RUBY_ENGINE == "truffleruby") then
291
+ begin
292
+ cl = socket_io.remote_address.connect
293
+ rescue NotImplementedError
294
+ cl2 = Socket.for_fd(socket_io.fileno)
295
+ cl2.autoclose = false
296
+ adr = cl2.remote_address
297
+ if adr.ip? then
298
+ cl = TCPSocket.new(adr.ip_address, adr.ip_port)
299
+ cl.autoclose = false
300
+ else
301
+ cl = UNIXSocket.new(adr.unix_path)
302
+ cl.autoclose = false
303
+ end
304
+ end
305
+ cl.write(cancel_request)
306
+ cl.read(1)
307
+ else
308
+ cl = socket_io.remote_address.connect
309
+ cl.write(cancel_request)
310
+ cl.read(1)
311
+ end
312
+ end
313
+ cl.close
314
+ nil)
315
+ rescue SystemCallError => err
316
+ err.to_s
317
+ end
318
+
319
+ alias :async_cancel :cancel
320
+
321
+ private(def async_connect_or_reset(poll_meth)
322
+ if timeo = conninfo_hash[:connect_timeout].to_i and (timeo > 0) then
323
+ timeo = [timeo, 2].max
324
+ host_count = (conninfo_hash[:host].to_s.count(",") + 1)
325
+ stop_time = ((timeo * host_count) + Process.clock_gettime(Process::CLOCK_MONOTONIC))
326
+ end
327
+ poll_status = CipherStashPG::PGRES_POLLING_WRITING
328
+ until ((poll_status == CipherStashPG::PGRES_POLLING_OK) or (poll_status == CipherStashPG::PGRES_POLLING_FAILED)) do
329
+ (if stop_time then
330
+ timeout = [timeo, (stop_time - Process.clock_gettime(Process::CLOCK_MONOTONIC))].min
331
+ end
332
+ event = if ((not timeout) or (timeout >= 0)) then
333
+ case poll_status
334
+ when CipherStashPG::PGRES_POLLING_READING then
335
+ if defined? IO::READABLE then
336
+ socket_io.wait((IO::READABLE | IO::PRIORITY), timeout)
337
+ else
338
+ IO.select([socket_io], nil, [socket_io], timeout)
339
+ end
340
+ when CipherStashPG::PGRES_POLLING_WRITING then
341
+ if defined? IO::WRITABLE then
342
+ socket_io.wait((IO::WRITABLE | IO::PRIORITY), timeout)
343
+ else
344
+ IO.select(nil, [socket_io], [socket_io], timeout)
345
+ end
346
+ end
347
+ end
348
+ unless event then
349
+ if self.class.send(:host_is_named_pipe?, host) then
350
+ connhost = "on socket \"#{host}\""
351
+ else
352
+ if respond_to?(:hostaddr) then
353
+ connhost = "at \"#{host}\" (#{hostaddr}), port #{port}"
354
+ else
355
+ connhost = "at \"#{host}\", port #{port}"
356
+ end
357
+ end
358
+ raise(CipherStashPG::ConnectionBad.new("connection to server #{connhost} failed: timeout expired", :connection => (self)))
359
+ end
360
+ poll_status = send(poll_meth))
361
+ end
362
+ unless (status == CipherStashPG::CONNECTION_OK) then
363
+ msg = error_message
364
+ finish
365
+ raise(CipherStashPG::ConnectionBad.new(msg, :connection => (self)))
366
+ end
367
+ sync_setnonblocking(true)
368
+ self.flush_data = true
369
+ set_default_encoding
370
+ end)
371
+
372
+ class << self
373
+ def new(*args)
374
+ conn = connect_to_hosts(*args)
375
+ if block_given? then
376
+ begin
377
+ return yield(conn)
378
+ ensure
379
+ conn.finish
380
+ end
381
+ end
382
+ conn
383
+ end
384
+ alias :async_connect :new
385
+ alias :connect :new
386
+ alias :open :new
387
+ alias :setdb :new
388
+ alias :setdblogin :new
389
+ private(def connect_to_hosts(*args)
390
+ option_string = parse_connect_args(*args)
391
+ iopts = CipherStashPG::Connection.conninfo_parse(option_string).each_with_object({}) do |h, o|
392
+ o[h[:keyword].to_sym] = h[:val] if h[:val]
393
+ end
394
+ iopts = CipherStashPG::Connection.conndefaults.each_with_object({}) do |h, o|
395
+ o[h[:keyword].to_sym] = h[:val] if h[:val]
396
+ end.merge(iopts)
397
+ unless iopts[:hostaddr] then
398
+ if iopts[:host] and ((not iopts[:host].empty?) and (CipherStashPG.library_version >= 100000)) then
399
+ ihosts = iopts[:host].split(",", -1)
400
+ iports = iopts[:port].split(",", -1)
401
+ iports = [nil] if (iports.size == 0)
402
+ iports = (iports * ihosts.size) if (iports.size == 1)
403
+ if (iports.size != ihosts.size) then
404
+ raise(CipherStashPG::ConnectionBad, "could not match #{iports.size} port numbers to #{ihosts.size} hosts")
405
+ end
406
+ dests = ihosts.each_with_index.flat_map do |mhost, idx|
407
+ if host_is_named_pipe?(mhost) then
408
+ hostaddrs = [nil]
409
+ else
410
+ if Fiber.respond_to?(:scheduler) and (Fiber.scheduler and (RUBY_VERSION < "3.1.")) then
411
+ hostaddrs = Thread.new do
412
+ Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue [""]
413
+ end.value
414
+ else
415
+ hostaddrs = Addrinfo.getaddrinfo(mhost, nil, nil, :STREAM).map(&:ip_address) rescue [""]
416
+ end
417
+ end
418
+ hostaddrs.map { |hostaddr| [hostaddr, mhost, iports[idx]] }
419
+ end
420
+ iopts.merge!(:hostaddr => dests.map { |d| d[0] }.join(","), :host => dests.map { |d| d[1] }.join(","), :port => dests.map { |d| d[2] }.join(","))
421
+ end
422
+ end
423
+ (conn = self.connect_start(iopts) or raise(CipherStashPG::Error, "Unable to create a new connection"))
424
+ if (conn.status == CipherStashPG::CONNECTION_BAD) then
425
+ raise(CipherStashPG::ConnectionBad, conn.error_message)
426
+ end
427
+ conn.send(:async_connect_or_reset, :connect_poll)
428
+ conn
429
+ end)
430
+ private(def host_is_named_pipe?(host_string)
431
+ (host_string.empty? or (host_string.start_with?("/") or (host_string.start_with?("@") or (RUBY_PLATFORM =~ /mingw|mswin/ and host_string =~ /\A([\/\\]|\w:[\/\\])/))))
432
+ end)
433
+ def ping(*args)
434
+ if Fiber.respond_to?(:scheduler) and Fiber.scheduler then
435
+ Thread.new { sync_ping(*args) }.value
436
+ else
437
+ sync_ping(*args)
438
+ end
439
+ end
440
+ alias :async_ping :ping
441
+ REDIRECT_CLASS_METHODS = { :new => ([:async_connect, :sync_connect]), :connect => ([:async_connect, :sync_connect]), :open => ([:async_connect, :sync_connect]), :setdb => ([:async_connect, :sync_connect]), :setdblogin => ([:async_connect, :sync_connect]), :ping => ([:async_ping, :sync_ping]) }
442
+ REDIRECT_SEND_METHODS = { :isnonblocking => ([:async_isnonblocking, :sync_isnonblocking]), :nonblocking? => ([:async_isnonblocking, :sync_isnonblocking]), :put_copy_data => ([:async_put_copy_data, :sync_put_copy_data]), :put_copy_end => ([:async_put_copy_end, :sync_put_copy_end]), :flush => ([:async_flush, :sync_flush]) }
443
+ REDIRECT_METHODS = { :exec => ([:async_exec, :sync_exec]), :query => ([:async_exec, :sync_exec]), :exec_params => ([:async_exec_params, :sync_exec_params]), :prepare => ([:async_prepare, :sync_prepare]), :exec_prepared => ([:async_exec_prepared, :sync_exec_prepared]), :describe_portal => ([:async_describe_portal, :sync_describe_portal]), :describe_prepared => ([:async_describe_prepared, :sync_describe_prepared]), :setnonblocking => ([:async_setnonblocking, :sync_setnonblocking]), :get_result => ([:async_get_result, :sync_get_result]), :get_last_result => ([:async_get_last_result, :sync_get_last_result]), :get_copy_data => ([:async_get_copy_data, :sync_get_copy_data]), :reset => ([:async_reset, :sync_reset]), :set_client_encoding => ([:async_set_client_encoding, :sync_set_client_encoding]), :client_encoding= => ([:async_set_client_encoding, :sync_set_client_encoding]), :cancel => ([:async_cancel, :sync_cancel]) }
444
+ if CipherStashPG::Connection.instance_methods.include?(:async_encrypt_password) then
445
+ REDIRECT_METHODS.merge!(:encrypt_password => ([:async_encrypt_password, :sync_encrypt_password]))
446
+ end
447
+ def async_send_api=(enable)
448
+ REDIRECT_SEND_METHODS.each do |ali, (async, sync)|
449
+ undef_method(ali) if method_defined?(ali)
450
+ alias_method(ali, (enable ? (async) : (sync)))
451
+ end
452
+ end
453
+ def async_api=(enable)
454
+ self.async_send_api = enable
455
+ REDIRECT_METHODS.each do |ali, (async, sync)|
456
+ remove_method(ali) if method_defined?(ali)
457
+ alias_method(ali, (enable ? (async) : (sync)))
458
+ end
459
+ REDIRECT_CLASS_METHODS.each do |ali, (async, sync)|
460
+ singleton_class.remove_method(ali) if method_defined?(ali)
461
+ singleton_class.alias_method(ali, (enable ? (async) : (sync)))
462
+ end
463
+ end
464
+ end
465
+
466
+ self.async_api = true
467
+ end
@@ -0,0 +1,3 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ module CipherStashPG::Constants
3
+ end
@@ -0,0 +1,19 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ module CipherStashPG
3
+ class Error < StandardError
4
+ def initialize(msg = nil, connection: nil, result: nil)
5
+ @connection = connection
6
+ @result = result
7
+ super(msg)
8
+ end
9
+ end
10
+
11
+ class NotAllCopyDataRetrieved < CipherStashPG::Error
12
+ end
13
+
14
+ class LostCopyState < CipherStashPG::Error
15
+ end
16
+
17
+ class NotInBlockingMode < CipherStashPG::Error
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::Result
3
+ def map_types!(type_map)
4
+ self.type_map = type_map
5
+ return self
6
+ end
7
+
8
+ def field_names_as(type)
9
+ self.field_name_type = type
10
+ return self
11
+ end
12
+
13
+ def inspect
14
+ str = self.to_s
15
+ str[-1, 0] = if cleared? then
16
+ " cleared"
17
+ else
18
+ " status=#{res_status(result_status)} ntuples=#{ntuples} nfields=#{nfields} cmd_tuples=#{cmd_tuples}"
19
+ end
20
+ return str
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ require("date")
2
+ require("json")
3
+ module CipherStashPG
4
+ module TextDecoder
5
+ class Date < SimpleDecoder
6
+ def decode(string, tuple = nil, field = nil)
7
+ if string =~ /\A(\d{4})-(\d\d)-(\d\d)\z/ then
8
+ ::Date.new($1.to_i, $2.to_i, $3.to_i)
9
+ else
10
+ string
11
+ end
12
+ end
13
+ end
14
+
15
+ class JSON < SimpleDecoder
16
+ def decode(string, tuple = nil, field = nil)
17
+ ::JSON.parse(string, :quirks_mode => true)
18
+ end
19
+ end
20
+
21
+ class TimestampUtc < Timestamp
22
+ def initialize(params = {})
23
+ super(params.merge(:flags => (CipherStashPG::Coder::TIMESTAMP_DB_UTC | CipherStashPG::Coder::TIMESTAMP_APP_UTC)))
24
+ end
25
+ end
26
+
27
+ class TimestampUtcToLocal < Timestamp
28
+ def initialize(params = {})
29
+ super(params.merge(:flags => (CipherStashPG::Coder::TIMESTAMP_DB_UTC | CipherStashPG::Coder::TIMESTAMP_APP_LOCAL)))
30
+ end
31
+ end
32
+
33
+ class TimestampLocal < Timestamp
34
+ def initialize(params = {})
35
+ super(params.merge(:flags => (CipherStashPG::Coder::TIMESTAMP_DB_LOCAL | CipherStashPG::Coder::TIMESTAMP_APP_LOCAL)))
36
+ end
37
+ end
38
+
39
+ TimestampWithoutTimeZone = TimestampLocal
40
+
41
+ TimestampWithTimeZone = Timestamp
42
+ end
43
+ end
@@ -0,0 +1,67 @@
1
+ require("json")
2
+ require("ipaddr")
3
+ module CipherStashPG
4
+ module TextEncoder
5
+ class Date < SimpleEncoder
6
+ def encode(value)
7
+ value.respond_to?(:strftime) ? (value.strftime("%Y-%m-%d")) : (value)
8
+ end
9
+ end
10
+
11
+ class TimestampWithoutTimeZone < SimpleEncoder
12
+ def encode(value)
13
+ if value.respond_to?(:strftime) then
14
+ value.strftime("%Y-%m-%d %H:%M:%S.%N")
15
+ else
16
+ value
17
+ end
18
+ end
19
+ end
20
+
21
+ class TimestampUtc < SimpleEncoder
22
+ def encode(value)
23
+ if value.respond_to?(:utc) then
24
+ value.utc.strftime("%Y-%m-%d %H:%M:%S.%N")
25
+ else
26
+ value
27
+ end
28
+ end
29
+ end
30
+
31
+ class TimestampWithTimeZone < SimpleEncoder
32
+ def encode(value)
33
+ if value.respond_to?(:strftime) then
34
+ value.strftime("%Y-%m-%d %H:%M:%S.%N %:z")
35
+ else
36
+ value
37
+ end
38
+ end
39
+ end
40
+
41
+ class JSON < SimpleEncoder
42
+ def encode(value)
43
+ ::JSON.generate(value, :quirks_mode => true)
44
+ end
45
+ end
46
+
47
+ class Inet < SimpleEncoder
48
+ def encode(value)
49
+ case value
50
+ when IPAddr then
51
+ default_prefix = (value.family == Socket::AF_INET) ? (32) : (128)
52
+ s = value.to_s
53
+ if value.respond_to?(:prefix) then
54
+ prefix = value.prefix
55
+ else
56
+ range = value.to_range
57
+ prefix = (default_prefix - Math.log(((range.end.to_i - range.begin.to_i) + 1), 2).to_i)
58
+ end
59
+ ((s << "/") << prefix.to_s) if (prefix != default_prefix)
60
+ s
61
+ else
62
+ value
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,24 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::Tuple
3
+ def inspect
4
+ "#<#{self.class} #{self.map { |k, v| "#{k}: #{v.inspect}" }.join(", ")}>"
5
+ end
6
+
7
+ def has_key?(key)
8
+ field_map.has_key?(key)
9
+ end
10
+
11
+ alias :key? :has_key?
12
+
13
+ def keys
14
+ (field_names or field_map.keys.freeze)
15
+ end
16
+
17
+ def each_key(&block)
18
+ if fn = field_names then
19
+ fn.each(&block)
20
+ else
21
+ field_map.each_key(&block)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ require("cipherstash-pg") unless defined? CipherStashPG
2
+ class CipherStashPG::TypeMapByColumn
3
+ def oids
4
+ coders.map { |c| c.oid if c }
5
+ end
6
+
7
+ def inspect
8
+ type_strings = coders.map { |c| c ? (c.inspect_short) : ("nil") }
9
+ "#<#{self.class} #{type_strings.join(" ")}>"
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ module CipherStashPG
2
+ VERSION = "1.0.0.beta.4"
3
+ end