pg 1.3.3 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +15 -9
  4. data/.github/workflows/binary-gems.yml +43 -12
  5. data/.github/workflows/source-gem.yml +28 -20
  6. data/.gitignore +11 -2
  7. data/.travis.yml +2 -2
  8. data/{History.rdoc → History.md} +302 -115
  9. data/README.ja.md +276 -0
  10. data/README.md +286 -0
  11. data/Rakefile +15 -6
  12. data/Rakefile.cross +7 -11
  13. data/certs/larskanis-2023.pem +24 -0
  14. data/ext/errorcodes.def +4 -0
  15. data/ext/errorcodes.rb +0 -0
  16. data/ext/errorcodes.txt +2 -1
  17. data/ext/extconf.rb +0 -0
  18. data/ext/pg.c +14 -54
  19. data/ext/pg.h +12 -5
  20. data/ext/pg_binary_decoder.c +80 -1
  21. data/ext/pg_binary_encoder.c +225 -1
  22. data/ext/pg_coder.c +17 -8
  23. data/ext/pg_connection.c +385 -266
  24. data/ext/pg_copy_coder.c +307 -18
  25. data/ext/pg_errors.c +1 -1
  26. data/ext/pg_record_coder.c +12 -9
  27. data/ext/pg_result.c +117 -34
  28. data/ext/pg_text_decoder.c +28 -10
  29. data/ext/pg_text_encoder.c +23 -10
  30. data/ext/pg_tuple.c +36 -39
  31. data/ext/pg_type_map.c +4 -3
  32. data/ext/pg_type_map_all_strings.c +3 -3
  33. data/ext/pg_type_map_by_class.c +6 -4
  34. data/ext/pg_type_map_by_column.c +9 -5
  35. data/ext/pg_type_map_by_mri_type.c +1 -1
  36. data/ext/pg_type_map_by_oid.c +8 -5
  37. data/ext/pg_type_map_in_ruby.c +6 -3
  38. data/lib/pg/basic_type_map_based_on_result.rb +21 -1
  39. data/lib/pg/basic_type_map_for_queries.rb +13 -8
  40. data/lib/pg/basic_type_map_for_results.rb +26 -3
  41. data/lib/pg/basic_type_registry.rb +36 -33
  42. data/lib/pg/binary_decoder/date.rb +9 -0
  43. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  44. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  45. data/lib/pg/coder.rb +15 -13
  46. data/lib/pg/connection.rb +269 -139
  47. data/lib/pg/exceptions.rb +14 -1
  48. data/lib/pg/text_decoder/date.rb +18 -0
  49. data/lib/pg/text_decoder/inet.rb +9 -0
  50. data/lib/pg/text_decoder/json.rb +14 -0
  51. data/lib/pg/text_decoder/numeric.rb +9 -0
  52. data/lib/pg/text_decoder/timestamp.rb +30 -0
  53. data/lib/pg/text_encoder/date.rb +12 -0
  54. data/lib/pg/text_encoder/inet.rb +28 -0
  55. data/lib/pg/text_encoder/json.rb +14 -0
  56. data/lib/pg/text_encoder/numeric.rb +9 -0
  57. data/lib/pg/text_encoder/timestamp.rb +24 -0
  58. data/lib/pg/version.rb +1 -1
  59. data/lib/pg.rb +59 -19
  60. data/misc/openssl-pg-segfault.rb +0 -0
  61. data/pg.gemspec +4 -2
  62. data/rakelib/task_extension.rb +1 -1
  63. data/sample/array_insert.rb +0 -0
  64. data/sample/async_api.rb +3 -7
  65. data/sample/async_copyto.rb +0 -0
  66. data/sample/async_mixed.rb +0 -0
  67. data/sample/check_conn.rb +0 -0
  68. data/sample/copydata.rb +0 -0
  69. data/sample/copyfrom.rb +0 -0
  70. data/sample/copyto.rb +0 -0
  71. data/sample/cursor.rb +0 -0
  72. data/sample/disk_usage_report.rb +0 -0
  73. data/sample/issue-119.rb +0 -0
  74. data/sample/losample.rb +0 -0
  75. data/sample/minimal-testcase.rb +0 -0
  76. data/sample/notify_wait.rb +0 -0
  77. data/sample/pg_statistics.rb +0 -0
  78. data/sample/replication_monitor.rb +0 -0
  79. data/sample/test_binary_values.rb +0 -0
  80. data/sample/wal_shipper.rb +0 -0
  81. data/sample/warehouse_partitions.rb +0 -0
  82. data/translation/.po4a-version +7 -0
  83. data/translation/po/all.pot +910 -0
  84. data/translation/po/ja.po +1047 -0
  85. data/translation/po4a.cfg +12 -0
  86. data.tar.gz.sig +0 -0
  87. metadata +101 -32
  88. metadata.gz.sig +0 -0
  89. data/README.ja.rdoc +0 -13
  90. data/README.rdoc +0 -214
  91. data/lib/pg/binary_decoder.rb +0 -23
  92. data/lib/pg/constants.rb +0 -12
  93. data/lib/pg/text_decoder.rb +0 -46
  94. data/lib/pg/text_encoder.rb +0 -59
