pg 1.4.5-x86-mingw32 → 1.4.6-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -4
- data/.appveyor.yml +14 -8
- data/.github/workflows/binary-gems.yml +41 -10
- data/.github/workflows/source-gem.yml +18 -12
- data/.gitignore +8 -2
- data/.travis.yml +2 -2
- data/{History.rdoc → History.md} +168 -153
- data/README.ja.md +266 -0
- data/README.md +272 -0
- data/Rakefile +12 -3
- data/Rakefile.cross +7 -11
- data/certs/larskanis-2023.pem +24 -0
- data/ext/pg_connection.c +106 -26
- data/lib/2.5/pg_ext.so +0 -0
- data/lib/2.6/pg_ext.so +0 -0
- data/lib/2.7/pg_ext.so +0 -0
- data/lib/3.0/pg_ext.so +0 -0
- data/lib/3.1/pg_ext.so +0 -0
- data/lib/3.2/pg_ext.so +0 -0
- data/lib/pg/connection.rb +20 -19
- data/lib/pg/exceptions.rb +7 -0
- data/lib/pg/version.rb +1 -1
- data/lib/pg.rb +0 -6
- data/lib/x86-mingw32/libpq.dll +0 -0
- data/pg.gemspec +4 -2
- data/rakelib/task_extension.rb +1 -1
- data/translation/.po4a-version +7 -0
- data/translation/po/all.pot +875 -0
- data/translation/po/ja.po +868 -0
- data/translation/po4a.cfg +9 -0
- data.tar.gz.sig +0 -0
- metadata +89 -31
- metadata.gz.sig +2 -2
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -233
data/README.ja.md
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
# pg
|
2
|
+
|
3
|
+
* home :: https://github.com/ged/ruby-pg
|
4
|
+
* docs :: http://deveiate.org/code/pg
|
5
|
+
* clog :: link:/History.md
|
6
|
+
|
7
|
+
[![https://gitter.im/ged/ruby-pg
|
8
|
+
でチャットに参加](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ged/ruby-pg?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
9
|
+
|
10
|
+
|
11
|
+
## 説明
|
12
|
+
|
13
|
+
Pgは[PostgreSQL
|
14
|
+
RDBMS](http://www.postgresql.org/)へのRubyのインターフェースです。[PostgreSQL
|
15
|
+
9.3以降](http://www.postgresql.org/support/versioning/)で動作します。
|
16
|
+
|
17
|
+
簡単な使用例は次の通りです。
|
18
|
+
```ruby
|
19
|
+
#!/usr/bin/env ruby
|
20
|
+
|
21
|
+
require 'pg'
|
22
|
+
|
23
|
+
# データベースへの現在の接続を表に出力します
|
24
|
+
conn = PG.connect( dbname: 'sales' )
|
25
|
+
conn.exec( "SELECT * FROM pg_stat_activity" ) do |result|
|
26
|
+
puts " PID | User | Query"
|
27
|
+
result.each do |row|
|
28
|
+
puts " %7d | %-16s | %s " %
|
29
|
+
row.values_at('pid', 'usename', 'query')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
```
|
33
|
+
|
34
|
+
## ビルド状況
|
35
|
+
|
36
|
+
[![Github
|
37
|
+
Actionsのビルド状況](https://github.com/ged/ruby-pg/actions/workflows/source-gem.yml/badge.svg?branch=master)](https://github.com/ged/ruby-pg/actions/workflows/source-gem.yml)
|
38
|
+
[![バイナリgem](https://github.com/ged/ruby-pg/actions/workflows/binary-gems.yml/badge.svg?branch=master)](https://github.com/ged/ruby-pg/actions/workflows/binary-gems.yml)
|
39
|
+
[![Appveyorのビルド状況](https://ci.appveyor.com/api/projects/status/gjx5axouf3b1wicp?svg=true)](https://ci.appveyor.com/project/ged/ruby-pg-9j8l3)
|
40
|
+
|
41
|
+
|
42
|
+
## 要件
|
43
|
+
|
44
|
+
* Ruby 2.4かそれより新しいバージョン
|
45
|
+
* PostgreSQL 9.3.xかそれ以降のバージョン(ヘッダー付属のもの、例えば-devの名前のパッケージ)。
|
46
|
+
|
47
|
+
それより前のバージョンのRubyやPostgreSQLでも通常は同様に動作しますが、定期的なテストはされていません。
|
48
|
+
|
49
|
+
|
50
|
+
## バージョン管理
|
51
|
+
|
52
|
+
[セマンティックバージョニング](http://semver.org/)の原則にしたがってgemをタグ付けしてリリースしています。
|
53
|
+
|
54
|
+
この方針の結果として、2つの数字を指定する[悲観的バージョン制約](http://guides.rubygems.org/patterns/#pessimistic-version-constraint)を使ってこのgemへの依存関係を指定することができます(またそうすべきです)。
|
55
|
+
|
56
|
+
例えば次の通りです。
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
spec.add_dependency 'pg', '~> 1.0'
|
60
|
+
```
|
61
|
+
|
62
|
+
## インストール方法
|
63
|
+
|
64
|
+
RubyGemsを経由してインストールするには以下とします。
|
65
|
+
|
66
|
+
gem install pg
|
67
|
+
|
68
|
+
Postgresと一緒にインストールされた'pg_config'プログラムへのパスを指定する必要があるかもしれません。
|
69
|
+
|
70
|
+
gem install pg -- --with-pg-config=<path to pg_config>
|
71
|
+
|
72
|
+
Bundlerを介してインストールした場合は次のようにコンパイルのためのヒントを与えられます。
|
73
|
+
|
74
|
+
bundle config build.pg --with-pg-config=<path to pg_config>
|
75
|
+
|
76
|
+
MacOS Xへインストールする詳しい情報については README-OS_X.rdoc を、Windows用のビルドやインストールの説明については
|
77
|
+
README-Windows.rdoc を参照してください。
|
78
|
+
|
79
|
+
詰まったときやただ何か喋りたいときのために[Google+グループ](http://goo.gl/TFy1U)と[メーリングリスト](http://groups.google.com/group/ruby-pg)もあります。
|
80
|
+
|
81
|
+
署名されたgemとしてインストールしたい場合は、リポジトリの[`certs`ディレクトリ](https://github.com/ged/ruby-pg/tree/master/certs)にgemの署名をする公開証明書があります。
|
82
|
+
|
83
|
+
|
84
|
+
## 型変換
|
85
|
+
|
86
|
+
PgにはおまけとしてRubyとネイティブCコードにある結果の値やクエリ引数の型変換ができます。
|
87
|
+
こうすることでデータベースとのデータの往来を加速させられますが、それは文字列のアロケーションが減り、(より遅い)Rubyのコードでの変換部分が除かれるからです。
|
88
|
+
|
89
|
+
とても基本的な型変換は次のようにできます。
|
90
|
+
```ruby
|
91
|
+
conn.type_map_for_results = PG::BasicTypeMapForResults.new conn
|
92
|
+
# ……これは結果の値の対応付けに作用します。
|
93
|
+
conn.exec("select 1, now(), '{2,3}'::int[]").values
|
94
|
+
# => [[1, 2014-09-21 20:51:56 +0200, [2, 3]]]
|
95
|
+
|
96
|
+
conn.type_map_for_queries = PG::BasicTypeMapForQueries.new conn
|
97
|
+
# ……そしてこれは引数値の対応付けのためのものです。
|
98
|
+
conn.exec_params("SELECT $1::text, $2::text, $3::text", [1, 1.23, [2,3]]).values
|
99
|
+
# => [["1", "1.2300000000000000E+00", "{2,3}"]]
|
100
|
+
```
|
101
|
+
|
102
|
+
しかしPgの型変換はかなり調整が効きます。2層に分かれているのがその理由です。
|
103
|
+
|
104
|
+
### エンコーダーとデコーダー (ext/pg_*coder.c, lib/pg/*coder.rb)
|
105
|
+
|
106
|
+
こちらはより低層で、DBMSへ転送するためにRubyのオブジェクトを変換するエンコーディングクラスと取得してきたデータをRubyのオブジェクトに変換し戻すデコーディングクラスが含まれています。クラスはそれぞれの形式によって名前空間PG::TextEncoder、PG::TextDecoder、PG::BinaryEncoder、そしてPG::BinaryDecoderに分かれています。
|
107
|
+
|
108
|
+
エンコーダーないしデコーダーオブジェクトにOIDデータ型や形式コード(テキストないしバイナリ)や任意で名前を割り当てることができます。要素のエンコーダーないしデコーダーを割り当てることによって複合型を構築することもできます。PG::CoderオブジェクトはPG::TypeMapをセットアップしたりその代わりに単一の値と文字列表現とを相互に変換したりするのに使えます。
|
109
|
+
|
110
|
+
ruby-pgでは以下のPostgreSQLカラム型に対応しています(TE = Text Encoder、TD = Text Decoder、BE =
|
111
|
+
Binary Encoder、BD = Binary Decoder)。
|
112
|
+
|
113
|
+
* Integer:
|
114
|
+
[TE](rdoc-ref:PG::TextEncoder::Integer)、[TD](rdoc-ref:PG::TextDecoder::Integer)、[BD](rdoc-ref:PG::BinaryDecoder::Integer)
|
115
|
+
💡
|
116
|
+
リンクがないでしょうか。[こちら](https://deveiate.org/code/pg/README_ja_md.html#label-E5-9E-8B-E5-A4-89-E6-8F-9B)を代わりに見てください
|
117
|
+
💡
|
118
|
+
* BE:
|
119
|
+
[Int2](rdoc-ref:PG::BinaryEncoder::Int2)、[Int4](rdoc-ref:PG::BinaryEncoder::Int4)、[Int8](rdoc-ref:PG::BinaryEncoder::Int8)
|
120
|
+
* Float:
|
121
|
+
[TE](rdoc-ref:PG::TextEncoder::Float)、[TD](rdoc-ref:PG::TextDecoder::Float)、[BD](rdoc-ref:PG::BinaryDecoder::Float)
|
122
|
+
* Numeric:
|
123
|
+
[TE](rdoc-ref:PG::TextEncoder::Numeric)、[TD](rdoc-ref:PG::TextDecoder::Numeric)
|
124
|
+
* Boolean:
|
125
|
+
[TE](rdoc-ref:PG::TextEncoder::Boolean)、[TD](rdoc-ref:PG::TextDecoder::Boolean)、[BE](rdoc-ref:PG::BinaryEncoder::Boolean)、[BD](rdoc-ref:PG::BinaryDecoder::Boolean)
|
126
|
+
* String:
|
127
|
+
[TE](rdoc-ref:PG::TextEncoder::String)、[TD](rdoc-ref:PG::TextDecoder::String)、[BE](rdoc-ref:PG::BinaryEncoder::String)、[BD](rdoc-ref:PG::BinaryDecoder::String)
|
128
|
+
* Bytea:
|
129
|
+
[TE](rdoc-ref:PG::TextEncoder::Bytea)、[TD](rdoc-ref:PG::TextDecoder::Bytea)、[BE](rdoc-ref:PG::BinaryEncoder::Bytea)、[BD](rdoc-ref:PG::BinaryDecoder::Bytea)
|
130
|
+
* Base64:
|
131
|
+
[TE](rdoc-ref:PG::TextEncoder::ToBase64)、[TD](rdoc-ref:PG::TextDecoder::FromBase64)、[BE](rdoc-ref:PG::BinaryEncoder::FromBase64)、[BD](rdoc-ref:PG::BinaryDecoder::ToBase64)
|
132
|
+
* Timestamp:
|
133
|
+
* TE:
|
134
|
+
[現地時間](rdoc-ref:PG::TextEncoder::TimestampWithoutTimeZone)、[UTC](rdoc-ref:PG::TextEncoder::TimestampUtc)、[タイムゾーン付き](rdoc-ref:PG::TextEncoder::TimestampWithTimeZone)
|
135
|
+
* TD:
|
136
|
+
[現地時間](rdoc-ref:PG::TextDecoder::TimestampLocal)、[UTC](rdoc-ref:PG::TextDecoder::TimestampUtc)、[UTCから現地時間へ](rdoc-ref:PG::TextDecoder::TimestampUtcToLocal)
|
137
|
+
* BD:
|
138
|
+
[現地時間](rdoc-ref:PG::BinaryDecoder::TimestampLocal)、[UTC](rdoc-ref:PG::BinaryDecoder::TimestampUtc)、[UTCから現地時間へ](rdoc-ref:PG::BinaryDecoder::TimestampUtcToLocal)
|
139
|
+
* Date:
|
140
|
+
[TE](rdoc-ref:PG::TextEncoder::Date)、[TD](rdoc-ref:PG::TextDecoder::Date)
|
141
|
+
* JSONとJSONB:
|
142
|
+
[TE](rdoc-ref:PG::TextEncoder::JSON)、[TD](rdoc-ref:PG::TextDecoder::JSON)
|
143
|
+
* Inet:
|
144
|
+
[TE](rdoc-ref:PG::TextEncoder::Inet)、[TD](rdoc-ref:PG::TextDecoder::Inet)
|
145
|
+
* Array:
|
146
|
+
[TE](rdoc-ref:PG::TextEncoder::Array)、[TD](rdoc-ref:PG::TextDecoder::Array)
|
147
|
+
* 複合型(「行」や「レコード」などとも言います):[TE](rdoc-ref:PG::TextEncoder::Record)、[TD](rdoc-ref:PG::TextDecoder::Record)
|
148
|
+
|
149
|
+
カラム型として使われていませんが以下のテキスト形式もエンコードできます。
|
150
|
+
|
151
|
+
* COPYの入出力データ:[TE](rdoc-ref:PG::TextEncoder::CopyRow)、[TD](rdoc-ref:PG::TextDecoder::CopyRow)
|
152
|
+
* SQL文字列に挿入するリテラル:[TE](rdoc-ref:PG::TextEncoder::QuotedLiteral)
|
153
|
+
* SQLの識別子:
|
154
|
+
[TE](rdoc-ref:PG::TextEncoder::Identifier)、[TD](rdoc-ref:PG::TextDecoder::Identifier)
|
155
|
+
|
156
|
+
### PG::TypeMapとその派生 (ext/pg_type_map*.c, lib/pg/type_map*.rb)
|
157
|
+
|
158
|
+
TypeMapはエンコーダーまたはデコーダーのどちらによってどの値を変換するかを定義します。様々な型の対応付け戦略があるので、このクラスにはいくつかの派生が実装されています。型変換の特有の需要に合わせてそれらの派生から選んで調整を加えることができます。既定の型の対応付けはPG::TypeMapAllStringsです。
|
159
|
+
|
160
|
+
型の対応付けは、結果の集合それぞれに対し、接続毎ないしクエリ毎に割り当てることができます。型の対応付けはCOPYの入出力データストリーミングでも使うことができます。PG::Connection#copy_dataを参照してください。
|
161
|
+
|
162
|
+
以下の基底となる型の対応付けが使えます。
|
163
|
+
|
164
|
+
* PG::TypeMapAllStrings - 全ての値と文字列について相互にエンコードとデコードを行います(既定)
|
165
|
+
* PG::TypeMapByClass - 送信する値のクラスに基づいてエンコーダーを選択します
|
166
|
+
* PG::TypeMapByColumn - カラムの順番によってエンコーダーとデコーダーを選択します
|
167
|
+
* PG::TypeMapByOid - PostgreSQLのOIDデータ型によってデコーダーを選択します
|
168
|
+
* PG::TypeMapInRuby - Rubyで独自の型の対応付けを定義します
|
169
|
+
|
170
|
+
以下の型の対応付けはPG::BasicTypeRegistry由来の型の対応付けが入った状態になっています。
|
171
|
+
|
172
|
+
* PG::BasicTypeMapForResults -
|
173
|
+
PG::TypeMapByOidによくあるPostgreSQLカラム型用にデコーダーが入った状態になっています
|
174
|
+
* PG::BasicTypeMapBasedOnResult -
|
175
|
+
PG::TypeMapByOidによくあるPostgreSQLカラム型用のエンコーダーが入った状態になっています
|
176
|
+
* PG::BasicTypeMapForQueries -
|
177
|
+
PG::TypeMapByClassによくあるRubyの値クラス用にエンコーダーが入った状態になっています
|
178
|
+
|
179
|
+
|
180
|
+
## スレッド対応
|
181
|
+
|
182
|
+
PGには個々のスレッドが別々のPG::Connectionオブジェクトを同時に使えるという点でスレッド安全性があります。しかし1つ以上のスレッドから同時にPgのオブジェクトにアクセスすると安全ではありません。そのため必ず、毎回新しいスレッドを作るときに新しいデータベースサーバー接続を開くか、スレッド安全性のある方法で接続を管理するActiveRecordのようなラッパーライブラリを使うようにしてください。
|
183
|
+
|
184
|
+
以下のようなメッセージが標準エラー出力に表示された場合、恐らく複数のスレッドが1つの接続を使っています。
|
185
|
+
|
186
|
+
message type 0x31 arrived from server while idle
|
187
|
+
message type 0x32 arrived from server while idle
|
188
|
+
message type 0x54 arrived from server while idle
|
189
|
+
message type 0x43 arrived from server while idle
|
190
|
+
message type 0x5a arrived from server while idle
|
191
|
+
|
192
|
+
|
193
|
+
## Fiber IOスケジューラー対応
|
194
|
+
|
195
|
+
PgはRuby-3.0で導入された`Fiber.scheduler`に完全に対応しています。`Fiber.scheduler`のWindows対応についてはRuby-3.1以降で使えます。`Fiber.scheduler`が走らせているスレッドに登録されている場合、起こりうる全てのブロッキングIO操作はそのスケジューラーを経由します。同期的であったりブロックしたりするメソッド呼び出しについてもpgが内部的に非同期のlibpqインターフェースを使っているのはそれが理由です。またlibpqの組み込み関数に代えてRubyのDNS解決を使っています。
|
196
|
+
|
197
|
+
内部的にPgは常にlibpqのノンブロッキング接続モードを使います。それからブロッキングモードで走っているように振舞いますが、もし`Fiber.scheduler`が登録されていれば全てのブロッキングIOはそのスケジューラーを通じてRubyで制御されます。`PG::Connection.setnonblocking(true)`が呼ばれたらノンブロッキング状態が有効になったままになりますが、それ以降のブロッキング状態の制御が無効になるので、呼び出しているプログラムはブロッキング状態を自力で制御しなければなりません。
|
198
|
+
|
199
|
+
この規則の1つの例外には、`PG::Connection#lo_create`や外部ライブラリを使う認証メソッド(GSSAPI認証など)のような、大きめのオブジェクト用のメソッドがあります。これらは`Fiber.scheduler`と互換性がないため、ブロッキング状態は登録されたIOスケジューラに渡されません。つまり操作は適切に実行されますが、IO待ち状態に別のIOを扱うFiberから使用を切り替えてくることができなくなります。
|
200
|
+
|
201
|
+
|
202
|
+
## 貢献
|
203
|
+
|
204
|
+
バグを報告したり機能を提案したりGitでソースをチェックアウトしたりするには[プロジェクトページをご確認ください](https://github.com/ged/ruby-pg)。
|
205
|
+
|
206
|
+
ソースをチェックアウトしたあとは全ての依存関係をインストールします。
|
207
|
+
|
208
|
+
$ bundle install
|
209
|
+
|
210
|
+
拡張ファイル、パッケージファイル、テストデータベースを一掃するには次のようにします。
|
211
|
+
|
212
|
+
$ rake clean
|
213
|
+
|
214
|
+
拡張をコンパイルするには次のようにします。
|
215
|
+
|
216
|
+
$ rake compile
|
217
|
+
|
218
|
+
パスにある`initdb`といったPostgreSQLのツールを使ってテストやスペックを走らせるには次のようにします。
|
219
|
+
|
220
|
+
$ PATH=$PATH:/usr/lib/postgresql/14/bin rake test
|
221
|
+
|
222
|
+
あるいは行番号を使って特定のテストを走らせるには次のようにします。
|
223
|
+
|
224
|
+
$ PATH=$PATH:/usr/lib/postgresql/14/bin rspec -Ilib -fd spec/pg/connection_spec.rb:455
|
225
|
+
|
226
|
+
APIドキュメントを生成するには次のようにします。
|
227
|
+
|
228
|
+
$ rake docs
|
229
|
+
|
230
|
+
必ず全てのバグと新機能についてテストを使って検証してください。
|
231
|
+
|
232
|
+
現在のメンテナはMichael Granger <ged@FaerieMUD.org>とLars Kanis
|
233
|
+
<lars@greiz-reinsdorf.de>です。
|
234
|
+
|
235
|
+
|
236
|
+
## 著作権
|
237
|
+
|
238
|
+
Copyright (c) 1997-2022 by the authors.
|
239
|
+
|
240
|
+
* Jeff Davis <ruby-pg@j-davis.com>
|
241
|
+
* Guy Decoux (ts) <decoux@moulon.inra.fr>
|
242
|
+
* Michael Granger <ged@FaerieMUD.org>
|
243
|
+
* Lars Kanis <lars@greiz-reinsdorf.de>
|
244
|
+
* Dave Lee
|
245
|
+
* Eiji Matsumoto <usagi@ruby.club.or.jp>
|
246
|
+
* Yukihiro Matsumoto <matz@ruby-lang.org>
|
247
|
+
* Noboru Saitou <noborus@netlab.jp>
|
248
|
+
|
249
|
+
You may redistribute this software under the same terms as Ruby itself; see
|
250
|
+
https://www.ruby-lang.org/en/about/license.txt or the BSDL file in the
|
251
|
+
source for details.
|
252
|
+
(参考訳:このソフトウェアはRuby自体と同じ条件の元で再配布することができます。詳細については
|
253
|
+
https://www.ruby-lang.org/en/about/license.txt やソース中のBSDLファイルを参照してください)
|
254
|
+
|
255
|
+
Portions of the code are from the PostgreSQL project, and are distributed "
|
256
|
+
"under the terms of the PostgreSQL license, included in the file POSTGRES.
|
257
|
+
(参考訳:コードの一部はPostgreSQLプロジェクトから来ており、PostgreSQLの使用許諾の条件の元で配布されます。ファイルPOSTGRESに含まれています)
|
258
|
+
|
259
|
+
Portions copyright LAIKA, Inc.
|
260
|
+
|
261
|
+
|
262
|
+
## 謝辞
|
263
|
+
|
264
|
+
長年にわたって貢献してくださった方々についてはContributors.rdocを参照してください。
|
265
|
+
|
266
|
+
ruby-listとruby-devメーリングリストの方々に感謝します。またPostgreSQLを開発された方々へも謝意を表します。
|
data/README.md
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
# pg
|
2
|
+
|
3
|
+
* home :: https://github.com/ged/ruby-pg
|
4
|
+
* docs :: http://deveiate.org/code/pg
|
5
|
+
* clog :: link:/History.md
|
6
|
+
|
7
|
+
[![Join the chat at https://gitter.im/ged/ruby-pg](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ged/ruby-pg?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
|
+
|
9
|
+
|
10
|
+
## Description
|
11
|
+
|
12
|
+
Pg is the Ruby interface to the [PostgreSQL RDBMS](http://www.postgresql.org/).
|
13
|
+
It works with [PostgreSQL 9.3 and later](http://www.postgresql.org/support/versioning/).
|
14
|
+
|
15
|
+
A small example usage:
|
16
|
+
```ruby
|
17
|
+
#!/usr/bin/env ruby
|
18
|
+
|
19
|
+
require 'pg'
|
20
|
+
|
21
|
+
# Output a table of current connections to the DB
|
22
|
+
conn = PG.connect( dbname: 'sales' )
|
23
|
+
conn.exec( "SELECT * FROM pg_stat_activity" ) do |result|
|
24
|
+
puts " PID | User | Query"
|
25
|
+
result.each do |row|
|
26
|
+
puts " %7d | %-16s | %s " %
|
27
|
+
row.values_at('pid', 'usename', 'query')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
## Build Status
|
33
|
+
|
34
|
+
[![Build Status Github Actions](https://github.com/ged/ruby-pg/actions/workflows/source-gem.yml/badge.svg?branch=master)](https://github.com/ged/ruby-pg/actions/workflows/source-gem.yml)
|
35
|
+
[![Binary gems](https://github.com/ged/ruby-pg/actions/workflows/binary-gems.yml/badge.svg?branch=master)](https://github.com/ged/ruby-pg/actions/workflows/binary-gems.yml)
|
36
|
+
[![Build Status Appveyor](https://ci.appveyor.com/api/projects/status/gjx5axouf3b1wicp?svg=true)](https://ci.appveyor.com/project/ged/ruby-pg-9j8l3)
|
37
|
+
|
38
|
+
|
39
|
+
## Requirements
|
40
|
+
|
41
|
+
* Ruby 2.4 or newer
|
42
|
+
* PostgreSQL 9.3.x or later (with headers, -dev packages, etc).
|
43
|
+
|
44
|
+
It usually works with earlier versions of Ruby/PostgreSQL as well, but those are
|
45
|
+
not regularly tested.
|
46
|
+
|
47
|
+
|
48
|
+
## Versioning
|
49
|
+
|
50
|
+
We tag and release gems according to the [Semantic Versioning](http://semver.org/) principle.
|
51
|
+
|
52
|
+
As a result of this policy, you can (and should) specify a dependency on this gem using the [Pessimistic Version Constraint](http://guides.rubygems.org/patterns/#pessimistic-version-constraint) with two digits of precision.
|
53
|
+
|
54
|
+
For example:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
spec.add_dependency 'pg', '~> 1.0'
|
58
|
+
```
|
59
|
+
|
60
|
+
## How To Install
|
61
|
+
|
62
|
+
Install via RubyGems:
|
63
|
+
|
64
|
+
gem install pg
|
65
|
+
|
66
|
+
You may need to specify the path to the 'pg_config' program installed with
|
67
|
+
Postgres:
|
68
|
+
|
69
|
+
gem install pg -- --with-pg-config=<path to pg_config>
|
70
|
+
|
71
|
+
If you're installing via Bundler, you can provide compile hints like so:
|
72
|
+
|
73
|
+
bundle config build.pg --with-pg-config=<path to pg_config>
|
74
|
+
|
75
|
+
See README-OS_X.rdoc for more information about installing under MacOS X, and
|
76
|
+
README-Windows.rdoc for Windows build/installation instructions.
|
77
|
+
|
78
|
+
There's also [a Google+ group](http://goo.gl/TFy1U) and a
|
79
|
+
[mailing list](http://groups.google.com/group/ruby-pg) if you get stuck, or just
|
80
|
+
want to chat about something.
|
81
|
+
|
82
|
+
If you want to install as a signed gem, the public certs of the gem signers
|
83
|
+
can be found in [the `certs` directory](https://github.com/ged/ruby-pg/tree/master/certs)
|
84
|
+
of the repository.
|
85
|
+
|
86
|
+
|
87
|
+
## Type Casts
|
88
|
+
|
89
|
+
Pg can optionally type cast result values and query parameters in Ruby or
|
90
|
+
native C code. This can speed up data transfers to and from the database,
|
91
|
+
because String allocations are reduced and conversions in (slower) Ruby code
|
92
|
+
can be omitted.
|
93
|
+
|
94
|
+
Very basic type casting can be enabled by:
|
95
|
+
```ruby
|
96
|
+
conn.type_map_for_results = PG::BasicTypeMapForResults.new conn
|
97
|
+
# ... this works for result value mapping:
|
98
|
+
conn.exec("select 1, now(), '{2,3}'::int[]").values
|
99
|
+
# => [[1, 2014-09-21 20:51:56 +0200, [2, 3]]]
|
100
|
+
|
101
|
+
conn.type_map_for_queries = PG::BasicTypeMapForQueries.new conn
|
102
|
+
# ... and this for param value mapping:
|
103
|
+
conn.exec_params("SELECT $1::text, $2::text, $3::text", [1, 1.23, [2,3]]).values
|
104
|
+
# => [["1", "1.2300000000000000E+00", "{2,3}"]]
|
105
|
+
```
|
106
|
+
|
107
|
+
But Pg's type casting is highly customizable. That's why it's divided into
|
108
|
+
2 layers:
|
109
|
+
|
110
|
+
### Encoders / Decoders (ext/pg_*coder.c, lib/pg/*coder.rb)
|
111
|
+
|
112
|
+
This is the lower layer, containing encoding classes that convert Ruby
|
113
|
+
objects for transmission to the DBMS and decoding classes to convert
|
114
|
+
received data back to Ruby objects. The classes are namespaced according
|
115
|
+
to their format and direction in PG::TextEncoder, PG::TextDecoder,
|
116
|
+
PG::BinaryEncoder and PG::BinaryDecoder.
|
117
|
+
|
118
|
+
It is possible to assign a type OID, format code (text or binary) and
|
119
|
+
optionally a name to an encoder or decoder object. It's also possible
|
120
|
+
to build composite types by assigning an element encoder/decoder.
|
121
|
+
PG::Coder objects can be used to set up a PG::TypeMap or alternatively
|
122
|
+
to convert single values to/from their string representation.
|
123
|
+
|
124
|
+
The following PostgreSQL column types are supported by ruby-pg (TE = Text Encoder, TD = Text Decoder, BE = Binary Encoder, BD = Binary Decoder):
|
125
|
+
|
126
|
+
* Integer: [TE](rdoc-ref:PG::TextEncoder::Integer), [TD](rdoc-ref:PG::TextDecoder::Integer), [BD](rdoc-ref:PG::BinaryDecoder::Integer) 💡 No links? Switch to [here](https://deveiate.org/code/pg/README_md.html#label-Type+Casts) 💡
|
127
|
+
* BE: [Int2](rdoc-ref:PG::BinaryEncoder::Int2), [Int4](rdoc-ref:PG::BinaryEncoder::Int4), [Int8](rdoc-ref:PG::BinaryEncoder::Int8)
|
128
|
+
* Float: [TE](rdoc-ref:PG::TextEncoder::Float), [TD](rdoc-ref:PG::TextDecoder::Float), [BD](rdoc-ref:PG::BinaryDecoder::Float)
|
129
|
+
* Numeric: [TE](rdoc-ref:PG::TextEncoder::Numeric), [TD](rdoc-ref:PG::TextDecoder::Numeric)
|
130
|
+
* Boolean: [TE](rdoc-ref:PG::TextEncoder::Boolean), [TD](rdoc-ref:PG::TextDecoder::Boolean), [BE](rdoc-ref:PG::BinaryEncoder::Boolean), [BD](rdoc-ref:PG::BinaryDecoder::Boolean)
|
131
|
+
* String: [TE](rdoc-ref:PG::TextEncoder::String), [TD](rdoc-ref:PG::TextDecoder::String), [BE](rdoc-ref:PG::BinaryEncoder::String), [BD](rdoc-ref:PG::BinaryDecoder::String)
|
132
|
+
* Bytea: [TE](rdoc-ref:PG::TextEncoder::Bytea), [TD](rdoc-ref:PG::TextDecoder::Bytea), [BE](rdoc-ref:PG::BinaryEncoder::Bytea), [BD](rdoc-ref:PG::BinaryDecoder::Bytea)
|
133
|
+
* Base64: [TE](rdoc-ref:PG::TextEncoder::ToBase64), [TD](rdoc-ref:PG::TextDecoder::FromBase64), [BE](rdoc-ref:PG::BinaryEncoder::FromBase64), [BD](rdoc-ref:PG::BinaryDecoder::ToBase64)
|
134
|
+
* Timestamp:
|
135
|
+
* TE: [local](rdoc-ref:PG::TextEncoder::TimestampWithoutTimeZone), [UTC](rdoc-ref:PG::TextEncoder::TimestampUtc), [with-TZ](rdoc-ref:PG::TextEncoder::TimestampWithTimeZone)
|
136
|
+
* TD: [local](rdoc-ref:PG::TextDecoder::TimestampLocal), [UTC](rdoc-ref:PG::TextDecoder::TimestampUtc), [UTC-to-local](rdoc-ref:PG::TextDecoder::TimestampUtcToLocal)
|
137
|
+
* BD: [local](rdoc-ref:PG::BinaryDecoder::TimestampLocal), [UTC](rdoc-ref:PG::BinaryDecoder::TimestampUtc), [UTC-to-local](rdoc-ref:PG::BinaryDecoder::TimestampUtcToLocal)
|
138
|
+
* Date: [TE](rdoc-ref:PG::TextEncoder::Date), [TD](rdoc-ref:PG::TextDecoder::Date)
|
139
|
+
* JSON and JSONB: [TE](rdoc-ref:PG::TextEncoder::JSON), [TD](rdoc-ref:PG::TextDecoder::JSON)
|
140
|
+
* Inet: [TE](rdoc-ref:PG::TextEncoder::Inet), [TD](rdoc-ref:PG::TextDecoder::Inet)
|
141
|
+
* Array: [TE](rdoc-ref:PG::TextEncoder::Array), [TD](rdoc-ref:PG::TextDecoder::Array)
|
142
|
+
* Composite Type (also called "Row" or "Record"): [TE](rdoc-ref:PG::TextEncoder::Record), [TD](rdoc-ref:PG::TextDecoder::Record)
|
143
|
+
|
144
|
+
The following text formats can also be encoded although they are not used as column type:
|
145
|
+
|
146
|
+
* COPY input and output data: [TE](rdoc-ref:PG::TextEncoder::CopyRow), [TD](rdoc-ref:PG::TextDecoder::CopyRow)
|
147
|
+
* Literal for insertion into SQL string: [TE](rdoc-ref:PG::TextEncoder::QuotedLiteral)
|
148
|
+
* SQL-Identifier: [TE](rdoc-ref:PG::TextEncoder::Identifier), [TD](rdoc-ref:PG::TextDecoder::Identifier)
|
149
|
+
|
150
|
+
### PG::TypeMap and derivations (ext/pg_type_map*.c, lib/pg/type_map*.rb)
|
151
|
+
|
152
|
+
A TypeMap defines which value will be converted by which encoder/decoder.
|
153
|
+
There are different type map strategies, implemented by several derivations
|
154
|
+
of this class. They can be chosen and configured according to the particular
|
155
|
+
needs for type casting. The default type map is PG::TypeMapAllStrings.
|
156
|
+
|
157
|
+
A type map can be assigned per connection or per query respectively per
|
158
|
+
result set. Type maps can also be used for COPY in and out data streaming.
|
159
|
+
See PG::Connection#copy_data .
|
160
|
+
|
161
|
+
The following base type maps are available:
|
162
|
+
|
163
|
+
* PG::TypeMapAllStrings - encodes and decodes all values to and from strings (default)
|
164
|
+
* PG::TypeMapByClass - selects encoder based on the class of the value to be sent
|
165
|
+
* PG::TypeMapByColumn - selects encoder and decoder by column order
|
166
|
+
* PG::TypeMapByOid - selects decoder by PostgreSQL type OID
|
167
|
+
* PG::TypeMapInRuby - define a custom type map in ruby
|
168
|
+
|
169
|
+
The following type maps are prefilled with type mappings from the PG::BasicTypeRegistry :
|
170
|
+
|
171
|
+
* PG::BasicTypeMapForResults - a PG::TypeMapByOid prefilled with decoders for common PostgreSQL column types
|
172
|
+
* PG::BasicTypeMapBasedOnResult - a PG::TypeMapByOid prefilled with encoders for common PostgreSQL column types
|
173
|
+
* PG::BasicTypeMapForQueries - a PG::TypeMapByClass prefilled with encoders for common Ruby value classes
|
174
|
+
|
175
|
+
|
176
|
+
## Thread support
|
177
|
+
|
178
|
+
PG is thread safe in such a way that different threads can use different PG::Connection objects concurrently.
|
179
|
+
However it is not safe to access any Pg objects simultaneously from more than one thread.
|
180
|
+
So make sure to open a new database server connection for every new thread or use a wrapper library like ActiveRecord that manages connections in a thread safe way.
|
181
|
+
|
182
|
+
If messages like the following are printed to stderr, you're probably using one connection from several threads:
|
183
|
+
|
184
|
+
message type 0x31 arrived from server while idle
|
185
|
+
message type 0x32 arrived from server while idle
|
186
|
+
message type 0x54 arrived from server while idle
|
187
|
+
message type 0x43 arrived from server while idle
|
188
|
+
message type 0x5a arrived from server while idle
|
189
|
+
|
190
|
+
|
191
|
+
## Fiber IO scheduler support
|
192
|
+
|
193
|
+
Pg is fully compatible with `Fiber.scheduler` introduced in Ruby-3.0.
|
194
|
+
On Windows support for `Fiber.scheduler` is available on Ruby-3.1 or newer.
|
195
|
+
All possibly blocking IO operations are routed through the `Fiber.scheduler` if one is registered for the running thread.
|
196
|
+
That is why pg internally uses the asynchronous libpq interface even for synchronous/blocking method calls.
|
197
|
+
It also uses Ruby's DNS resolution instead of libpq's builtin functions.
|
198
|
+
|
199
|
+
Internally Pg always uses the nonblocking connection mode of libpq.
|
200
|
+
It then behaves like running in blocking mode but ensures, that all blocking IO is handled in Ruby through a possibly registered `Fiber.scheduler`.
|
201
|
+
When `PG::Connection.setnonblocking(true)` is called then the nonblocking state stays enabled, but the additional handling of blocking states is disabled, so that the calling program has to handle blocking states on its own.
|
202
|
+
|
203
|
+
An exception to this rule are the methods for large objects like `PG::Connection#lo_create` and authentication methods using external libraries (like GSSAPI authentication).
|
204
|
+
They are not compatible with `Fiber.scheduler`, so that blocking states are not passed to the registered IO scheduler.
|
205
|
+
That means the operation will work properly, but IO waiting states can not be used to switch to another Fiber doing IO.
|
206
|
+
|
207
|
+
|
208
|
+
## Contributing
|
209
|
+
|
210
|
+
To report bugs, suggest features, or check out the source with Git,
|
211
|
+
[check out the project page](https://github.com/ged/ruby-pg).
|
212
|
+
|
213
|
+
After checking out the source, install all dependencies:
|
214
|
+
|
215
|
+
$ bundle install
|
216
|
+
|
217
|
+
Cleanup extension files, packaging files, test databases:
|
218
|
+
|
219
|
+
$ rake clean
|
220
|
+
|
221
|
+
Compile extension:
|
222
|
+
|
223
|
+
$ rake compile
|
224
|
+
|
225
|
+
Run tests/specs with PostgreSQL tools like `initdb` in the path:
|
226
|
+
|
227
|
+
$ PATH=$PATH:/usr/lib/postgresql/14/bin rake test
|
228
|
+
|
229
|
+
Or run a specific test with the line number:
|
230
|
+
|
231
|
+
$ PATH=$PATH:/usr/lib/postgresql/14/bin rspec -Ilib -fd spec/pg/connection_spec.rb:455
|
232
|
+
|
233
|
+
Generate the API documentation:
|
234
|
+
|
235
|
+
$ rake docs
|
236
|
+
|
237
|
+
Make sure, that all bugs and new features are verified by tests.
|
238
|
+
|
239
|
+
The current maintainers are Michael Granger <ged@FaerieMUD.org> and
|
240
|
+
Lars Kanis <lars@greiz-reinsdorf.de>.
|
241
|
+
|
242
|
+
|
243
|
+
## Copying
|
244
|
+
|
245
|
+
Copyright (c) 1997-2022 by the authors.
|
246
|
+
|
247
|
+
* Jeff Davis <ruby-pg@j-davis.com>
|
248
|
+
* Guy Decoux (ts) <decoux@moulon.inra.fr>
|
249
|
+
* Michael Granger <ged@FaerieMUD.org>
|
250
|
+
* Lars Kanis <lars@greiz-reinsdorf.de>
|
251
|
+
* Dave Lee
|
252
|
+
* Eiji Matsumoto <usagi@ruby.club.or.jp>
|
253
|
+
* Yukihiro Matsumoto <matz@ruby-lang.org>
|
254
|
+
* Noboru Saitou <noborus@netlab.jp>
|
255
|
+
|
256
|
+
You may redistribute this software under the same terms as Ruby itself; see
|
257
|
+
https://www.ruby-lang.org/en/about/license.txt or the BSDL file in the source
|
258
|
+
for details.
|
259
|
+
|
260
|
+
Portions of the code are from the PostgreSQL project, and are distributed
|
261
|
+
under the terms of the PostgreSQL license, included in the file POSTGRES.
|
262
|
+
|
263
|
+
Portions copyright LAIKA, Inc.
|
264
|
+
|
265
|
+
|
266
|
+
## Acknowledgments
|
267
|
+
|
268
|
+
See Contributors.rdoc for the many additional fine people that have contributed
|
269
|
+
to this library over the years.
|
270
|
+
|
271
|
+
We are thankful to the people at the ruby-list and ruby-dev mailing lists.
|
272
|
+
And to the people who developed PostgreSQL.
|
data/Rakefile
CHANGED
@@ -74,10 +74,9 @@ task :test => :spec
|
|
74
74
|
require 'rdoc/task'
|
75
75
|
|
76
76
|
RDoc::Task.new( 'docs' ) do |rdoc|
|
77
|
-
rdoc.
|
78
|
-
rdoc.rdoc_files
|
77
|
+
rdoc.options = $gem_spec.rdoc_options
|
78
|
+
rdoc.rdoc_files = $gem_spec.extra_rdoc_files
|
79
79
|
rdoc.generator = :fivefish
|
80
|
-
rdoc.title = "PG: The Ruby PostgreSQL Driver"
|
81
80
|
rdoc.rdoc_dir = 'doc'
|
82
81
|
end
|
83
82
|
|
@@ -104,3 +103,13 @@ file 'ext/pg_errors.c' => ['ext/errorcodes.def'] do
|
|
104
103
|
# trigger compilation of changed errorcodes.def
|
105
104
|
touch 'ext/pg_errors.c'
|
106
105
|
end
|
106
|
+
|
107
|
+
desc "Translate readme"
|
108
|
+
task :translate do
|
109
|
+
cd "translation" do
|
110
|
+
# po4a's lexer might change, so record its version for reference
|
111
|
+
sh "LANG=C po4a --version > .po4a-version"
|
112
|
+
|
113
|
+
sh "po4a po4a.cfg"
|
114
|
+
end
|
115
|
+
end
|
data/Rakefile.cross
CHANGED
@@ -31,8 +31,8 @@ class CrossLibrary < OpenStruct
|
|
31
31
|
self.host_platform = toolchain
|
32
32
|
|
33
33
|
# Cross-compilation constants
|
34
|
-
self.openssl_version = ENV['OPENSSL_VERSION'] || '
|
35
|
-
self.postgresql_version = ENV['POSTGRESQL_VERSION'] || '15.
|
34
|
+
self.openssl_version = ENV['OPENSSL_VERSION'] || '3.0.8'
|
35
|
+
self.postgresql_version = ENV['POSTGRESQL_VERSION'] || '15.2'
|
36
36
|
|
37
37
|
# Check if symlinks work in the current working directory.
|
38
38
|
# This fails, if rake-compiler-dock is running on a Windows box.
|
@@ -127,7 +127,7 @@ class CrossLibrary < OpenStruct
|
|
127
127
|
file openssl_makefile => static_openssl_builddir do |t|
|
128
128
|
chdir( static_openssl_builddir ) do
|
129
129
|
cmd = cmd_prelude.dup
|
130
|
-
cmd << "./Configure" << openssl_config
|
130
|
+
cmd << "./Configure" << "-static" << openssl_config
|
131
131
|
|
132
132
|
run( *cmd )
|
133
133
|
end
|
@@ -146,14 +146,10 @@ class CrossLibrary < OpenStruct
|
|
146
146
|
end
|
147
147
|
|
148
148
|
desc "compile static #{libssl}"
|
149
|
-
file libssl => "compile_static_openssl:#{for_platform}"
|
150
|
-
rm t.name.gsub(/\.a$/, ".dll.a")
|
151
|
-
end
|
149
|
+
file libssl => "compile_static_openssl:#{for_platform}"
|
152
150
|
|
153
151
|
desc "compile static #{libcrypto}"
|
154
|
-
file libcrypto => "compile_static_openssl:#{for_platform}"
|
155
|
-
rm t.name.gsub(/\.a$/, ".dll.a")
|
156
|
-
end
|
152
|
+
file libcrypto => "compile_static_openssl:#{for_platform}"
|
157
153
|
|
158
154
|
|
159
155
|
|
@@ -196,7 +192,7 @@ class CrossLibrary < OpenStruct
|
|
196
192
|
cmd << "CFLAGS=-L#{static_openssl_builddir}"
|
197
193
|
cmd << "LDFLAGS=-L#{static_openssl_builddir}"
|
198
194
|
cmd << "LDFLAGS_SL=-L#{static_openssl_builddir}"
|
199
|
-
cmd << "LIBS=-lwsock32 -lgdi32 -lws2_32"
|
195
|
+
cmd << "LIBS=-lwsock32 -lgdi32 -lws2_32 -lcrypt32"
|
200
196
|
cmd << "CPPFLAGS=-I#{static_openssl_builddir}/include"
|
201
197
|
|
202
198
|
run( *cmd )
|
@@ -294,7 +290,7 @@ CrossLibraries.each do |xlib|
|
|
294
290
|
RakeCompilerDock.sh <<-EOT, platform: platform
|
295
291
|
(cp build/gem/gem-*.pem ~/.gem/ || true) &&
|
296
292
|
bundle install --local &&
|
297
|
-
rake native:#{platform} pkg/#{$gem_spec.full_name}-#{platform}.gem MAKE="make -j`nproc`" RUBY_CC_VERSION=3.1.0:3.0.0:2.7.0:2.6.0:2.5.0
|
293
|
+
rake native:#{platform} pkg/#{$gem_spec.full_name}-#{platform}.gem MAKE="make -j`nproc`" RUBY_CC_VERSION=3.2.0:3.1.0:3.0.0:2.7.0:2.6.0:2.5.0
|
298
294
|
EOT
|
299
295
|
end
|
300
296
|
desc "Build the windows binary gems"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIEBDCCAmygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
|
3
|
+
L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yMzAyMTUxNzQxMTVaFw0yNDAy
|
4
|
+
MTUxNzQxMTVaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
|
5
|
+
PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
|
6
|
+
mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
|
7
|
+
eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
|
8
|
+
8nBMvR0mHo77kIkapHc26UzVq/G0nKLfDsIHXVylto3PjzOumjG6GhmFN4r3cP6e
|
9
|
+
SDfl1FSeRYVpt4kmQULz/zdSaOH3AjAq7PM2Z91iGwQvoUXMANH2v89OWjQO/NHe
|
10
|
+
JMNDFsmHK/6Ji4Kk48Z3TyscHQnipAID5GhS1oD21/WePdj7GhmbF5gBzkV5uepd
|
11
|
+
eJQPgWGwrQW/Z2oPjRuJrRofzWfrMWqbOahj9uth6WSxhNexUtbjk6P8emmXOJi5
|
12
|
+
chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
|
13
|
+
9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjOTA3MAkG
|
14
|
+
A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQ4h1tIyvdUWtMI739xMzTR
|
15
|
+
7EfMFzANBgkqhkiG9w0BAQsFAAOCAYEAQAcuTARfiiVUVx5KURICfdTM2Kd7LhOn
|
16
|
+
qt3Vs4ANGvT226LEp3RnQ+kWGQYMRb3cw3LY2TNQRPlnZxE994mgjBscN4fbjXqO
|
17
|
+
T0JbVpeszRZa5k1goggbnWT7CO7yU7WcHh13DaSubY7HUpAJn2xz9w2stxQfN/EE
|
18
|
+
VMlnDJ1P7mUHAvpK8X9j9h7Xlc1niViT18MYwux8mboVTryrLr+clATUkkM3yBF0
|
19
|
+
RV+c34ReW5eXO9Tr6aKTxh/pFC9ggDT6jOxuJgSvG8HWJzVf4NDvMavIas4KYjiI
|
20
|
+
BU6CpWaG5NxicqL3BERi52U43HV08br+LNVpb7Rekgve/PJuSFnAR015bhSRXe5U
|
21
|
+
vBioD1qW2ZW9tXg8Ww2IfDaO5a1So5Xby51rhNlyo6ATj2NkuLWZUKPKHhAz0TKm
|
22
|
+
Dzx/gFSOrRoCt2mXNgrmcAfr386AfaMvCh7cXqdxZwmVo7ILZCYXck0pajvubsDd
|
23
|
+
NUIIFkVXvd1odFyK9LF1RFAtxn/iAmpx
|
24
|
+
-----END CERTIFICATE-----
|