pg 1.0.0 → 1.1.0.pre20180730144600

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 (54) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +0 -6595
  5. data/History.rdoc +52 -0
  6. data/README.rdoc +11 -0
  7. data/Rakefile +1 -1
  8. data/Rakefile.cross +1 -1
  9. data/ext/errorcodes.rb +1 -1
  10. data/ext/extconf.rb +2 -0
  11. data/ext/pg.c +3 -2
  12. data/ext/pg.h +33 -5
  13. data/ext/pg_binary_decoder.c +69 -6
  14. data/ext/pg_binary_encoder.c +1 -1
  15. data/ext/pg_coder.c +52 -3
  16. data/ext/pg_connection.c +290 -103
  17. data/ext/pg_copy_coder.c +10 -5
  18. data/ext/pg_result.c +339 -113
  19. data/ext/pg_text_decoder.c +597 -37
  20. data/ext/pg_text_encoder.c +1 -1
  21. data/ext/pg_tuple.c +540 -0
  22. data/ext/pg_type_map.c +1 -1
  23. data/ext/pg_type_map_all_strings.c +1 -1
  24. data/ext/pg_type_map_by_class.c +1 -1
  25. data/ext/pg_type_map_by_column.c +1 -1
  26. data/ext/pg_type_map_by_mri_type.c +1 -1
  27. data/ext/pg_type_map_by_oid.c +1 -1
  28. data/ext/pg_type_map_in_ruby.c +1 -1
  29. data/ext/util.c +6 -6
  30. data/ext/util.h +2 -2
  31. data/lib/pg.rb +5 -3
  32. data/lib/pg/basic_type_mapping.rb +40 -7
  33. data/lib/pg/coder.rb +1 -1
  34. data/lib/pg/connection.rb +20 -1
  35. data/lib/pg/constants.rb +1 -1
  36. data/lib/pg/exceptions.rb +1 -1
  37. data/lib/pg/result.rb +1 -1
  38. data/lib/pg/text_decoder.rb +19 -23
  39. data/lib/pg/text_encoder.rb +35 -1
  40. data/lib/pg/type_map_by_column.rb +1 -1
  41. data/spec/helpers.rb +39 -7
  42. data/spec/pg/basic_type_mapping_spec.rb +230 -27
  43. data/spec/pg/connection_spec.rb +116 -77
  44. data/spec/pg/result_spec.rb +46 -11
  45. data/spec/pg/type_map_by_class_spec.rb +1 -1
  46. data/spec/pg/type_map_by_column_spec.rb +1 -1
  47. data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
  48. data/spec/pg/type_map_by_oid_spec.rb +1 -1
  49. data/spec/pg/type_map_in_ruby_spec.rb +1 -1
  50. data/spec/pg/type_map_spec.rb +1 -1
  51. data/spec/pg/type_spec.rb +177 -11
  52. data/spec/pg_spec.rb +1 -1
  53. metadata +24 -28
  54. metadata.gz.sig +0 -0
@@ -1,3 +1,54 @@
1
+ == v2.0.0 - far from release -
2
+
3
+ Removed:
4
+ - Removed query method variants deprecated in pg-1.1.0.
5
+
6
+
7
+ == v1.1.0 [YYYY-MM-DD] Michael Granger <ged@FaerieMUD.org>
8
+
9
+ Deprecated:
10
+ - Forwarding conn.exec to conn.exec_params is deprecated.
11
+ - Forwarding conn.exec_params to conn.exec is deprecated.
12
+ - Forwarding conn.async_exec to conn.async_exec_params.
13
+ - Forwarding conn.send_query to conn.send_query_params is deprecated.
14
+ - Forwarding conn.async_exec_params to conn.async_exec is deprecated.
15
+
16
+ PG::Connection enhancements:
17
+ - Provide PG::Connection#sync_* and PG::Connection#async_* query methods for explicit calling syncronous or asynchronous libpq API.
18
+ - Make PG::Connection#exec and siblings switchable between sync and async API per PG::Connection.async_api= and change the default to async flavors.
19
+ - Add async flavors of exec_params, prepare, exec_prepared, describe_prepared and describe_portal.
20
+ They are identical to their syncronous counterpart, but make use of PostgreSQL's async API.
21
+ - Replace `rb_thread_fd_select()` by faster `rb_wait_for_single_fd()` in `conn.block` and `conn.async_exec` .
22
+ - Add PG::Connection#discard_results .
23
+
24
+ Result retrieval enhancements:
25
+ - Add PG::Result#tuple_values to retrieve all field values of a row as array.
26
+ - Add PG::Tuple, PG::Result#tuple_values and PG::Result#stream_each_tuple .
27
+ PG::Tuple offers a way to lazy cast result values.
28
+ - Estimate PG::Result size allocated by libpq and notify the garbage collector about it when running on Ruby-2.4 or newer.
29
+ - Make the estimated PG::Result size available to ObjectSpace.memsize_of(result) .
30
+
31
+ Type cast enhancements:
32
+ - Replace Ruby code by a faster C implementation of the SimpleDecoder's timestamp decode functions. github #20
33
+ - Interpret years with up to 7 digists and BC dates by timestamp decoder.
34
+ - Add text timestamp decoders for UTC vs. local timezone variations.
35
+ - Add text timestamp encoders for UTC timezone.
36
+ - Add decoders for binary timestamps: PG::BinaryDecoder::Timestamp and variations.
37
+ - Add PG::Coder#flags accessor to allow modifications of de- respectively encoder behaviour.
38
+ - Add a flag to raise TypeError for invalid input values to PG::TextDecoder::Array .
39
+ - Add a text decoder for inet/cidr written in C.
40
+ - Add a numeric decoder written in C.
41
+ - Ensure input text is zero terminated for text format in PG::Coder#decode .
42
+
43
+ Source code enhancements:
44
+ - Fix headers and permission bits of various repository files.
45
+
46
+ Bugfixes:
47
+ - Properly decode array with prepended dimensions. #272
48
+ For now dimension decorations are ignored, but a correct Array is returned.
49
+ - Array-Decoder: Avoid leaking memory when an Exception is raised while parsing. Fixes #279
50
+
51
+
1
52
  == v1.0.0 [2018-01-10] Michael Granger <ged@FaerieMUD.org>
2
53
 
3
54
  Deprecated:
@@ -7,6 +58,7 @@ Deprecated:
7
58
  Removed:
8
59
  - Remove compatibility code for Ruby < 2.0 and PostgreSQL < 9.2.
9
60
  - Remove partial compatibility with Rubinius.
61
+ - Remove top-level constants PGconn, PGresult, and PGError.
10
62
 
11
63
  Enhancements:
12
64
  - Update error codes to PostgreSQL-10
@@ -44,6 +44,17 @@ It usually work with earlier versions of Ruby/PostgreSQL as well, but those are
44
44
  not regularly tested.
45
45
 
46
46
 
47
+ == Versioning
48
+
49
+ We tag and release gems according to the {Semantic Versioning}[http://semver.org/] principle.
50
+
51
+ 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.
52
+
53
+ For example:
54
+
55
+ spec.add_dependency 'pg', '~> 1.0'
56
+
57
+
47
58
  == How To Install
48
59
 
49
60
  Install via RubyGems:
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env rake
1
+ # -*- rake -*-
2
2
 
3
3
  require 'rbconfig'
4
4
  require 'pathname'
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env rake
1
+ # -*- rake -*-
2
2
 
3
3
  require 'uri'
4
4
  require 'tempfile'
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ # -*- ruby -*-
2
2
 
3
3
  def camelize(lower_case_and_underscored_word)
4
4
  lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
@@ -76,6 +76,8 @@ have_func 'PQsetSingleRowMode' or
76
76
  have_func 'PQconninfo'
77
77
  have_func 'PQsslAttribute'
78
78
  have_func 'PQencryptPasswordConn'
79
+ have_func 'timegm'
80
+ have_func 'rb_gc_adjust_memory_usage'
79
81
 
80
82
  have_const 'PG_DIAG_TABLE_NAME', 'libpq-fe.h'
81
83
 
data/ext/pg.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg.c - Toplevel extension
3
- * $Id: pg.c,v 1f0926bfa9a5 2018/01/04 18:14:32 lars $
3
+ * $Id$
4
4
  *
5
5
  * Author/s:
6
6
  *
@@ -143,7 +143,7 @@ pg_find_or_create_johab(void)
143
143
 
144
144
  enc_index = rb_define_dummy_encoding(aliases[0]);
145
145
  for (i = 1; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
146
- rb_encdb_alias(aliases[i], aliases[0]);
146
+ rb_enc_alias(aliases[i], aliases[0]);
147
147
  }
148
148
  return rb_enc_from_index(enc_index);
149
149
  }
@@ -630,5 +630,6 @@ Init_pg_ext()
630
630
  init_pg_binary_encoder();
631
631
  init_pg_binary_decoder();
632
632
  init_pg_copycoder();
633
+ init_pg_tuple();
633
634
  }
634
635
 
data/ext/pg.h CHANGED
@@ -22,7 +22,7 @@
22
22
  #include "ruby/encoding.h"
23
23
 
24
24
  /* exported by ruby-1.9.3+ but not declared */
25
- extern int rb_encdb_alias(const char *, const char *);
25
+ extern int rb_enc_alias(const char *, const char *);
26
26
 
27
27
  #define PG_ENCODING_SET_NOCHECK(obj,i) \
28
28
  do { \
@@ -77,6 +77,10 @@ typedef long suseconds_t;
77
77
  #define PG_MAX_COLUMNS 4000
78
78
  #endif
79
79
 
80
+ #ifndef RARRAY_AREF
81
+ #define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
82
+ #endif
83
+
80
84
  /* The data behind each PG::Connection object */
81
85
  typedef struct {
82
86
  PGconn *pgconn;
@@ -100,6 +104,11 @@ typedef struct {
100
104
  /* Kind of PG::Coder object for casting COPY rows to ruby values */
101
105
  VALUE decoder_for_get_copy_data;
102
106
 
107
+ /* The connection socket, used for rb_wait_for_single_fd() */
108
+ int socket;
109
+
110
+ /* enable/disable guessing size of PGresult's allocated memory */
111
+ int guess_result_memsize;
103
112
  } t_pg_connection;
104
113
 
105
114
  typedef struct pg_coder t_pg_coder;
@@ -130,9 +139,15 @@ typedef struct {
130
139
  */
131
140
  int nfields;
132
141
 
142
+ /* Size of PGresult as published to ruby memory management. */
143
+ ssize_t result_size;
144
+
133
145
  /* Prefilled tuple Hash with fnames[] as keys. */
134
146
  VALUE tuple_hash;
135
147
 
148
+ /* Hash with fnames[] to field number mapping. */
149
+ VALUE field_map;
150
+
136
151
  /* List of field names as frozen String objects.
137
152
  * Only valid if nfields != -1
138
153
  */
@@ -141,7 +156,7 @@ typedef struct {
141
156
 
142
157
 
143
158
  typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *, int);
144
- typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, char *, int, int, int, int);
159
+ typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, const char *, int, int, int, int);
145
160
  typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE);
146
161
  typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE);
147
162
  typedef int (* t_pg_fit_to_copy_get)(VALUE);
@@ -149,12 +164,23 @@ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
149
164
  typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
150
165
  typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
151
166
 
167
+ #define PG_CODER_TIMESTAMP_DB_UTC 0x0
168
+ #define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
169
+ #define PG_CODER_TIMESTAMP_APP_UTC 0x0
170
+ #define PG_CODER_TIMESTAMP_APP_LOCAL 0x2
171
+ #define PG_CODER_FORMAT_ERROR_MASK 0xc
172
+ #define PG_CODER_FORMAT_ERROR_TO_RAISE 0x4
173
+ #define PG_CODER_FORMAT_ERROR_TO_STRING 0x8
174
+ #define PG_CODER_FORMAT_ERROR_TO_PARTIAL 0xc
175
+
152
176
  struct pg_coder {
153
177
  t_pg_coder_enc_func enc_func;
154
178
  t_pg_coder_dec_func dec_func;
155
179
  VALUE coder_obj;
156
180
  Oid oid;
157
181
  int format;
182
+ /* OR-ed values out of PG_CODER_* */
183
+ int flags;
158
184
  };
159
185
 
160
186
  typedef struct {
@@ -253,9 +279,10 @@ void init_pg_text_encoder _(( void ));
253
279
  void init_pg_text_decoder _(( void ));
254
280
  void init_pg_binary_encoder _(( void ));
255
281
  void init_pg_binary_decoder _(( void ));
282
+ void init_pg_tuple _(( void ));
256
283
  VALUE lookup_error_class _(( const char * ));
257
- VALUE pg_bin_dec_bytea _(( t_pg_coder*, char *, int, int, int, int ));
258
- VALUE pg_text_dec_string _(( t_pg_coder*, char *, int, int, int, int ));
284
+ VALUE pg_bin_dec_bytea _(( t_pg_coder*, const char *, int, int, int, int ));
285
+ VALUE pg_text_dec_string _(( t_pg_coder*, const char *, int, int, int, int ));
259
286
  int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *, int));
260
287
  int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
261
288
  t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
@@ -298,6 +325,7 @@ VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
298
325
  PGresult* pgresult_get _(( VALUE ));
299
326
  VALUE pg_result_check _(( VALUE ));
300
327
  VALUE pg_result_clear _(( VALUE ));
328
+ VALUE pg_tuple_new _(( VALUE, int ));
301
329
 
302
330
  /*
303
331
  * Fetch the data pointer for the result object
@@ -305,7 +333,7 @@ VALUE pg_result_clear _(( VALUE ));
305
333
  static inline t_pg_result *
306
334
  pgresult_get_this( VALUE self )
307
335
  {
308
- t_pg_result *this = DATA_PTR(self);
336
+ t_pg_result *this = RTYPEDDATA_DATA(self);
309
337
 
310
338
  if( this == NULL )
311
339
  rb_raise(rb_ePGerror, "result has been cleared");
@@ -1,9 +1,10 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id: pg_binary_decoder.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
3
+ * $Id$
4
4
  *
5
5
  */
6
6
 
7
+ #include "ruby/version.h"
7
8
  #include "pg.h"
8
9
  #include "util.h"
9
10
  #ifdef HAVE_INTTYPES_H
@@ -21,7 +22,7 @@ VALUE rb_mPG_BinaryDecoder;
21
22
  *
22
23
  */
23
24
  static VALUE
24
- pg_bin_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
25
+ pg_bin_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
25
26
  {
26
27
  if (len < 1) {
27
28
  rb_raise( rb_eTypeError, "wrong data for binary boolean converter in tuple %d field %d", tuple, field);
@@ -37,7 +38,7 @@ pg_bin_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field, i
37
38
  *
38
39
  */
39
40
  static VALUE
40
- pg_bin_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
41
+ pg_bin_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
41
42
  {
42
43
  switch( len ){
43
44
  case 2:
@@ -59,7 +60,7 @@ pg_bin_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field, i
59
60
  *
60
61
  */
61
62
  static VALUE
62
- pg_bin_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
63
+ pg_bin_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
63
64
  {
64
65
  union {
65
66
  float f;
@@ -91,7 +92,7 @@ pg_bin_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, int
91
92
  *
92
93
  */
93
94
  VALUE
94
- pg_bin_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
95
+ pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
95
96
  {
96
97
  VALUE ret;
97
98
  ret = rb_tainted_str_new( val, len );
@@ -106,7 +107,7 @@ pg_bin_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, int
106
107
  *
107
108
  */
108
109
  static VALUE
109
- pg_bin_dec_to_base64(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
110
+ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
110
111
  {
111
112
  t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
112
113
  t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
@@ -130,6 +131,66 @@ pg_bin_dec_to_base64(t_pg_coder *conv, char *val, int len, int tuple, int field,
130
131
  return out_value;
131
132
  }
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
+ struct timespec ts;
158
+ VALUE t;
159
+
160
+ if( len != sizeof(timestamp) ){
161
+ rb_raise( rb_eTypeError, "wrong data for timestamp converter in tuple %d field %d length %d", tuple, field, len);
162
+ }
163
+
164
+ timestamp = read_nbo64(val);
165
+
166
+ switch(timestamp){
167
+ case PG_INT64_MAX:
168
+ return rb_str_new2("infinity");
169
+ case PG_INT64_MIN:
170
+ return rb_str_new2("-infinity");
171
+ default:
172
+ /* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
173
+ * Adjust the 30 years difference. */
174
+ ts.tv_sec = (timestamp / 1000000) + 10957L * 24L * 3600L;
175
+ ts.tv_nsec = (timestamp % 1000000) * 1000;
176
+
177
+ #if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(NEGATIVE_TIME_T)
178
+ /* Fast path for time conversion */
179
+ t = rb_time_timespec_new(&ts, conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ? INT_MAX : INT_MAX-1);
180
+ #else
181
+ t = rb_funcall(rb_cTime, rb_intern("at"), 2, LL2NUM(ts.tv_sec), LL2NUM(ts.tv_nsec / 1000));
182
+ if( !(conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL) ) {
183
+ t = rb_funcall(t, rb_intern("utc"), 0);
184
+ }
185
+ #endif
186
+ if( conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
187
+ /* interpret it as local time */
188
+ t = rb_funcall(t, rb_intern("-"), 1, rb_funcall(t, rb_intern("utc_offset"), 0));
189
+ }
190
+ return t;
191
+ }
192
+ }
193
+
133
194
  /*
134
195
  * Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
135
196
  *
@@ -156,6 +217,8 @@ init_pg_binary_decoder()
156
217
  pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
157
218
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
158
219
  pg_define_coder( "Bytea", pg_bin_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
220
+ /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
221
+ pg_define_coder( "Timestamp", pg_bin_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
159
222
 
160
223
  /* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
161
224
  pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
@@ -1,6 +1,6 @@
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
 
@@ -38,6 +38,7 @@ pg_coder_init_encoder( VALUE self )
38
38
  this->coder_obj = self;
39
39
  this->oid = 0;
40
40
  this->format = 0;
41
+ this->flags = 0;
41
42
  rb_iv_set( self, "@name", Qnil );
42
43
  }
43
44
 
@@ -56,6 +57,7 @@ pg_coder_init_decoder( VALUE self )
56
57
  this->coder_obj = self;
57
58
  this->oid = 0;
58
59
  this->format = 0;
60
+ this->flags = 0;
59
61
  rb_iv_set( self, "@name", Qnil );
60
62
  }
61
63
 
@@ -192,7 +194,11 @@ pg_coder_decode(int argc, VALUE *argv, VALUE self)
192
194
  if( NIL_P(argv[0]) )
193
195
  return Qnil;
194
196
 
195
- val = StringValuePtr(argv[0]);
197
+ if( this->format == 0 ){
198
+ val = StringValueCStr(argv[0]);
199
+ }else{
200
+ val = StringValuePtr(argv[0]);
201
+ }
196
202
  if( !this->dec_func ){
197
203
  rb_raise(rb_eRuntimeError, "no decoder function defined");
198
204
  }
@@ -265,6 +271,36 @@ pg_coder_format_get(VALUE self)
265
271
  return INT2NUM(this->format);
266
272
  }
267
273
 
274
+ /*
275
+ * call-seq:
276
+ * coder.flags = Integer
277
+ *
278
+ * Set coder specific bitwise OR-ed flags.
279
+ * See the particular en- or decoder description for available flags.
280
+ *
281
+ * The default is +0+.
282
+ */
283
+ static VALUE
284
+ pg_coder_flags_set(VALUE self, VALUE flags)
285
+ {
286
+ t_pg_coder *this = DATA_PTR(self);
287
+ this->flags = NUM2INT(flags);
288
+ return flags;
289
+ }
290
+
291
+ /*
292
+ * call-seq:
293
+ * coder.flags -> Integer
294
+ *
295
+ * Get current bitwise OR-ed coder flags.
296
+ */
297
+ static VALUE
298
+ pg_coder_flags_get(VALUE self)
299
+ {
300
+ t_pg_coder *this = DATA_PTR(self);
301
+ return INT2NUM(this->flags);
302
+ }
303
+
268
304
  /*
269
305
  * call-seq:
270
306
  * coder.needs_quotation = Boolean
@@ -403,14 +439,14 @@ pg_coder_enc_func(t_pg_coder *this)
403
439
  }
404
440
 
405
441
  static VALUE
406
- pg_text_dec_in_ruby(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
442
+ pg_text_dec_in_ruby(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
407
443
  {
408
444
  VALUE string = pg_text_dec_string(this, val, len, tuple, field, enc_idx);
409
445
  return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
410
446
  }
411
447
 
412
448
  static VALUE
413
- pg_bin_dec_in_ruby(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
449
+ pg_bin_dec_in_ruby(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
414
450
  {
415
451
  VALUE string = pg_bin_dec_bytea(this, val, len, tuple, field, enc_idx);
416
452
  return rb_funcall( this->coder_obj, s_id_decode, 3, string, INT2NUM(tuple), INT2NUM(field) );
@@ -457,6 +493,19 @@ init_pg_coder()
457
493
  rb_define_method( rb_cPG_Coder, "oid", pg_coder_oid_get, 0 );
458
494
  rb_define_method( rb_cPG_Coder, "format=", pg_coder_format_set, 1 );
459
495
  rb_define_method( rb_cPG_Coder, "format", pg_coder_format_get, 0 );
496
+ rb_define_method( rb_cPG_Coder, "flags=", pg_coder_flags_set, 1 );
497
+ rb_define_method( rb_cPG_Coder, "flags", pg_coder_flags_get, 0 );
498
+
499
+ /* define flags to be used with PG::Coder#flags= */
500
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_DB_UTC", INT2NUM(PG_CODER_TIMESTAMP_DB_UTC));
501
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_DB_LOCAL", INT2NUM(PG_CODER_TIMESTAMP_DB_LOCAL));
502
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_APP_UTC", INT2NUM(PG_CODER_TIMESTAMP_APP_UTC));
503
+ rb_define_const( rb_cPG_Coder, "TIMESTAMP_APP_LOCAL", INT2NUM(PG_CODER_TIMESTAMP_APP_LOCAL));
504
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_MASK", INT2NUM(PG_CODER_FORMAT_ERROR_MASK));
505
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_RAISE", INT2NUM(PG_CODER_FORMAT_ERROR_TO_RAISE));
506
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_STRING", INT2NUM(PG_CODER_FORMAT_ERROR_TO_STRING));
507
+ rb_define_const( rb_cPG_Coder, "FORMAT_ERROR_TO_PARTIAL", INT2NUM(PG_CODER_FORMAT_ERROR_TO_PARTIAL));
508
+
460
509
  /*
461
510
  * Name of the coder or the corresponding data type.
462
511
  *