@@ -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-----
data/ext/errorcodes.def CHANGED
@@ -366,6 +366,10 @@
366
366
  VALUE klass = define_error_class( "SqlJsonScalarRequired", "22" );
367
367
  register_error_class( "2203F", klass );
368
368
  }
369
+ {
370
+ VALUE klass = define_error_class( "SqlJsonItemCannotBeCastToTargetType", "22" );
371
+ register_error_class( "2203G", klass );
372
+ }
369
373
  {
370
374
  VALUE klass = define_error_class( "IntegrityConstraintViolation", NULL );
371
375
  register_error_class( "23000", klass );
data/ext/errorcodes.rb CHANGED
File without changes
data/ext/errorcodes.txt CHANGED
@@ -2,7 +2,7 @@
2
2
  # errcodes.txt
3
3
  # PostgreSQL error codes
4
4
  #
5
- # Copyright (c) 2003-2021, PostgreSQL Global Development Group
5
+ # Copyright (c) 2003-2022, PostgreSQL Global Development Group
6
6
  #
7
7
  # This list serves as the basis for generating source files containing error
8
8
  # codes. It is kept in a common format to make sure all these source files have
@@ -222,6 +222,7 @@ Section: Class 22 - Data Exception
222
222
  2203D E ERRCODE_TOO_MANY_JSON_ARRAY_ELEMENTS too_many_json_array_elements
223
223
  2203E E ERRCODE_TOO_MANY_JSON_OBJECT_MEMBERS too_many_json_object_members
224
224
  2203F E ERRCODE_SQL_JSON_SCALAR_REQUIRED sql_json_scalar_required
225
+ 2203G E ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE sql_json_item_cannot_be_cast_to_target_type
225
226
 
226
227
  Section: Class 23 - Integrity Constraint Violation
227
228
 
data/ext/extconf.rb CHANGED
File without changes
data/ext/pg.c CHANGED
@@ -33,7 +33,6 @@
33
33
  *
34
34
  * - PQfreemem -- unnecessary: copied to ruby object, then freed. Ruby object's
35
35
  * memory is freed when it is garbage collected.
36
- * - PQbinaryTuples -- better to use PQfformat
37
36
  * - PQprint -- not very useful
38
37
  * - PQsetdb -- not very useful
39
38
  * - PQoidStatus -- deprecated, use PQoidValue
@@ -47,7 +46,6 @@
47
46
  */
48
47
 
49
48
  #include "pg.h"
50
- #include "pg_config.h"
51
49
 
52
50
  int pg_skip_deprecation_warning;
53
51
  VALUE rb_mPG;
@@ -75,6 +73,7 @@ VALUE rb_mPGconstants;
75
73
  * The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
76
74
  */
77
75
  const char * const (pg_enc_pg2ruby_mapping[][2]) = {
76
+ {"UTF8", "UTF-8" },
78
77
  {"BIG5", "Big5" },
79
78
  {"EUC_CN", "GB2312" },
80
79
  {"EUC_JP", "EUC-JP" },
@@ -106,7 +105,6 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
106
105
  {"SHIFT_JIS_2004","Windows-31J" },
107
106
  /* {"SQL_ASCII", NULL }, special case*/
108
107
  {"UHC", "CP949" },
109
- {"UTF8", "UTF-8" },
110
108
  {"WIN866", "IBM866" },
111
109
  {"WIN874", "Windows-874" },
112
110
  {"WIN1250", "Windows-1250"},
@@ -121,32 +119,6 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
121
119
  };
122
120
 
123
121
 
124
- /*
125
- * A cache of mapping from PostgreSQL's encoding indices to Ruby's rb_encoding*s.
126
- */
127
- static struct st_table *enc_pg2ruby;
128
-
129
-
130
- /*
131
- * Look up the JOHAB encoding, creating it as a dummy encoding if it's not
132
- * already defined.
133
- */
134
- static rb_encoding *
135
- pg_find_or_create_johab(void)
136
- {
137
- static const char * const aliases[] = { "JOHAB", "Windows-1361", "CP1361" };
138
- int enc_index;
139
- size_t i;
140
-
141
- for (i = 0; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
142
- enc_index = rb_enc_find_index(aliases[i]);
143
- if (enc_index > 0) return rb_enc_from_index(enc_index);
144
- }
145
-
146
- enc_index = rb_define_dummy_encoding(aliases[0]);
147
- return rb_enc_from_index(enc_index);
148
- }
149
-
150
122
  /*
151
123
  * Return the given PostgreSQL encoding ID as an rb_encoding.
152
124
  *
@@ -156,21 +128,8 @@ pg_find_or_create_johab(void)
156
128
  rb_encoding *
157
129
  pg_get_pg_encoding_as_rb_encoding( int enc_id )
158
130
  {
159
- rb_encoding *enc;
160
-
161
- /* Use the cached value if it exists */
162
- if ( st_lookup(enc_pg2ruby, (st_data_t)enc_id, (st_data_t*)&enc) ) {
163
- return enc;
164
- }
165
- else {
166
- const char *name = pg_encoding_to_char( enc_id );
167
-
168
- enc = pg_get_pg_encname_as_rb_encoding( name );
169
- st_insert( enc_pg2ruby, (st_data_t)enc_id, (st_data_t)enc );
170
-
171
- return enc;
172
- }
173
-
131
+ const char *name = pg_encoding_to_char( enc_id );
132
+ return pg_get_pg_encname_as_rb_encoding( name );
174
133
  }
175
134
 
176
135
  /*
@@ -187,10 +146,6 @@ pg_get_pg_encname_as_rb_encoding( const char *pg_encname )
187
146
  return rb_enc_find( pg_enc_pg2ruby_mapping[i][1] );
188
147
  }
189
148
 
190
- /* JOHAB isn't a builtin encoding, so make up a dummy encoding if it's seen */
191
- if ( strncmp(pg_encname, "JOHAB", 5) == 0 )
192
- return pg_find_or_create_johab();
193
-
194
149
  /* Fallthrough to ASCII-8BIT */
195
150
  return rb_ascii8bit_encoding();
196
151
  }
@@ -377,8 +332,13 @@ pg_s_init_ssl(VALUE self, VALUE do_ssl)
377
332
  **************************************************************************/
378
333
 
379
334
  void
380
- Init_pg_ext()
335
+ Init_pg_ext(void)
381
336
  {
337
+
338
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
339
+ rb_ext_ractor_safe(PQisthreadsafe());
340
+ #endif
341
+
382
342
  if( RTEST(rb_eval_string("ENV['PG_SKIP_DEPRECATION_WARNING']")) ){
383
343
  /* Set all bits to disable all deprecation warnings. */
384
344
  pg_skip_deprecation_warning = 0xFFFF;
@@ -397,8 +357,8 @@ Init_pg_ext()
397
357
  SINGLETON_ALIAS( rb_mPG, "is_threadsafe?", "isthreadsafe" );
398
358
  SINGLETON_ALIAS( rb_mPG, "threadsafe?", "isthreadsafe" );
399
359
 
400
- rb_define_singleton_method( rb_mPG, "init_openssl", pg_s_init_openssl, 2 );
401
- rb_define_singleton_method( rb_mPG, "init_ssl", pg_s_init_ssl, 1 );
360
+ rb_define_singleton_method( rb_mPG, "init_openssl", pg_s_init_openssl, 2 );
361
+ rb_define_singleton_method( rb_mPG, "init_ssl", pg_s_init_ssl, 1 );
402
362
 
403
363
 
404
364
  /****** PG::Connection CLASS CONSTANTS: Connection Status ******/
@@ -704,11 +664,12 @@ Init_pg_ext()
704
664
  rb_define_const(rb_mPGconstants, "INVALID_OID", INT2FIX(InvalidOid));
705
665
  rb_define_const(rb_mPGconstants, "InvalidOid", INT2FIX(InvalidOid));
706
666
 
667
+ /* PostgreSQL compiled in default port */
668
+ rb_define_const(rb_mPGconstants, "DEF_PGPORT", INT2FIX(DEF_PGPORT));
669
+
707
670
  /* Add the constants to the toplevel namespace */
708
671
  rb_include_module( rb_mPG, rb_mPGconstants );
709
672
 
710
- enc_pg2ruby = st_init_numtable();
711
-
712
673
  /* Initialize the main extension classes */
713
674
  init_pg_connection();
714
675
  init_pg_result();
@@ -729,4 +690,3 @@ Init_pg_ext()
729
690
  init_pg_recordcoder();
730
691
  init_pg_tuple();
731
692
  }
732
-
data/ext/pg.h CHANGED
@@ -57,6 +57,7 @@
57
57
  #endif
58
58
 
59
59
  /* PostgreSQL headers */
60
+ #include "pg_config.h"
60
61
  #include "libpq-fe.h"
61
62
  #include "libpq/libpq-fs.h" /* large-object interface */
62
63
  #include "pg_config_manual.h"
@@ -75,10 +76,6 @@ typedef long suseconds_t;
75
76
  #define PG_MAX_COLUMNS 4000
76
77
  #endif
77
78
 
78
- #ifndef RARRAY_AREF
79
- #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
80
- #endif
81
-
82
79
  #ifdef HAVE_RB_GC_MARK_MOVABLE
83
80
  #define pg_compact_callback(x) (x)
84
81
  #define pg_gc_location(x) x = rb_gc_location(x)
@@ -88,6 +85,12 @@ typedef long suseconds_t;
88
85
  #define pg_gc_location(x) UNUSED(x)
89
86
  #endif
90
87
 
88
+ /* For compatibility with ruby < 3.0 */
89
+ #ifndef RUBY_TYPED_FROZEN_SHAREABLE
90
+ #define PG_RUBY_TYPED_FROZEN_SHAREABLE 0
91
+ #else
92
+ #define PG_RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
93
+ #endif
91
94
  #define PG_ENC_IDX_BITS 28
92
95
 
93
96
  /* The data behind each PG::Connection object */
@@ -96,6 +99,9 @@ typedef struct {
96
99
 
97
100
  /* Cached IO object for the socket descriptor */
98
101
  VALUE socket_io;
102
+ /* function pointers of the original libpq notice receivers */
103
+ PQnoticeReceiver default_notice_receiver;
104
+ PQnoticeProcessor default_notice_processor;
99
105
  /* Proc object that receives notices as PG::Result objects */
100
106
  VALUE notice_receiver;
101
107
  /* Proc object that receives notices as String objects */
@@ -313,7 +319,7 @@ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, c
313
319
  int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
314
320
  t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
315
321
  t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
316
- void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
322
+ VALUE pg_define_coder _(( const char *, void *, VALUE, VALUE ));
317
323
  VALUE pg_obj_to_i _(( VALUE ));
318
324
  VALUE pg_tmbc_allocate _(( void ));
319
325
  void pg_coder_init_encoder _(( VALUE ));
@@ -344,6 +350,7 @@ void pg_typemap_compact _(( void * ));
344
350
 
345
351
  PGconn *pg_get_pgconn _(( VALUE ));
346
352
  t_pg_connection *pg_get_connection _(( VALUE ));
353
+ VALUE pgconn_block _(( int, VALUE *, VALUE ));
347
354
 
348
355
  VALUE pg_new_result _(( PGresult *, VALUE ));
349
356
  VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
@@ -12,6 +12,8 @@
12
12
  #endif
13
13
 
14
14
  VALUE rb_mPG_BinaryDecoder;
15
+ static VALUE s_Date;
16
+ static ID s_id_new;
15
17
 
16
18
 
17
19
  /*
@@ -195,6 +197,82 @@ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int
195
197
  }
196
198
  }
197
199
 
200
+ #define PG_INT32_MIN (-0x7FFFFFFF-1)
201
+ #define PG_INT32_MAX (0x7FFFFFFF)
202
+ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
203
+ #define MONTHS_PER_YEAR 12
204
+
205
+ /* taken from PostgreSQL sources at src/backend/utils/adt/datetime.c */
206
+ void
207
+ j2date(int jd, int *year, int *month, int *day)
208
+ {
209
+ unsigned int julian;
210
+ unsigned int quad;
211
+ unsigned int extra;
212
+ int y;
213
+
214
+ julian = jd;
215
+ julian += 32044;
216
+ quad = julian / 146097;
217
+ extra = (julian - quad * 146097) * 4 + 3;
218
+ julian += 60 + quad * 3 + extra / 146097;
219
+ quad = julian / 1461;
220
+ julian -= quad * 1461;
221
+ y = julian * 4 / 1461;
222
+ julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
223
+ + 123;
224
+ y += quad * 4;
225
+ *year = y - 4800;
226
+ quad = julian * 2141 / 65536;
227
+ *day = julian - 7834 * quad / 256;
228
+ *month = (quad + 10) % MONTHS_PER_YEAR + 1;
229
+ } /* j2date() */
230
+
231
+ /*
232
+ * Document-class: PG::BinaryDecoder::Date < PG::SimpleDecoder
233
+ *
234
+ * This is a decoder class for conversion of PostgreSQL binary date
235
+ * to Ruby Date objects.
236
+ */
237
+ static VALUE
238
+ pg_bin_dec_date(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
239
+ {
240
+ int year, month, day;
241
+ int date;
242
+
243
+ if (len != 4) {
244
+ rb_raise(rb_eTypeError, "unexpected date format != 4 bytes");
245
+ }
246
+
247
+ date = read_nbo32(val);
248
+ switch(date){
249
+ case PG_INT32_MAX:
250
+ return rb_str_new2("infinity");
251
+ case PG_INT32_MIN:
252
+ return rb_str_new2("-infinity");
253
+ default:
254
+ j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
255
+
256
+ return rb_funcall(s_Date, s_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
257
+ }
258
+ }
259
+
260
+ /* called per autoload when BinaryDecoder::Date is used */
261
+ static VALUE
262
+ init_pg_bin_decoder_date(VALUE rb_mPG_BinaryDecoder)
263
+ {
264
+ rb_require("date");
265
+ s_Date = rb_const_get(rb_cObject, rb_intern("Date"));
266
+ rb_gc_register_mark_object(s_Date);
267
+ s_id_new = rb_intern("new");
268
+
269
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Date", rb_cPG_SimpleDecoder ); */
270
+ pg_define_coder( "Date", pg_bin_dec_date, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
271
+
272
+ return Qnil;
273
+ }
274
+
275
+
198
276
  /*
199
277
  * Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
200
278
  *
@@ -205,10 +283,11 @@ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int
205
283
  */
206
284
 
207
285
  void
208
- init_pg_binary_decoder()
286
+ init_pg_binary_decoder(void)
209
287
  {
210
288
  /* This module encapsulates all decoder classes with binary input format */
211
289
  rb_mPG_BinaryDecoder = rb_define_module_under( rb_mPG, "BinaryDecoder" );
290
+ rb_define_private_method(rb_singleton_class(rb_mPG_BinaryDecoder), "init_date", init_pg_bin_decoder_date, 0);
212
291
 
213
292
  /* Make RDoc aware of the decoder classes... */
214
293
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
@@ -11,6 +11,9 @@
11
11
  #endif
12
12
 
13
13
  VALUE rb_mPG_BinaryEncoder;
14
+ static ID s_id_year;
15
+ static ID s_id_month;
16
+ static ID s_id_day;
14
17
 
15
18
 
16
19
  /*
@@ -93,6 +96,215 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
93
96
  return 8;
94
97
  }
95
98
 
99
+ /*
100
+ * Document-class: PG::BinaryEncoder::Float4 < PG::SimpleEncoder
101
+ *
102
+ * This is the binary encoder class for the PostgreSQL +float4+ type.
103
+ *
104
+ */
105
+ static int
106
+ pg_bin_enc_float4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
107
+ {
108
+ union {
109
+ float f;
110
+ int32_t i;
111
+ } swap4;
112
+
113
+ if(out){
114
+ swap4.f = NUM2DBL(*intermediate);
115
+ write_nbo32(swap4.i, out);
116
+ }else{
117
+ *intermediate = value;
118
+ }
119
+ return 4;
120
+ }
121
+
122
+ /*
123
+ * Document-class: PG::BinaryEncoder::Float8 < PG::SimpleEncoder
124
+ *
125
+ * This is the binary encoder class for the PostgreSQL +float8+ type.
126
+ *
127
+ */
128
+ static int
129
+ pg_bin_enc_float8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
130
+ {
131
+ union {
132
+ double f;
133
+ int64_t i;
134
+ } swap8;
135
+
136
+ if(out){
137
+ swap8.f = NUM2DBL(*intermediate);
138
+ write_nbo64(swap8.i, out);
139
+ }else{
140
+ *intermediate = value;
141
+ }
142
+ return 8;
143
+ }
144
+
145
+ #define PG_INT32_MIN (-0x7FFFFFFF-1)
146
+ #define PG_INT32_MAX (0x7FFFFFFF)
147
+ #define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
148
+ #define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
149
+
150
+ /*
151
+ * Document-class: PG::BinaryEncoder::Timestamp < PG::SimpleEncoder
152
+ *
153
+ * This is a encoder class for conversion of Ruby Time objects to PostgreSQL binary timestamps.
154
+ *
155
+ * The following flags can be used to specify timezone interpretation:
156
+ * * +PG::Coder::TIMESTAMP_DB_UTC+ : Send timestamp as UTC time (default)
157
+ * * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Send timestamp as local time (slower)
158
+ *
159
+ * Example:
160
+ * enco = PG::BinaryEncoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC)
161
+ * enco.encode(Time.utc(2000, 1, 1)) # => "\x00\x00\x00\x00\x00\x00\x00\x00"
162
+ *
163
+ * String values are expected to contain a binary data with a length of 8 byte.
164
+ *
165
+ */
166
+ static int
167
+ pg_bin_enc_timestamp(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
168
+ {
169
+ if(out){
170
+ int64_t timestamp;
171
+ struct timespec ts;
172
+
173
+ /* second call -> write data to *out */
174
+ switch(TYPE(*intermediate)){
175
+ case T_STRING:
176
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
177
+ case T_TRUE:
178
+ write_nbo64(PG_INT64_MAX, out);
179
+ return 8;
180
+ case T_FALSE:
181
+ write_nbo64(PG_INT64_MIN, out);
182
+ return 8;
183
+ }
184
+
185
+ ts = rb_time_timespec(*intermediate);
186
+ /* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
187
+ * Adjust the 30 years difference. */
188
+ timestamp = (ts.tv_sec - 10957L * 24L * 3600L) * 1000000 + (ts.tv_nsec / 1000);
189
+
190
+ if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
191
+ /* send as local time */
192
+ timestamp += NUM2LL(rb_funcall(*intermediate, rb_intern("utc_offset"), 0)) * 1000000;
193
+ }
194
+
195
+ write_nbo64(timestamp, out);
196
+ }else{
197
+ /* first call -> determine the required length */
198
+ if(TYPE(value) == T_STRING){
199
+ char *pstr = RSTRING_PTR(value);
200
+ if(RSTRING_LEN(value) >= 1){
201
+ switch(pstr[0]) {
202
+ case 'I':
203
+ case 'i':
204
+ *intermediate = Qtrue;
205
+ return 8;
206
+ case '-':
207
+ if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
208
+ *intermediate = Qfalse;
209
+ return 8;
210
+ }
211
+ }
212
+ }
213
+
214
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
215
+ }
216
+
217
+ if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
218
+ /* make a local time, so that utc_offset is set */
219
+ value = rb_funcall(value, rb_intern("getlocal"), 0);
220
+ }
221
+ *intermediate = value;
222
+ }
223
+ return 8;
224
+ }
225
+
226
+ #define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
227
+ int
228
+ date2j(int year, int month, int day)
229
+ {
230
+ int julian;
231
+ int century;
232
+
233
+ if (month > 2)
234
+ {
235
+ month += 1;
236
+ year += 4800;
237
+ }
238
+ else
239
+ {
240
+ month += 13;
241
+ year += 4799;
242
+ }
243
+
244
+ century = year / 100;
245
+ julian = year * 365 - 32167;
246
+ julian += year / 4 - century + century / 4;
247
+ julian += 7834 * month / 256 + day;
248
+
249
+ return julian;
250
+ } /* date2j() */
251
+
252
+ /*
253
+ * Document-class: PG::BinaryEncoder::Date < PG::SimpleEncoder
254
+ *
255
+ * This is a encoder class for conversion of Ruby Date objects to PostgreSQL binary date.
256
+ *
257
+ * String values are expected to contain a binary data with a length of 4 byte.
258
+ *
259
+ */
260
+ static int
261
+ pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
262
+ {
263
+ if(out){
264
+ /* second call -> write data to *out */
265
+ switch(TYPE(*intermediate)){
266
+ case T_STRING:
267
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
268
+ case T_TRUE:
269
+ write_nbo32(PG_INT32_MAX, out);
270
+ return 4;
271
+ case T_FALSE:
272
+ write_nbo32(PG_INT32_MIN, out);
273
+ return 4;
274
+ }
275
+
276
+ VALUE year = rb_funcall(value, s_id_year, 0);
277
+ VALUE month = rb_funcall(value, s_id_month, 0);
278
+ VALUE day = rb_funcall(value, s_id_day, 0);
279
+ int jday = date2j(NUM2INT(year), NUM2INT(month), NUM2INT(day)) - POSTGRES_EPOCH_JDATE;
280
+ write_nbo32(jday, out);
281
+
282
+ }else{
283
+ /* first call -> determine the required length */
284
+ if(TYPE(value) == T_STRING){
285
+ char *pstr = RSTRING_PTR(value);
286
+ if(RSTRING_LEN(value) >= 1){
287
+ switch(pstr[0]) {
288
+ case 'I':
289
+ case 'i':
290
+ *intermediate = Qtrue;
291
+ return 4;
292
+ case '-':
293
+ if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
294
+ *intermediate = Qfalse;
295
+ return 4;
296
+ }
297
+ }
298
+ }
299
+
300
+ return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
301
+ }
302
+
303
+ *intermediate = value;
304
+ }
305
+ return 4;
306
+ }
307
+
96
308
  /*
97
309
  * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
98
310
  *
@@ -139,8 +351,12 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
139
351
  }
140
352
 
141
353
  void
142
- init_pg_binary_encoder()
354
+ init_pg_binary_encoder(void)
143
355
  {
356
+ s_id_year = rb_intern("year");
357
+ s_id_month = rb_intern("month");
358
+ s_id_day = rb_intern("day");
359
+
144
360
  /* This module encapsulates all encoder classes with binary output format */
145
361
  rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
146
362
 
@@ -153,10 +369,18 @@ init_pg_binary_encoder()
153
369
  pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
154
370
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
155
371
  pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
372
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float4", rb_cPG_SimpleEncoder ); */
373
+ pg_define_coder( "Float4", pg_bin_enc_float4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
374
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float8", rb_cPG_SimpleEncoder ); */
375
+ pg_define_coder( "Float8", pg_bin_enc_float8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
156
376
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
157
377
  pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
158
378
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
159
379
  pg_define_coder( "Bytea", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
380
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Timestamp", rb_cPG_SimpleEncoder ); */
381
+ pg_define_coder( "Timestamp", pg_bin_enc_timestamp, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
382
+ /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Date", rb_cPG_SimpleEncoder ); */
383
+ pg_define_coder( "Date", pg_bin_enc_date, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
160
384
 
161
385
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
162
386
  pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );