pg 1.1.4 → 1.5.3

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 (140) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.appveyor.yml +42 -0
  4. data/.gems +6 -0
  5. data/.github/workflows/binary-gems.yml +117 -0
  6. data/.github/workflows/source-gem.yml +137 -0
  7. data/.gitignore +22 -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/Gemfile +14 -0
  15. data/History.md +876 -0
  16. data/Manifest.txt +3 -3
  17. data/README-Windows.rdoc +4 -4
  18. data/README.ja.md +276 -0
  19. data/README.md +286 -0
  20. data/Rakefile +37 -137
  21. data/Rakefile.cross +62 -62
  22. data/certs/ged.pem +24 -0
  23. data/certs/larskanis-2022.pem +26 -0
  24. data/certs/larskanis-2023.pem +24 -0
  25. data/ext/errorcodes.def +76 -0
  26. data/ext/errorcodes.rb +0 -0
  27. data/ext/errorcodes.txt +21 -2
  28. data/ext/extconf.rb +101 -26
  29. data/ext/gvl_wrappers.c +4 -0
  30. data/ext/gvl_wrappers.h +23 -0
  31. data/ext/pg.c +203 -151
  32. data/ext/pg.h +48 -21
  33. data/ext/pg_binary_decoder.c +89 -10
  34. data/ext/pg_binary_encoder.c +238 -13
  35. data/ext/pg_coder.c +109 -34
  36. data/ext/pg_connection.c +1365 -976
  37. data/ext/pg_copy_coder.c +356 -35
  38. data/ext/pg_errors.c +1 -1
  39. data/ext/pg_record_coder.c +522 -0
  40. data/ext/pg_result.c +436 -171
  41. data/ext/pg_text_decoder.c +42 -18
  42. data/ext/pg_text_encoder.c +201 -56
  43. data/ext/pg_tuple.c +97 -66
  44. data/ext/pg_type_map.c +45 -11
  45. data/ext/pg_type_map_all_strings.c +21 -7
  46. data/ext/pg_type_map_by_class.c +59 -27
  47. data/ext/pg_type_map_by_column.c +80 -37
  48. data/ext/pg_type_map_by_mri_type.c +49 -20
  49. data/ext/pg_type_map_by_oid.c +62 -29
  50. data/ext/pg_type_map_in_ruby.c +56 -22
  51. data/ext/{util.c → pg_util.c} +7 -7
  52. data/lib/pg/basic_type_map_based_on_result.rb +67 -0
  53. data/lib/pg/basic_type_map_for_queries.rb +198 -0
  54. data/lib/pg/basic_type_map_for_results.rb +104 -0
  55. data/lib/pg/basic_type_registry.rb +299 -0
  56. data/lib/pg/binary_decoder/date.rb +9 -0
  57. data/lib/pg/binary_decoder/timestamp.rb +26 -0
  58. data/lib/pg/binary_encoder/timestamp.rb +20 -0
  59. data/lib/pg/coder.rb +35 -12
  60. data/lib/pg/connection.rb +744 -84
  61. data/lib/pg/exceptions.rb +15 -1
  62. data/lib/pg/result.rb +13 -1
  63. data/lib/pg/text_decoder/date.rb +18 -0
  64. data/lib/pg/text_decoder/inet.rb +9 -0
  65. data/lib/pg/text_decoder/json.rb +14 -0
  66. data/lib/pg/text_decoder/numeric.rb +9 -0
  67. data/lib/pg/text_decoder/timestamp.rb +30 -0
  68. data/lib/pg/text_encoder/date.rb +12 -0
  69. data/lib/pg/text_encoder/inet.rb +28 -0
  70. data/lib/pg/text_encoder/json.rb +14 -0
  71. data/lib/pg/text_encoder/numeric.rb +9 -0
  72. data/lib/pg/text_encoder/timestamp.rb +24 -0
  73. data/lib/pg/type_map_by_column.rb +2 -1
  74. data/lib/pg/version.rb +4 -0
  75. data/lib/pg.rb +94 -39
  76. data/misc/openssl-pg-segfault.rb +31 -0
  77. data/misc/postgres/History.txt +9 -0
  78. data/misc/postgres/Manifest.txt +5 -0
  79. data/misc/postgres/README.txt +21 -0
  80. data/misc/postgres/Rakefile +21 -0
  81. data/misc/postgres/lib/postgres.rb +16 -0
  82. data/misc/ruby-pg/History.txt +9 -0
  83. data/misc/ruby-pg/Manifest.txt +5 -0
  84. data/misc/ruby-pg/README.txt +21 -0
  85. data/misc/ruby-pg/Rakefile +21 -0
  86. data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
  87. data/pg.gemspec +34 -0
  88. data/rakelib/task_extension.rb +46 -0
  89. data/sample/array_insert.rb +20 -0
  90. data/sample/async_api.rb +102 -0
  91. data/sample/async_copyto.rb +39 -0
  92. data/sample/async_mixed.rb +56 -0
  93. data/sample/check_conn.rb +21 -0
  94. data/sample/copydata.rb +71 -0
  95. data/sample/copyfrom.rb +81 -0
  96. data/sample/copyto.rb +19 -0
  97. data/sample/cursor.rb +21 -0
  98. data/sample/disk_usage_report.rb +177 -0
  99. data/sample/issue-119.rb +94 -0
  100. data/sample/losample.rb +69 -0
  101. data/sample/minimal-testcase.rb +17 -0
  102. data/sample/notify_wait.rb +72 -0
  103. data/sample/pg_statistics.rb +285 -0
  104. data/sample/replication_monitor.rb +222 -0
  105. data/sample/test_binary_values.rb +33 -0
  106. data/sample/wal_shipper.rb +434 -0
  107. data/sample/warehouse_partitions.rb +311 -0
  108. data/translation/.po4a-version +7 -0
  109. data/translation/po/all.pot +910 -0
  110. data/translation/po/ja.po +1047 -0
  111. data/translation/po4a.cfg +12 -0
  112. data.tar.gz.sig +0 -0
  113. metadata +151 -218
  114. metadata.gz.sig +0 -0
  115. data/ChangeLog +0 -6595
  116. data/History.rdoc +0 -492
  117. data/README.ja.rdoc +0 -14
  118. data/README.rdoc +0 -178
  119. data/lib/pg/basic_type_mapping.rb +0 -459
  120. data/lib/pg/binary_decoder.rb +0 -22
  121. data/lib/pg/constants.rb +0 -11
  122. data/lib/pg/text_decoder.rb +0 -47
  123. data/lib/pg/text_encoder.rb +0 -69
  124. data/spec/data/expected_trace.out +0 -26
  125. data/spec/data/random_binary_data +0 -0
  126. data/spec/helpers.rb +0 -380
  127. data/spec/pg/basic_type_mapping_spec.rb +0 -508
  128. data/spec/pg/connection_spec.rb +0 -1872
  129. data/spec/pg/connection_sync_spec.rb +0 -41
  130. data/spec/pg/result_spec.rb +0 -491
  131. data/spec/pg/tuple_spec.rb +0 -280
  132. data/spec/pg/type_map_by_class_spec.rb +0 -138
  133. data/spec/pg/type_map_by_column_spec.rb +0 -222
  134. data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
  135. data/spec/pg/type_map_by_oid_spec.rb +0 -149
  136. data/spec/pg/type_map_in_ruby_spec.rb +0 -164
  137. data/spec/pg/type_map_spec.rb +0 -22
  138. data/spec/pg/type_spec.rb +0 -949
  139. data/spec/pg_spec.rb +0 -50
  140. /data/ext/{util.h → pg_util.h} +0 -0
