pg 1.4.5-x64-mingw-ucrt → 1.5.0-x64-mingw-ucrt
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +15 -9
- data/.github/workflows/binary-gems.yml +41 -10
- data/.github/workflows/source-gem.yml +18 -12
- data/.gitignore +11 -2
- data/.travis.yml +2 -2
- data/{History.rdoc → History.md} +223 -153
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +12 -3
- data/Rakefile.cross +7 -11
- data/certs/larskanis-2023.pem +24 -0
- data/ext/pg.c +10 -28
- data/ext/pg.h +10 -5
- data/ext/pg_binary_decoder.c +79 -0
- data/ext/pg_binary_encoder.c +224 -0
- data/ext/pg_coder.c +16 -7
- data/ext/pg_connection.c +156 -60
- data/ext/pg_copy_coder.c +306 -17
- data/ext/pg_record_coder.c +5 -4
- data/ext/pg_result.c +88 -17
- data/ext/pg_text_decoder.c +28 -10
- data/ext/pg_text_encoder.c +22 -9
- data/ext/pg_tuple.c +34 -31
- data/ext/pg_type_map.c +3 -2
- data/ext/pg_type_map_all_strings.c +2 -2
- data/ext/pg_type_map_by_class.c +5 -3
- data/ext/pg_type_map_by_column.c +9 -3
- data/ext/pg_type_map_by_oid.c +7 -4
- data/ext/pg_type_map_in_ruby.c +5 -2
- data/lib/3.1/pg_ext.so +0 -0
- data/lib/3.2/pg_ext.so +0 -0
- data/lib/pg/basic_type_map_based_on_result.rb +21 -1
- data/lib/pg/basic_type_map_for_queries.rb +13 -8
- data/lib/pg/basic_type_map_for_results.rb +26 -3
- data/lib/pg/basic_type_registry.rb +30 -32
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +15 -13
- data/lib/pg/connection.rb +82 -30
- data/lib/pg/exceptions.rb +7 -0
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/version.rb +1 -1
- data/lib/pg.rb +44 -15
- data/lib/x64-mingw-ucrt/libpq.dll +0 -0
- data/pg.gemspec +4 -2
- data/rakelib/task_extension.rb +1 -1
- data/translation/.po4a-version +7 -0
- data/translation/po/all.pot +910 -0
- data/translation/po/ja.po +1047 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +111 -35
- metadata.gz.sig +0 -0
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -233
- data/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
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
|
@@ -74,6 +73,7 @@ VALUE rb_mPGconstants;
|
|
74
73
|
* The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
|
75
74
|
*/
|
76
75
|
const char * const (pg_enc_pg2ruby_mapping[][2]) = {
|
76
|
+
{"UTF8", "UTF-8" },
|
77
77
|
{"BIG5", "Big5" },
|
78
78
|
{"EUC_CN", "GB2312" },
|
79
79
|
{"EUC_JP", "EUC-JP" },
|
@@ -105,7 +105,6 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
|
|
105
105
|
{"SHIFT_JIS_2004","Windows-31J" },
|
106
106
|
/* {"SQL_ASCII", NULL }, special case*/
|
107
107
|
{"UHC", "CP949" },
|
108
|
-
{"UTF8", "UTF-8" },
|
109
108
|
{"WIN866", "IBM866" },
|
110
109
|
{"WIN874", "Windows-874" },
|
111
110
|
{"WIN1250", "Windows-1250"},
|
@@ -120,12 +119,6 @@ const char * const (pg_enc_pg2ruby_mapping[][2]) = {
|
|
120
119
|
};
|
121
120
|
|
122
121
|
|
123
|
-
/*
|
124
|
-
* A cache of mapping from PostgreSQL's encoding indices to Ruby's rb_encoding*s.
|
125
|
-
*/
|
126
|
-
static struct st_table *enc_pg2ruby;
|
127
|
-
|
128
|
-
|
129
122
|
/*
|
130
123
|
* Return the given PostgreSQL encoding ID as an rb_encoding.
|
131
124
|
*
|
@@ -135,21 +128,8 @@ static struct st_table *enc_pg2ruby;
|
|
135
128
|
rb_encoding *
|
136
129
|
pg_get_pg_encoding_as_rb_encoding( int enc_id )
|
137
130
|
{
|
138
|
-
|
139
|
-
|
140
|
-
/* Use the cached value if it exists */
|
141
|
-
if ( st_lookup(enc_pg2ruby, (st_data_t)enc_id, (st_data_t*)&enc) ) {
|
142
|
-
return enc;
|
143
|
-
}
|
144
|
-
else {
|
145
|
-
const char *name = pg_encoding_to_char( enc_id );
|
146
|
-
|
147
|
-
enc = pg_get_pg_encname_as_rb_encoding( name );
|
148
|
-
st_insert( enc_pg2ruby, (st_data_t)enc_id, (st_data_t)enc );
|
149
|
-
|
150
|
-
return enc;
|
151
|
-
}
|
152
|
-
|
131
|
+
const char *name = pg_encoding_to_char( enc_id );
|
132
|
+
return pg_get_pg_encname_as_rb_encoding( name );
|
153
133
|
}
|
154
134
|
|
155
135
|
/*
|
@@ -354,6 +334,11 @@ pg_s_init_ssl(VALUE self, VALUE do_ssl)
|
|
354
334
|
void
|
355
335
|
Init_pg_ext(void)
|
356
336
|
{
|
337
|
+
|
338
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
339
|
+
rb_ext_ractor_safe(PQisthreadsafe());
|
340
|
+
#endif
|
341
|
+
|
357
342
|
if( RTEST(rb_eval_string("ENV['PG_SKIP_DEPRECATION_WARNING']")) ){
|
358
343
|
/* Set all bits to disable all deprecation warnings. */
|
359
344
|
pg_skip_deprecation_warning = 0xFFFF;
|
@@ -372,8 +357,8 @@ Init_pg_ext(void)
|
|
372
357
|
SINGLETON_ALIAS( rb_mPG, "is_threadsafe?", "isthreadsafe" );
|
373
358
|
SINGLETON_ALIAS( rb_mPG, "threadsafe?", "isthreadsafe" );
|
374
359
|
|
375
|
-
|
376
|
-
|
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 );
|
377
362
|
|
378
363
|
|
379
364
|
/****** PG::Connection CLASS CONSTANTS: Connection Status ******/
|
@@ -685,8 +670,6 @@ Init_pg_ext(void)
|
|
685
670
|
/* Add the constants to the toplevel namespace */
|
686
671
|
rb_include_module( rb_mPG, rb_mPGconstants );
|
687
672
|
|
688
|
-
enc_pg2ruby = st_init_numtable();
|
689
|
-
|
690
673
|
/* Initialize the main extension classes */
|
691
674
|
init_pg_connection();
|
692
675
|
init_pg_result();
|
@@ -707,4 +690,3 @@ Init_pg_ext(void)
|
|
707
690
|
init_pg_recordcoder();
|
708
691
|
init_pg_tuple();
|
709
692
|
}
|
710
|
-
|
data/ext/pg.h
CHANGED
@@ -76,10 +76,6 @@ typedef long suseconds_t;
|
|
76
76
|
#define PG_MAX_COLUMNS 4000
|
77
77
|
#endif
|
78
78
|
|
79
|
-
#ifndef RARRAY_AREF
|
80
|
-
#define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
|
81
|
-
#endif
|
82
|
-
|
83
79
|
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
84
80
|
#define pg_compact_callback(x) (x)
|
85
81
|
#define pg_gc_location(x) x = rb_gc_location(x)
|
@@ -89,6 +85,12 @@ typedef long suseconds_t;
|
|
89
85
|
#define pg_gc_location(x) UNUSED(x)
|
90
86
|
#endif
|
91
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
|
92
94
|
#define PG_ENC_IDX_BITS 28
|
93
95
|
|
94
96
|
/* The data behind each PG::Connection object */
|
@@ -97,6 +99,9 @@ typedef struct {
|
|
97
99
|
|
98
100
|
/* Cached IO object for the socket descriptor */
|
99
101
|
VALUE socket_io;
|
102
|
+
/* function pointers of the original libpq notice receivers */
|
103
|
+
PQnoticeReceiver default_notice_receiver;
|
104
|
+
PQnoticeProcessor default_notice_processor;
|
100
105
|
/* Proc object that receives notices as PG::Result objects */
|
101
106
|
VALUE notice_receiver;
|
102
107
|
/* Proc object that receives notices as String objects */
|
@@ -314,7 +319,7 @@ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, c
|
|
314
319
|
int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
|
315
320
|
t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
|
316
321
|
t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
|
317
|
-
|
322
|
+
VALUE pg_define_coder _(( const char *, void *, VALUE, VALUE ));
|
318
323
|
VALUE pg_obj_to_i _(( VALUE ));
|
319
324
|
VALUE pg_tmbc_allocate _(( void ));
|
320
325
|
void pg_coder_init_encoder _(( VALUE ));
|
data/ext/pg_binary_decoder.c
CHANGED
@@ -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
|
*
|
@@ -209,6 +287,7 @@ 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 ); */
|
data/ext/pg_binary_encoder.c
CHANGED
@@ -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
|
*
|
@@ -141,6 +353,10 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
|
|
141
353
|
void
|
142
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(void)
|
|
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 );
|
data/ext/pg_coder.c
CHANGED
@@ -35,7 +35,7 @@ pg_coder_init_encoder( VALUE self )
|
|
35
35
|
this->enc_func = NULL;
|
36
36
|
}
|
37
37
|
this->dec_func = NULL;
|
38
|
-
this->coder_obj
|
38
|
+
RB_OBJ_WRITE(self, &this->coder_obj, self);
|
39
39
|
this->oid = 0;
|
40
40
|
this->format = 0;
|
41
41
|
this->flags = 0;
|
@@ -54,7 +54,7 @@ pg_coder_init_decoder( VALUE self )
|
|
54
54
|
} else {
|
55
55
|
this->dec_func = NULL;
|
56
56
|
}
|
57
|
-
this->coder_obj
|
57
|
+
RB_OBJ_WRITE(self, &this->coder_obj, self);
|
58
58
|
this->oid = 0;
|
59
59
|
this->format = 0;
|
60
60
|
this->flags = 0;
|
@@ -99,7 +99,9 @@ const rb_data_type_t pg_coder_type = {
|
|
99
99
|
},
|
100
100
|
0,
|
101
101
|
0,
|
102
|
-
|
102
|
+
// IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
|
103
|
+
// macro to update VALUE references, as to trigger write barriers.
|
104
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
103
105
|
};
|
104
106
|
|
105
107
|
static VALUE
|
@@ -121,7 +123,7 @@ static const rb_data_type_t pg_composite_coder_type = {
|
|
121
123
|
},
|
122
124
|
&pg_coder_type,
|
123
125
|
0,
|
124
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
126
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
125
127
|
};
|
126
128
|
|
127
129
|
static VALUE
|
@@ -273,6 +275,7 @@ static VALUE
|
|
273
275
|
pg_coder_oid_set(VALUE self, VALUE oid)
|
274
276
|
{
|
275
277
|
t_pg_coder *this = RTYPEDDATA_DATA(self);
|
278
|
+
rb_check_frozen(self);
|
276
279
|
this->oid = NUM2UINT(oid);
|
277
280
|
return oid;
|
278
281
|
}
|
@@ -304,6 +307,7 @@ static VALUE
|
|
304
307
|
pg_coder_format_set(VALUE self, VALUE format)
|
305
308
|
{
|
306
309
|
t_pg_coder *this = RTYPEDDATA_DATA(self);
|
310
|
+
rb_check_frozen(self);
|
307
311
|
this->format = NUM2INT(format);
|
308
312
|
return format;
|
309
313
|
}
|
@@ -335,6 +339,7 @@ static VALUE
|
|
335
339
|
pg_coder_flags_set(VALUE self, VALUE flags)
|
336
340
|
{
|
337
341
|
t_pg_coder *this = RTYPEDDATA_DATA(self);
|
342
|
+
rb_check_frozen(self);
|
338
343
|
this->flags = NUM2INT(flags);
|
339
344
|
return flags;
|
340
345
|
}
|
@@ -366,6 +371,7 @@ static VALUE
|
|
366
371
|
pg_coder_needs_quotation_set(VALUE self, VALUE needs_quotation)
|
367
372
|
{
|
368
373
|
t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
|
374
|
+
rb_check_frozen(self);
|
369
375
|
this->needs_quotation = RTEST(needs_quotation);
|
370
376
|
return needs_quotation;
|
371
377
|
}
|
@@ -396,6 +402,7 @@ static VALUE
|
|
396
402
|
pg_coder_delimiter_set(VALUE self, VALUE delimiter)
|
397
403
|
{
|
398
404
|
t_pg_composite_coder *this = RTYPEDDATA_DATA(self);
|
405
|
+
rb_check_frozen(self);
|
399
406
|
StringValue(delimiter);
|
400
407
|
if(RSTRING_LEN(delimiter) != 1)
|
401
408
|
rb_raise( rb_eArgError, "delimiter size must be one byte");
|
@@ -430,6 +437,7 @@ pg_coder_elements_type_set(VALUE self, VALUE elem_type)
|
|
430
437
|
{
|
431
438
|
t_pg_composite_coder *this = RTYPEDDATA_DATA( self );
|
432
439
|
|
440
|
+
rb_check_frozen(self);
|
433
441
|
if ( NIL_P(elem_type) ){
|
434
442
|
this->elem = NULL;
|
435
443
|
} else if ( rb_obj_is_kind_of(elem_type, rb_cPG_Coder) ){
|
@@ -452,10 +460,10 @@ static const rb_data_type_t pg_coder_cfunc_type = {
|
|
452
460
|
},
|
453
461
|
0,
|
454
462
|
0,
|
455
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
463
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
456
464
|
};
|
457
465
|
|
458
|
-
|
466
|
+
VALUE
|
459
467
|
pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
|
460
468
|
{
|
461
469
|
VALUE cfunc_obj = TypedData_Wrap_Struct( rb_cObject, &pg_coder_cfunc_type, func );
|
@@ -468,9 +476,10 @@ pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
|
|
468
476
|
if( nsp==rb_mPG_BinaryDecoder || nsp==rb_mPG_TextDecoder )
|
469
477
|
rb_define_method( coder_klass, "decode", pg_coder_decode, -1 );
|
470
478
|
|
471
|
-
rb_define_const( coder_klass, "CFUNC", cfunc_obj );
|
479
|
+
rb_define_const( coder_klass, "CFUNC", rb_obj_freeze(cfunc_obj) );
|
472
480
|
|
473
481
|
RB_GC_GUARD(cfunc_obj);
|
482
|
+
return coder_klass;
|
474
483
|
}
|
475
484
|
|
476
485
|
|