pg 0.17.1 → 1.2.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 (86) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/BSDL +2 -2
  4. data/ChangeLog +0 -3506
  5. data/History.rdoc +308 -0
  6. data/Manifest.txt +35 -19
  7. data/README-Windows.rdoc +17 -28
  8. data/README.ja.rdoc +1 -2
  9. data/README.rdoc +113 -14
  10. data/Rakefile +67 -30
  11. data/Rakefile.cross +109 -83
  12. data/ext/errorcodes.def +101 -0
  13. data/ext/errorcodes.rb +1 -1
  14. data/ext/errorcodes.txt +33 -2
  15. data/ext/extconf.rb +55 -58
  16. data/ext/gvl_wrappers.c +4 -0
  17. data/ext/gvl_wrappers.h +27 -39
  18. data/ext/pg.c +262 -130
  19. data/ext/pg.h +266 -54
  20. data/ext/pg_binary_decoder.c +229 -0
  21. data/ext/pg_binary_encoder.c +163 -0
  22. data/ext/pg_coder.c +561 -0
  23. data/ext/pg_connection.c +1689 -990
  24. data/ext/pg_copy_coder.c +599 -0
  25. data/ext/pg_errors.c +6 -0
  26. data/ext/pg_record_coder.c +491 -0
  27. data/ext/pg_result.c +897 -164
  28. data/ext/pg_text_decoder.c +987 -0
  29. data/ext/pg_text_encoder.c +814 -0
  30. data/ext/pg_tuple.c +549 -0
  31. data/ext/pg_type_map.c +166 -0
  32. data/ext/pg_type_map_all_strings.c +116 -0
  33. data/ext/pg_type_map_by_class.c +244 -0
  34. data/ext/pg_type_map_by_column.c +313 -0
  35. data/ext/pg_type_map_by_mri_type.c +284 -0
  36. data/ext/pg_type_map_by_oid.c +356 -0
  37. data/ext/pg_type_map_in_ruby.c +299 -0
  38. data/ext/pg_util.c +149 -0
  39. data/ext/pg_util.h +65 -0
  40. data/lib/pg/basic_type_mapping.rb +522 -0
  41. data/lib/pg/binary_decoder.rb +23 -0
  42. data/lib/pg/coder.rb +104 -0
  43. data/lib/pg/connection.rb +153 -41
  44. data/lib/pg/constants.rb +2 -1
  45. data/lib/pg/exceptions.rb +2 -1
  46. data/lib/pg/result.rb +33 -6
  47. data/lib/pg/text_decoder.rb +46 -0
  48. data/lib/pg/text_encoder.rb +59 -0
  49. data/lib/pg/tuple.rb +30 -0
  50. data/lib/pg/type_map_by_column.rb +16 -0
  51. data/lib/pg.rb +29 -9
  52. data/spec/{lib/helpers.rb → helpers.rb} +151 -64
  53. data/spec/pg/basic_type_mapping_spec.rb +630 -0
  54. data/spec/pg/connection_spec.rb +1180 -477
  55. data/spec/pg/connection_sync_spec.rb +41 -0
  56. data/spec/pg/result_spec.rb +456 -120
  57. data/spec/pg/tuple_spec.rb +333 -0
  58. data/spec/pg/type_map_by_class_spec.rb +138 -0
  59. data/spec/pg/type_map_by_column_spec.rb +226 -0
  60. data/spec/pg/type_map_by_mri_type_spec.rb +136 -0
  61. data/spec/pg/type_map_by_oid_spec.rb +149 -0
  62. data/spec/pg/type_map_in_ruby_spec.rb +164 -0
  63. data/spec/pg/type_map_spec.rb +22 -0
  64. data/spec/pg/type_spec.rb +1123 -0
  65. data/spec/pg_spec.rb +26 -20
  66. data.tar.gz.sig +0 -0
  67. metadata +148 -91
  68. metadata.gz.sig +0 -0
  69. data/sample/array_insert.rb +0 -20
  70. data/sample/async_api.rb +0 -106
  71. data/sample/async_copyto.rb +0 -39
  72. data/sample/async_mixed.rb +0 -56
  73. data/sample/check_conn.rb +0 -21
  74. data/sample/copyfrom.rb +0 -81
  75. data/sample/copyto.rb +0 -19
  76. data/sample/cursor.rb +0 -21
  77. data/sample/disk_usage_report.rb +0 -186
  78. data/sample/issue-119.rb +0 -94
  79. data/sample/losample.rb +0 -69
  80. data/sample/minimal-testcase.rb +0 -17
  81. data/sample/notify_wait.rb +0 -72
  82. data/sample/pg_statistics.rb +0 -294
  83. data/sample/replication_monitor.rb +0 -231
  84. data/sample/test_binary_values.rb +0 -33
  85. data/sample/wal_shipper.rb +0 -434
  86. data/sample/warehouse_partitions.rb +0 -320
data/ext/pg.h CHANGED
@@ -9,62 +9,27 @@
9
9
  #include <stdio.h>
10
10
  #include <stdlib.h>
11
11
  #include <sys/types.h>
12
+ #if !defined(_WIN32)
13
+ # include <sys/time.h>
14
+ #endif
12
15
  #if defined(HAVE_UNISTD_H) && !defined(_WIN32)
13
16
  # include <unistd.h>
14
17
  #endif /* HAVE_UNISTD_H */
15
18
 
16
19
  /* Ruby headers */
17
20
  #include "ruby.h"
18
- #ifdef HAVE_RUBY_ST_H
19
- # include "ruby/st.h"
20
- #elif HAVE_ST_H
21
- # include "st.h"
22
- #endif
23
-
24
- #if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
25
- # include "ruby/encoding.h"
26
- # define M17N_SUPPORTED
27
- # define ASSOCIATE_INDEX( obj, index_holder ) rb_enc_associate_index((obj), pg_enc_get_index((index_holder)))
28
- # ifdef HAVE_RB_ENCDB_ALIAS
29
- extern int rb_encdb_alias(const char *, const char *);
30
- # define ENC_ALIAS(name, orig) rb_encdb_alias((name), (orig))
31
- # elif HAVE_RB_ENC_ALIAS
32
- extern int rb_enc_alias(const char *, const char *);
33
- # define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
34
- # else
35
- extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
36
- # define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
37
- # endif
38
- #else
39
- # define ASSOCIATE_INDEX( obj, index_holder ) /* nothing */
40
- #endif
41
-
42
- #if RUBY_VM != 1
43
- # define RUBY_18_COMPAT
44
- #endif
21
+ #include "ruby/st.h"
22
+ #include "ruby/encoding.h"
45
23
 
46
- #ifndef RARRAY_LEN
47
- # define RARRAY_LEN(x) RARRAY((x))->len
48
- #endif /* RARRAY_LEN */
49
-
50
- #ifndef RSTRING_LEN
51
- # define RSTRING_LEN(x) RSTRING((x))->len
52
- #endif /* RSTRING_LEN */
53
-
54
- #ifndef RSTRING_PTR
55
- # define RSTRING_PTR(x) RSTRING((x))->ptr
56
- #endif /* RSTRING_PTR */
24
+ #define PG_ENCODING_SET_NOCHECK(obj,i) \
25
+ do { \
26
+ if ((i) < ENCODING_INLINE_MAX) \
27
+ ENCODING_SET_INLINED((obj), (i)); \
28
+ else \
29
+ rb_enc_set_index((obj), (i)); \
30
+ } while(0)
57
31
 
58
- #ifndef StringValuePtr
59
- # define StringValuePtr(x) STR2CSTR(x)
60
- #endif /* StringValuePtr */
61
-
62
- #ifdef RUBY_18_COMPAT
63
- # define rb_io_stdio_file GetWriteFile
64
- # include "rubyio.h"
65
- #else
66
- # include "ruby/io.h"
67
- #endif
32
+ #include "ruby/io.h"
68
33
 
69
34
  #ifndef timeradd
70
35
  #define timeradd(a, b, result) \
@@ -97,26 +62,204 @@
97
62
 
98
63
  #if defined(_WIN32)
99
64
  # include <fcntl.h>
100
- __declspec(dllexport)
101
65
  typedef long suseconds_t;
102
66
  #endif
103
67
 
68
+ #if defined(HAVE_VARIABLE_LENGTH_ARRAYS)
69
+ #define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) type name[(len)];
70
+ #else
71
+ #define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) \
72
+ type name[(maxlen)] = {(len)>(maxlen) ? (rb_raise(rb_eArgError, "Number of " #name " (%d) exceeds allowed maximum of " #maxlen, (len) ), (type)1) : (type)0};
73
+
74
+ #define PG_MAX_COLUMNS 4000
75
+ #endif
76
+
77
+ #ifndef RARRAY_AREF
78
+ #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
79
+ #endif
80
+
81
+ #define PG_ENC_IDX_BITS 28
82
+
83
+ /* The data behind each PG::Connection object */
84
+ typedef struct {
85
+ PGconn *pgconn;
86
+
87
+ /* Cached IO object for the socket descriptor */
88
+ VALUE socket_io;
89
+ /* Proc object that receives notices as PG::Result objects */
90
+ VALUE notice_receiver;
91
+ /* Proc object that receives notices as String objects */
92
+ VALUE notice_processor;
93
+ /* Kind of PG::TypeMap object for casting query params */
94
+ VALUE type_map_for_queries;
95
+ /* Kind of PG::TypeMap object for casting result values */
96
+ VALUE type_map_for_results;
97
+ /* IO object internally used for the trace stream */
98
+ VALUE trace_stream;
99
+ /* Kind of PG::Coder object for casting ruby values to COPY rows */
100
+ VALUE encoder_for_put_copy_data;
101
+ /* Kind of PG::Coder object for casting COPY rows to ruby values */
102
+ VALUE decoder_for_get_copy_data;
103
+ /* Ruby encoding index of the client/internal encoding */
104
+ int enc_idx : PG_ENC_IDX_BITS;
105
+ /* flags controlling Symbol/String field names */
106
+ unsigned int flags : 2;
107
+
108
+ #if defined(_WIN32)
109
+ /* File descriptor to be used for rb_w32_unwrap_io_handle() */
110
+ int ruby_sd;
111
+ #endif
112
+ } t_pg_connection;
113
+
114
+ typedef struct pg_coder t_pg_coder;
115
+ typedef struct pg_typemap t_typemap;
116
+
117
+ /* The data behind each PG::Result object */
118
+ typedef struct {
119
+ PGresult *pgresult;
120
+
121
+ /* The connection object used to build this result */
122
+ VALUE connection;
123
+
124
+ /* The TypeMap used to type cast result values */
125
+ VALUE typemap;
126
+
127
+ /* Pointer to the typemap object data. This is assumed to be
128
+ * always valid.
129
+ */
130
+ t_typemap *p_typemap;
131
+
132
+ /* Ruby encoding index of the client/internal encoding */
133
+ int enc_idx : PG_ENC_IDX_BITS;
134
+
135
+ /* 0 = PGresult is cleared by PG::Result#clear or by the GC
136
+ * 1 = PGresult is cleared internally by libpq
137
+ */
138
+ unsigned int autoclear : 1;
139
+
140
+ /* flags controlling Symbol/String field names */
141
+ unsigned int flags : 2;
142
+
143
+ /* Number of fields in fnames[] .
144
+ * Set to -1 if fnames[] is not yet initialized.
145
+ */
146
+ int nfields;
147
+
148
+ /* Size of PGresult as published to ruby memory management. */
149
+ ssize_t result_size;
150
+
151
+ /* Prefilled tuple Hash with fnames[] as keys. */
152
+ VALUE tuple_hash;
153
+
154
+ /* Hash with fnames[] to field number mapping. */
155
+ VALUE field_map;
156
+
157
+ /* List of field names as frozen String or Symbol objects.
158
+ * Only valid if nfields != -1
159
+ */
160
+ VALUE fnames[0];
161
+ } t_pg_result;
162
+
163
+
164
+ typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *, int);
165
+ typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, const char *, int, int, int, int);
166
+ typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE);
167
+ typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE);
168
+ typedef int (* t_pg_fit_to_copy_get)(VALUE);
169
+ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
170
+ typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
171
+ typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
172
+
173
+ #define PG_RESULT_FIELD_NAMES_MASK 0x03
174
+ #define PG_RESULT_FIELD_NAMES_SYMBOL 0x01
175
+ #define PG_RESULT_FIELD_NAMES_STATIC_SYMBOL 0x02
176
+
177
+ #define PG_CODER_TIMESTAMP_DB_UTC 0x0
178
+ #define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
179
+ #define PG_CODER_TIMESTAMP_APP_UTC 0x0
180
+ #define PG_CODER_TIMESTAMP_APP_LOCAL 0x2
181
+ #define PG_CODER_FORMAT_ERROR_MASK 0xc
182
+ #define PG_CODER_FORMAT_ERROR_TO_RAISE 0x4
183
+ #define PG_CODER_FORMAT_ERROR_TO_STRING 0x8
184
+ #define PG_CODER_FORMAT_ERROR_TO_PARTIAL 0xc
185
+
186
+ struct pg_coder {
187
+ t_pg_coder_enc_func enc_func;
188
+ t_pg_coder_dec_func dec_func;
189
+ VALUE coder_obj;
190
+ Oid oid;
191
+ int format;
192
+ /* OR-ed values out of PG_CODER_* */
193
+ int flags;
194
+ };
195
+
196
+ typedef struct {
197
+ t_pg_coder comp;
198
+ t_pg_coder *elem;
199
+ int needs_quotation;
200
+ char delimiter;
201
+ } t_pg_composite_coder;
202
+
203
+ struct pg_typemap {
204
+ struct pg_typemap_funcs {
205
+ t_pg_fit_to_result fit_to_result;
206
+ t_pg_fit_to_query fit_to_query;
207
+ t_pg_fit_to_copy_get fit_to_copy_get;
208
+ t_pg_typecast_result typecast_result_value;
209
+ t_pg_typecast_query_param typecast_query_param;
210
+ t_pg_typecast_copy_get typecast_copy_get;
211
+ } funcs;
212
+ VALUE default_typemap;
213
+ };
214
+
215
+ typedef struct {
216
+ t_typemap typemap;
217
+ int nfields;
218
+ struct pg_tmbc_converter {
219
+ t_pg_coder *cconv;
220
+ } convs[0];
221
+ } t_tmbc;
222
+
223
+
104
224
  #include "gvl_wrappers.h"
105
225
 
106
226
  /***************************************************************************
107
227
  * Globals
108
228
  **************************************************************************/
109
229
 
230
+ extern int pg_skip_deprecation_warning;
110
231
  extern VALUE rb_mPG;
111
232
  extern VALUE rb_ePGerror;
112
233
  extern VALUE rb_eServerError;
113
234
  extern VALUE rb_eUnableToSend;
114
235
  extern VALUE rb_eConnectionBad;
236
+ extern VALUE rb_eInvalidResultStatus;
237
+ extern VALUE rb_eNoResultError;
238
+ extern VALUE rb_eInvalidChangeOfResultFields;
115
239
  extern VALUE rb_mPGconstants;
116
240
  extern VALUE rb_cPGconn;
117
241
  extern VALUE rb_cPGresult;
118
242
  extern VALUE rb_hErrors;
243
+ extern VALUE rb_cTypeMap;
244
+ extern VALUE rb_cTypeMapAllStrings;
245
+ extern VALUE rb_mDefaultTypeMappable;
246
+ extern VALUE rb_cPG_Coder;
247
+ extern VALUE rb_cPG_SimpleEncoder;
248
+ extern VALUE rb_cPG_SimpleDecoder;
249
+ extern VALUE rb_cPG_CompositeEncoder;
250
+ extern VALUE rb_cPG_CompositeDecoder;
251
+ extern VALUE rb_cPG_CopyCoder;
252
+ extern VALUE rb_cPG_CopyEncoder;
253
+ extern VALUE rb_cPG_CopyDecoder;
254
+ extern VALUE rb_mPG_TextEncoder;
255
+ extern VALUE rb_mPG_TextDecoder;
256
+ extern VALUE rb_mPG_BinaryEncoder;
257
+ extern VALUE rb_mPG_BinaryDecoder;
258
+ extern VALUE rb_mPG_BinaryFormatting;
259
+ extern const struct pg_typemap_funcs pg_tmbc_funcs;
260
+ extern const struct pg_typemap_funcs pg_typemap_funcs;
119
261
 
262
+ extern VALUE pg_typemap_all_strings;
120
263
 
121
264
  /***************************************************************************
122
265
  * MACROS
@@ -134,23 +277,92 @@ void Init_pg_ext _(( void ));
134
277
  void init_pg_connection _(( void ));
135
278
  void init_pg_result _(( void ));
136
279
  void init_pg_errors _(( void ));
137
- VALUE lookup_error_class _(( const char *sqlstate ));
280
+ void init_pg_type_map _(( void ));
281
+ void init_pg_type_map_all_strings _(( void ));
282
+ void init_pg_type_map_by_class _(( void ));
283
+ void init_pg_type_map_by_column _(( void ));
284
+ void init_pg_type_map_by_mri_type _(( void ));
285
+ void init_pg_type_map_by_oid _(( void ));
286
+ void init_pg_type_map_in_ruby _(( void ));
287
+ void init_pg_coder _(( void ));
288
+ void init_pg_copycoder _(( void ));
289
+ void init_pg_recordcoder _(( void ));
290
+ void init_pg_text_encoder _(( void ));
291
+ void init_pg_text_decoder _(( void ));
292
+ void init_pg_binary_encoder _(( void ));
293
+ void init_pg_binary_decoder _(( void ));
294
+ void init_pg_tuple _(( void ));
295
+ VALUE lookup_error_class _(( const char * ));
296
+ VALUE pg_bin_dec_bytea _(( t_pg_coder*, const char *, int, int, int, int ));
297
+ VALUE pg_text_dec_string _(( t_pg_coder*, const char *, int, int, int, int ));
298
+ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *, int));
299
+ int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
300
+ t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
301
+ t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
302
+ void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
303
+ VALUE pg_obj_to_i _(( VALUE ));
304
+ VALUE pg_tmbc_allocate _(( void ));
305
+ void pg_coder_init_encoder _(( VALUE ));
306
+ void pg_coder_init_decoder _(( VALUE ));
307
+ void pg_coder_mark _(( t_pg_coder * ));
308
+ char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
309
+
310
+ #define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
311
+ do { \
312
+ if( (curr_ptr) + (expand_len) >= (end_ptr) ) \
313
+ (curr_ptr) = pg_rb_str_ensure_capa( (str), (expand_len), (curr_ptr), &(end_ptr) ); \
314
+ } while(0);
138
315
 
139
- PGconn *pg_get_pgconn _(( VALUE ));
316
+ #define PG_RB_STR_NEW( str, curr_ptr, end_ptr ) ( \
317
+ (str) = rb_str_new( NULL, 0 ), \
318
+ (curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
319
+ )
320
+
321
+ VALUE pg_typemap_fit_to_result _(( VALUE, VALUE ));
322
+ VALUE pg_typemap_fit_to_query _(( VALUE, VALUE ));
323
+ int pg_typemap_fit_to_copy_get _(( VALUE ));
324
+ VALUE pg_typemap_result_value _(( t_typemap *, VALUE, int, int ));
325
+ t_pg_coder *pg_typemap_typecast_query_param _(( t_typemap *, VALUE, int ));
326
+ VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int ));
327
+
328
+ PGconn *pg_get_pgconn _(( VALUE ));
329
+ t_pg_connection *pg_get_connection _(( VALUE ));
140
330
 
141
331
  VALUE pg_new_result _(( PGresult *, VALUE ));
332
+ VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
333
+ PGresult* pgresult_get _(( VALUE ));
142
334
  VALUE pg_result_check _(( VALUE ));
143
335
  VALUE pg_result_clear _(( VALUE ));
336
+ VALUE pg_tuple_new _(( VALUE, int ));
337
+
338
+ /*
339
+ * Fetch the data pointer for the result object
340
+ */
341
+ static inline t_pg_result *
342
+ pgresult_get_this( VALUE self )
343
+ {
344
+ return RTYPEDDATA_DATA(self);
345
+ }
346
+
144
347
 
145
- #ifdef M17N_SUPPORTED
146
348
  rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int ));
147
349
  rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * ));
148
350
  const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * ));
149
- int pg_enc_get_index _(( VALUE ));
150
351
  rb_encoding *pg_conn_enc_get _(( PGconn * ));
151
- #endif /* M17N_SUPPORTED */
152
352
 
153
353
  void notice_receiver_proxy(void *arg, const PGresult *result);
154
354
  void notice_processor_proxy(void *arg, const char *message);
155
355
 
356
+ /* reports if `-W' specified and PG_SKIP_DEPRECATION_WARNING environment variable isn't set
357
+ *
358
+ * message_id identifies the warning, so that it's reported only once.
359
+ */
360
+ #define pg_deprecated(message_id, format_args) \
361
+ do { \
362
+ if( !(pg_skip_deprecation_warning & (1 << message_id)) ){ \
363
+ pg_skip_deprecation_warning |= 1 << message_id; \
364
+ rb_warning format_args; \
365
+ } \
366
+ } while(0);
367
+
156
368
  #endif /* end __pg_h */
@@ -0,0 +1,229 @@
1
+ /*
2
+ * pg_column_map.c - PG::ColumnMap class extension
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ #include "ruby/version.h"
8
+ #include "pg.h"
9
+ #include "pg_util.h"
10
+ #ifdef HAVE_INTTYPES_H
11
+ #include <inttypes.h>
12
+ #endif
13
+
14
+ VALUE rb_mPG_BinaryDecoder;
15
+
16
+
17
+ /*
18
+ * Document-class: PG::BinaryDecoder::Boolean < PG::SimpleDecoder
19
+ *
20
+ * This is a decoder class for conversion of PostgreSQL binary +bool+ type
21
+ * to Ruby +true+ or +false+ objects.
22
+ *
23
+ */
24
+ static VALUE
25
+ pg_bin_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
26
+ {
27
+ if (len < 1) {
28
+ rb_raise( rb_eTypeError, "wrong data for binary boolean converter in tuple %d field %d", tuple, field);
29
+ }
30
+ return *val == 0 ? Qfalse : Qtrue;
31
+ }
32
+
33
+ /*
34
+ * Document-class: PG::BinaryDecoder::Integer < PG::SimpleDecoder
35
+ *
36
+ * This is a decoder class for conversion of PostgreSQL binary +int2+, +int4+ and +int8+ types
37
+ * to Ruby Integer objects.
38
+ *
39
+ */
40
+ static VALUE
41
+ pg_bin_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
42
+ {
43
+ switch( len ){
44
+ case 2:
45
+ return INT2NUM(read_nbo16(val));
46
+ case 4:
47
+ return LONG2NUM(read_nbo32(val));
48
+ case 8:
49
+ return LL2NUM(read_nbo64(val));
50
+ default:
51
+ rb_raise( rb_eTypeError, "wrong data for binary integer converter in tuple %d field %d length %d", tuple, field, len);
52
+ }
53
+ }
54
+
55
+ /*
56
+ * Document-class: PG::BinaryDecoder::Float < PG::SimpleDecoder
57
+ *
58
+ * This is a decoder class for conversion of PostgreSQL binary +float4+ and +float8+ types
59
+ * to Ruby Float objects.
60
+ *
61
+ */
62
+ static VALUE
63
+ pg_bin_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
64
+ {
65
+ union {
66
+ float f;
67
+ int32_t i;
68
+ } swap4;
69
+ union {
70
+ double f;
71
+ int64_t i;
72
+ } swap8;
73
+
74
+ switch( len ){
75
+ case 4:
76
+ swap4.i = read_nbo32(val);
77
+ return rb_float_new(swap4.f);
78
+ case 8:
79
+ swap8.i = read_nbo64(val);
80
+ return rb_float_new(swap8.f);
81
+ default:
82
+ rb_raise( rb_eTypeError, "wrong data for BinaryFloat converter in tuple %d field %d length %d", tuple, field, len);
83
+ }
84
+ }
85
+
86
+ /*
87
+ * Document-class: PG::BinaryDecoder::Bytea < PG::SimpleDecoder
88
+ *
89
+ * 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
91
+ * data in binary format.
92
+ *
93
+ */
94
+ VALUE
95
+ pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
96
+ {
97
+ VALUE ret;
98
+ ret = rb_str_new( val, len );
99
+ PG_ENCODING_SET_NOCHECK( ret, rb_ascii8bit_encindex() );
100
+ return ret;
101
+ }
102
+
103
+ /*
104
+ * Document-class: PG::BinaryDecoder::ToBase64 < PG::CompositeDecoder
105
+ *
106
+ * This is a decoder class for conversion of binary +bytea+ to base64 data.
107
+ *
108
+ */
109
+ static VALUE
110
+ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
111
+ {
112
+ t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
113
+ t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
114
+ int encoded_len = BASE64_ENCODED_SIZE(len);
115
+ /* create a buffer of the encoded length */
116
+ VALUE out_value = rb_str_new(NULL, encoded_len);
117
+
118
+ base64_encode( RSTRING_PTR(out_value), val, len );
119
+
120
+ /* Is it a pure String conversion? Then we can directly send out_value to the user. */
121
+ if( this->comp.format == 0 && dec_func == pg_text_dec_string ){
122
+ PG_ENCODING_SET_NOCHECK( out_value, enc_idx );
123
+ return out_value;
124
+ }
125
+ if( this->comp.format == 1 && dec_func == pg_bin_dec_bytea ){
126
+ PG_ENCODING_SET_NOCHECK( out_value, rb_ascii8bit_encindex() );
127
+ return out_value;
128
+ }
129
+ out_value = dec_func(this->elem, RSTRING_PTR(out_value), encoded_len, tuple, field, enc_idx);
130
+
131
+ return out_value;
132
+ }
133
+
134
+ #define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
135
+ #define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
136
+
137
+ /*
138
+ * Document-class: PG::BinaryDecoder::Timestamp < PG::SimpleDecoder
139
+ *
140
+ * This is a decoder class for conversion of PostgreSQL binary timestamps
141
+ * to Ruby Time objects.
142
+ *
143
+ * The following flags can be used to specify timezone interpretation:
144
+ * * +PG::Coder::TIMESTAMP_DB_UTC+ : Interpret timestamp as UTC time (default)
145
+ * * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Interpret timestamp as local time
146
+ * * +PG::Coder::TIMESTAMP_APP_UTC+ : Return timestamp as UTC time (default)
147
+ * * +PG::Coder::TIMESTAMP_APP_LOCAL+ : Return timestamp as local time
148
+ *
149
+ * Example:
150
+ * deco = PG::BinaryDecoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL)
151
+ * deco.decode("\0"*8) # => 2000-01-01 01:00:00 +0100
152
+ */
153
+ static VALUE
154
+ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
155
+ {
156
+ int64_t timestamp;
157
+ int64_t sec;
158
+ int64_t nsec;
159
+ VALUE t;
160
+
161
+ if( len != sizeof(timestamp) ){
162
+ rb_raise( rb_eTypeError, "wrong data for timestamp converter in tuple %d field %d length %d", tuple, field, len);
163
+ }
164
+
165
+ timestamp = read_nbo64(val);
166
+
167
+ switch(timestamp){
168
+ case PG_INT64_MAX:
169
+ return rb_str_new2("infinity");
170
+ case PG_INT64_MIN:
171
+ return rb_str_new2("-infinity");
172
+ default:
173
+ /* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
174
+ * Adjust the 30 years difference. */
175
+ sec = (timestamp / 1000000) + 10957L * 24L * 3600L;
176
+ nsec = (timestamp % 1000000) * 1000;
177
+
178
+ #if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(NEGATIVE_TIME_T) && defined(SIZEOF_TIME_T) && SIZEOF_TIME_T >= 8
179
+ /* Fast path for time conversion */
180
+ {
181
+ struct timespec ts = {sec, nsec};
182
+ t = rb_time_timespec_new(&ts, conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ? INT_MAX : INT_MAX-1);
183
+ }
184
+ #else
185
+ t = rb_funcall(rb_cTime, rb_intern("at"), 2, LL2NUM(sec), LL2NUM(nsec / 1000));
186
+ if( !(conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL) ) {
187
+ t = rb_funcall(t, rb_intern("utc"), 0);
188
+ }
189
+ #endif
190
+ if( conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
191
+ /* interpret it as local time */
192
+ t = rb_funcall(t, rb_intern("-"), 1, rb_funcall(t, rb_intern("utc_offset"), 0));
193
+ }
194
+ return t;
195
+ }
196
+ }
197
+
198
+ /*
199
+ * Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
200
+ *
201
+ * This is a decoder class for conversion of PostgreSQL text output to
202
+ * to Ruby String object. The output value will have the character encoding
203
+ * set with PG::Connection#internal_encoding= .
204
+ *
205
+ */
206
+
207
+ void
208
+ init_pg_binary_decoder()
209
+ {
210
+ /* This module encapsulates all decoder classes with binary input format */
211
+ rb_mPG_BinaryDecoder = rb_define_module_under( rb_mPG, "BinaryDecoder" );
212
+
213
+ /* Make RDoc aware of the decoder classes... */
214
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
215
+ pg_define_coder( "Boolean", pg_bin_dec_boolean, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
216
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Integer", rb_cPG_SimpleDecoder ); */
217
+ pg_define_coder( "Integer", pg_bin_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
218
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Float", rb_cPG_SimpleDecoder ); */
219
+ pg_define_coder( "Float", pg_bin_dec_float, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
220
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "String", rb_cPG_SimpleDecoder ); */
221
+ pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
222
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
223
+ pg_define_coder( "Bytea", pg_bin_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
224
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
225
+ pg_define_coder( "Timestamp", pg_bin_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
226
+
227
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
228
+ pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
229
+ }