data/ext/pg.h CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <sys/types.h>
12
12
  #if !defined(_WIN32)
13
13
  # include <sys/time.h>
14
+ # include <sys/socket.h>
14
15
  #endif
15
16
  #if defined(HAVE_UNISTD_H) && !defined(_WIN32)
16
17
  # include <unistd.h>
@@ -56,6 +57,7 @@
56
57
  #endif
57
58
 
58
59
  /* PostgreSQL headers */
60
+ #include "pg_config.h"
59
61
  #include "libpq-fe.h"
60
62
  #include "libpq/libpq-fs.h" /* large-object interface */
61
63
  #include "pg_config_manual.h"
@@ -74,9 +76,22 @@ typedef long suseconds_t;
74
76
  #define PG_MAX_COLUMNS 4000
75
77
  #endif
76
78
 
77
- #ifndef RARRAY_AREF
78
- #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
79
+ #ifdef HAVE_RB_GC_MARK_MOVABLE
80
+ #define pg_compact_callback(x) (x)
81
+ #define pg_gc_location(x) x = rb_gc_location(x)
82
+ #else
83
+ #define rb_gc_mark_movable(x) rb_gc_mark(x)
84
+ #define pg_compact_callback(x) {(x)}
85
+ #define pg_gc_location(x) UNUSED(x)
86
+ #endif
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
79
93
  #endif
94
+ #define PG_ENC_IDX_BITS 28
80
95
 
81
96
  /* The data behind each PG::Connection object */
82
97
  typedef struct {
@@ -84,6 +99,9 @@ typedef struct {
84
99
 
85
100
  /* Cached IO object for the socket descriptor */
86
101
  VALUE socket_io;
102
+ /* function pointers of the original libpq notice receivers */
103
+ PQnoticeReceiver default_notice_receiver;
104
+ PQnoticeProcessor default_notice_processor;
87
105
  /* Proc object that receives notices as PG::Result objects */
88
106
  VALUE notice_receiver;
89
107
  /* Proc object that receives notices as String objects */
@@ -94,15 +112,16 @@ typedef struct {
94
112
  VALUE type_map_for_results;
95
113
  /* IO object internally used for the trace stream */
96
114
  VALUE trace_stream;
97
- /* Cached Encoding object */
98
- VALUE external_encoding;
99
115
  /* Kind of PG::Coder object for casting ruby values to COPY rows */
100
116
  VALUE encoder_for_put_copy_data;
101
117
  /* Kind of PG::Coder object for casting COPY rows to ruby values */
102
118
  VALUE decoder_for_get_copy_data;
103
-
104
- /* enable/disable guessing size of PGresult's allocated memory */
105
- int guess_result_memsize;
119
+ /* Ruby encoding index of the client/internal encoding */
120
+ int enc_idx : PG_ENC_IDX_BITS;
121
+ /* flags controlling Symbol/String field names */
122
+ unsigned int flags : 2;
123
+ /* enable automatic flushing of send data at the end of send_query calls */
124
+ unsigned int flush_data : 1;
106
125
 
107
126
  #if defined(_WIN32)
108
127
  /* File descriptor to be used for rb_w32_unwrap_io_handle() */
@@ -128,10 +147,16 @@ typedef struct {
128
147
  */
129
148
  t_typemap *p_typemap;
130
149
 
150
+ /* Ruby encoding index of the client/internal encoding */
151
+ int enc_idx : PG_ENC_IDX_BITS;
152
+
131
153
  /* 0 = PGresult is cleared by PG::Result#clear or by the GC
132
154
  * 1 = PGresult is cleared internally by libpq
133
155
  */
134
- int autoclear;
156
+ unsigned int autoclear : 1;
157
+
158
+ /* flags controlling Symbol/String field names */
159
+ unsigned int flags : 2;
135
160
 
136
161
  /* Number of fields in fnames[] .
137
162
  * Set to -1 if fnames[] is not yet initialized.
@@ -147,7 +172,7 @@ typedef struct {
147
172
  /* Hash with fnames[] to field number mapping. */
148
173
  VALUE field_map;
149
174
 
150
- /* List of field names as frozen String objects.
175
+ /* List of field names as frozen String or Symbol objects.
151
176
  * Only valid if nfields != -1
152
177
  */
153
178
  VALUE fnames[0];
@@ -163,6 +188,10 @@ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
163
188
  typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
164
189
  typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
165
190
 
191
+ #define PG_RESULT_FIELD_NAMES_MASK 0x03
192
+ #define PG_RESULT_FIELD_NAMES_SYMBOL 0x01
193
+ #define PG_RESULT_FIELD_NAMES_STATIC_SYMBOL 0x02
194
+
166
195
  #define PG_CODER_TIMESTAMP_DB_UTC 0x0
167
196
  #define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
168
197
  #define PG_CODER_TIMESTAMP_APP_UTC 0x0
@@ -209,6 +238,8 @@ typedef struct {
209
238
  } convs[0];
210
239
  } t_tmbc;
211
240
 
241
+ extern const rb_data_type_t pg_typemap_type;
242
+ extern const rb_data_type_t pg_coder_type;
212
243
 
213
244
  #include "gvl_wrappers.h"
214
245
 
@@ -275,6 +306,7 @@ void init_pg_type_map_by_oid _(( void ));
275
306
  void init_pg_type_map_in_ruby _(( void ));
276
307
  void init_pg_coder _(( void ));
277
308
  void init_pg_copycoder _(( void ));
309
+ void init_pg_recordcoder _(( void ));
278
310
  void init_pg_text_encoder _(( void ));
279
311
  void init_pg_text_decoder _(( void ));
280
312
  void init_pg_binary_encoder _(( void ));
@@ -287,11 +319,12 @@ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, c
287
319
  int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
288
320
  t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
289
321
  t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
290
- void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
322
+ VALUE pg_define_coder _(( const char *, void *, VALUE, VALUE ));
291
323
  VALUE pg_obj_to_i _(( VALUE ));
292
324
  VALUE pg_tmbc_allocate _(( void ));
293
325
  void pg_coder_init_encoder _(( VALUE ));
294
326
  void pg_coder_init_decoder _(( VALUE ));
327
+ void pg_coder_compact _(( void * ));
295
328
  char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
296
329
 
297
330
  #define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
@@ -305,20 +338,19 @@ char *pg_rb_str_ensure_capa _(( VALUE, long, char *,
305
338
  (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
306
339
  )
307
340
 
308
- #define PG_RB_TAINTED_STR_NEW( str, curr_ptr, end_ptr ) ( \
309
- (str) = rb_tainted_str_new( NULL, 0 ), \
310
- (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
311
- )
312
-
313
341
  VALUE pg_typemap_fit_to_result _(( VALUE, VALUE ));
314
342
  VALUE pg_typemap_fit_to_query _(( VALUE, VALUE ));
315
343
  int pg_typemap_fit_to_copy_get _(( VALUE ));
316
344
  VALUE pg_typemap_result_value _(( t_typemap *, VALUE, int, int ));
317
345
  t_pg_coder *pg_typemap_typecast_query_param _(( t_typemap *, VALUE, int ));
318
346
  VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int ));
347
+ void pg_typemap_mark _(( void * ));
348
+ size_t pg_typemap_memsize _(( const void * ));
349
+ void pg_typemap_compact _(( void * ));
319
350
 
320
351
  PGconn *pg_get_pgconn _(( VALUE ));
321
352
  t_pg_connection *pg_get_connection _(( VALUE ));
353
+ VALUE pgconn_block _(( int, VALUE *, VALUE ));
322
354
 
323
355
  VALUE pg_new_result _(( PGresult *, VALUE ));
324
356
  VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
@@ -333,12 +365,7 @@ VALUE pg_tuple_new _(( VALUE, int ));
333
365
  static inline t_pg_result *
334
366
  pgresult_get_this( VALUE self )
335
367
  {
336
- t_pg_result *this = RTYPEDDATA_DATA(self);
337
-
338
- if( this == NULL )
339
- rb_raise(rb_ePGerror, "result has been cleared");
340
-
341
- return this;
368
+ return RTYPEDDATA_DATA(self);
342
369
  }
343
370
 
344
371
 
@@ -6,19 +6,21 @@
6
6
 
7
7
  #include "ruby/version.h"
8
8
  #include "pg.h"
9
- #include "util.h"
9
+ #include "pg_util.h"
10
10
  #ifdef HAVE_INTTYPES_H
11
11
  #include <inttypes.h>
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
  /*
18
20
  * Document-class: PG::BinaryDecoder::Boolean < PG::SimpleDecoder
19
21
  *
20
- * This is a decoder class for conversion of PostgreSQL binary bool type
21
- * to Ruby true or false objects.
22
+ * This is a decoder class for conversion of PostgreSQL binary +bool+ type
23
+ * to Ruby +true+ or +false+ objects.
22
24
  *
23
25
  */
24
26
  static VALUE
@@ -33,7 +35,7 @@ pg_bin_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int fi
33
35
  /*
34
36
  * Document-class: PG::BinaryDecoder::Integer < PG::SimpleDecoder
35
37
  *
36
- * This is a decoder class for conversion of PostgreSQL binary int2, int4 and int8 types
38
+ * This is a decoder class for conversion of PostgreSQL binary +int2+, +int4+ and +int8+ types
37
39
  * to Ruby Integer objects.
38
40
  *
39
41
  */
@@ -55,7 +57,7 @@ pg_bin_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int fi
55
57
  /*
56
58
  * Document-class: PG::BinaryDecoder::Float < PG::SimpleDecoder
57
59
  *
58
- * This is a decoder class for conversion of PostgreSQL binary float4 and float8 types
60
+ * This is a decoder class for conversion of PostgreSQL binary +float4+ and +float8+ types
59
61
  * to Ruby Float objects.
60
62
  *
61
63
  */
@@ -87,7 +89,7 @@ pg_bin_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
87
89
  * Document-class: PG::BinaryDecoder::Bytea < PG::SimpleDecoder
88
90
  *
89
91
  * This decoder class delivers the data received from the server as binary String object.
90
- * It is therefore suitable for conversion of PostgreSQL bytea data as well as any other
92
+ * It is therefore suitable for conversion of PostgreSQL +bytea+ data as well as any other
91
93
  * data in binary format.
92
94
  *
93
95
  */
@@ -95,7 +97,7 @@ VALUE
95
97
  pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
96
98
  {
97
99
  VALUE ret;
98
- ret = rb_tainted_str_new( val, len );
100
+ ret = rb_str_new( val, len );
99
101
  PG_ENCODING_SET_NOCHECK( ret, rb_ascii8bit_encindex() );
100
102
  return ret;
101
103
  }
@@ -103,7 +105,7 @@ pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
103
105
  /*
104
106
  * Document-class: PG::BinaryDecoder::ToBase64 < PG::CompositeDecoder
105
107
  *
106
- * This is a decoder class for conversion of binary (bytea) to base64 data.
108
+ * This is a decoder class for conversion of binary +bytea+ to base64 data.
107
109
  *
108
110
  */
109
111
  static VALUE
@@ -113,7 +115,7 @@ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int
113
115
  t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
114
116
  int encoded_len = BASE64_ENCODED_SIZE(len);
115
117
  /* create a buffer of the encoded length */
116
- VALUE out_value = rb_tainted_str_new(NULL, encoded_len);
118
+ VALUE out_value = rb_str_new(NULL, encoded_len);
117
119
 
118
120
  base64_encode( RSTRING_PTR(out_value), val, len );
119
121
 
@@ -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 ); */
@@ -1,16 +1,19 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_binary_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
7
  #include "pg.h"
8
- #include "util.h"
8
+ #include "pg_util.h"
9
9
  #ifdef HAVE_INTTYPES_H
10
10
  #include <inttypes.h>
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
  /*
@@ -25,11 +28,12 @@ static int
25
28
  pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
26
29
  {
27
30
  char mybool;
28
- switch(value){
29
- case Qtrue : mybool = 1; break;
30
- case Qfalse : mybool = 0; break;
31
- default :
32
- rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
31
+ if (value == Qtrue) {
32
+ mybool = 1;
33
+ } else if (value == Qfalse) {
34
+ mybool = 0;
35
+ } else {
36
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
33
37
  }
34
38
  if(out) *out = mybool;
35
39
  return 1;
@@ -38,7 +42,7 @@ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
38
42
  /*
39
43
  * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
40
44
  *
41
- * This is the encoder class for the PostgreSQL int2 type.
45
+ * This is the encoder class for the PostgreSQL +int2+ (alias +smallint+) type.
42
46
  *
43
47
  * Non-Number values are expected to have method +to_i+ defined.
44
48
  *
@@ -55,9 +59,9 @@ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
55
59
  }
56
60
 
57
61
  /*
58
- * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
62
+ * Document-class: PG::BinaryEncoder::Int4 < PG::SimpleEncoder
59
63
  *
60
- * This is the encoder class for the PostgreSQL int4 type.
64
+ * This is the encoder class for the PostgreSQL +int4+ (alias +integer+) type.
61
65
  *
62
66
  * Non-Number values are expected to have method +to_i+ defined.
63
67
  *
@@ -74,9 +78,9 @@ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
74
78
  }
75
79
 
76
80
  /*
77
- * Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
81
+ * Document-class: PG::BinaryEncoder::Int8 < PG::SimpleEncoder
78
82
  *
79
- * This is the encoder class for the PostgreSQL int8 type.
83
+ * This is the encoder class for the PostgreSQL +int8+ (alias +bigint+) type.
80
84
  *
81
85
  * Non-Number values are expected to have method +to_i+ defined.
82
86
  *
@@ -92,6 +96,215 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
92
96
  return 8;
93
97
  }
94
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
+
95
308
  /*
96
309
  * Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
97
310
  *
@@ -138,8 +351,12 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
138
351
  }
139
352
 
140
353
  void
141
- init_pg_binary_encoder()
354
+ init_pg_binary_encoder(void)
142
355
  {
356
+ s_id_year = rb_intern("year");
357
+ s_id_month = rb_intern("month");
358
+ s_id_day = rb_intern("day");
359
+
143
360
  /* This module encapsulates all encoder classes with binary output format */
144
361
  rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
145
362
 
@@ -152,10 +369,18 @@ init_pg_binary_encoder()
152
369
  pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
153
370
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
154
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 );
155
376
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
156
377
  pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
157
378
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
158
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 );
159
384
 
160
385
  /* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
161
386
  pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );