pg 0.18.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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +42 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +117 -0
- data/.github/workflows/source-gem.yml +137 -0
- data/.gitignore +22 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/BSDL +2 -2
- data/Gemfile +14 -0
- data/History.md +876 -0
- data/Manifest.txt +8 -21
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +38 -141
- data/Rakefile.cross +69 -72
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +113 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +36 -2
- data/ext/extconf.rb +119 -54
- data/ext/gvl_wrappers.c +8 -0
- data/ext/gvl_wrappers.h +44 -33
- data/ext/pg.c +226 -200
- data/ext/pg.h +99 -99
- data/ext/pg_binary_decoder.c +162 -16
- data/ext/pg_binary_encoder.c +245 -20
- data/ext/pg_coder.c +189 -44
- data/ext/pg_connection.c +1865 -1172
- data/ext/pg_copy_coder.c +398 -42
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +727 -232
- data/ext/pg_text_decoder.c +627 -43
- data/ext/pg_text_encoder.c +266 -102
- data/ext/pg_tuple.c +572 -0
- data/ext/pg_type_map.c +58 -17
- data/ext/pg_type_map_all_strings.c +21 -7
- data/ext/pg_type_map_by_class.c +59 -27
- data/ext/pg_type_map_by_column.c +80 -37
- data/ext/pg_type_map_by_mri_type.c +49 -20
- data/ext/pg_type_map_by_oid.c +62 -29
- data/ext/pg_type_map_in_ruby.c +56 -22
- data/ext/{util.c → pg_util.c} +12 -12
- data/ext/{util.h → pg_util.h} +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -0
- 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 +36 -13
- data/lib/pg/connection.rb +797 -77
- data/lib/pg/exceptions.rb +16 -2
- data/lib/pg/result.rb +24 -7
- 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/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +3 -2
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +106 -41
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +34 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +1 -1
- data/sample/async_api.rb +4 -8
- data/sample/async_copyto.rb +1 -1
- data/sample/async_mixed.rb +1 -1
- data/sample/check_conn.rb +1 -1
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +1 -1
- data/sample/copyto.rb +1 -1
- data/sample/cursor.rb +1 -1
- data/sample/disk_usage_report.rb +6 -15
- data/sample/issue-119.rb +2 -2
- data/sample/losample.rb +1 -1
- data/sample/minimal-testcase.rb +2 -2
- data/sample/notify_wait.rb +1 -1
- data/sample/pg_statistics.rb +6 -15
- data/sample/replication_monitor.rb +9 -18
- data/sample/test_binary_values.rb +1 -1
- data/sample/wal_shipper.rb +2 -2
- data/sample/warehouse_partitions.rb +8 -17
- 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 +136 -213
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -5911
- data/History.rdoc +0 -338
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -164
- data/lib/pg/basic_type_mapping.rb +0 -399
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -44
- data/lib/pg/text_encoder.rb +0 -27
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -355
- data/spec/pg/basic_type_mapping_spec.rb +0 -251
- data/spec/pg/connection_spec.rb +0 -1544
- data/spec/pg/result_spec.rb +0 -449
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -697
- data/spec/pg_spec.rb +0 -50
data/ext/pg_text_decoder.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_text_decoder.c - PG::TextDecoder module
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -12,13 +12,13 @@
|
|
|
12
12
|
* assigns a decoder function.
|
|
13
13
|
*
|
|
14
14
|
* Signature of all type cast decoders is:
|
|
15
|
-
* VALUE decoder_function(t_pg_coder *this, char *val, int len, int tuple, int field, int enc_idx)
|
|
15
|
+
* VALUE decoder_function(t_pg_coder *this, const char *val, int len, int tuple, int field, int enc_idx)
|
|
16
16
|
*
|
|
17
17
|
* Params:
|
|
18
18
|
* this - The data part of the coder object that belongs to the decoder function.
|
|
19
|
-
* val, len - The text or binary data to decode.
|
|
20
|
-
*
|
|
21
|
-
* only by the callee.
|
|
19
|
+
* val, len - The text or binary data to decode.
|
|
20
|
+
* The caller ensures, that text data (format=0) is zero terminated so that val[len]=0.
|
|
21
|
+
* The memory should be used read-only by the callee.
|
|
22
22
|
* tuple - Row of the value within the result set.
|
|
23
23
|
* field - Column of the value within the result set.
|
|
24
24
|
* enc_idx - Index of the Encoding that any output String should get assigned.
|
|
@@ -28,15 +28,38 @@
|
|
|
28
28
|
*
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
+
#include "ruby/version.h"
|
|
31
32
|
#include "pg.h"
|
|
32
|
-
#include "
|
|
33
|
+
#include "pg_util.h"
|
|
33
34
|
#ifdef HAVE_INTTYPES_H
|
|
34
35
|
#include <inttypes.h>
|
|
35
36
|
#endif
|
|
37
|
+
#include <ctype.h>
|
|
38
|
+
#include <time.h>
|
|
39
|
+
#if !defined(_WIN32)
|
|
40
|
+
#include <arpa/inet.h>
|
|
41
|
+
#include <sys/socket.h>
|
|
42
|
+
#endif
|
|
43
|
+
#include <string.h>
|
|
36
44
|
|
|
37
45
|
VALUE rb_mPG_TextDecoder;
|
|
38
|
-
static ID
|
|
39
|
-
|
|
46
|
+
static ID s_id_Rational;
|
|
47
|
+
static ID s_id_new;
|
|
48
|
+
static ID s_id_utc;
|
|
49
|
+
static ID s_id_getlocal;
|
|
50
|
+
static ID s_id_BigDecimal;
|
|
51
|
+
|
|
52
|
+
static VALUE s_IPAddr;
|
|
53
|
+
static VALUE s_vmasks4;
|
|
54
|
+
static VALUE s_vmasks6;
|
|
55
|
+
static VALUE s_nan, s_pos_inf, s_neg_inf;
|
|
56
|
+
static int use_ipaddr_alloc;
|
|
57
|
+
static ID s_id_lshift;
|
|
58
|
+
static ID s_id_add;
|
|
59
|
+
static ID s_id_mask;
|
|
60
|
+
static ID s_ivar_family;
|
|
61
|
+
static ID s_ivar_addr;
|
|
62
|
+
static ID s_ivar_mask_addr;
|
|
40
63
|
|
|
41
64
|
/*
|
|
42
65
|
* Document-class: PG::TextDecoder::Boolean < PG::SimpleDecoder
|
|
@@ -46,7 +69,7 @@ static ID s_id_decode;
|
|
|
46
69
|
*
|
|
47
70
|
*/
|
|
48
71
|
static VALUE
|
|
49
|
-
pg_text_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
72
|
+
pg_text_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
50
73
|
{
|
|
51
74
|
if (len < 1) {
|
|
52
75
|
rb_raise( rb_eTypeError, "wrong data for text boolean converter in tuple %d field %d", tuple, field);
|
|
@@ -63,9 +86,9 @@ pg_text_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field,
|
|
|
63
86
|
*
|
|
64
87
|
*/
|
|
65
88
|
VALUE
|
|
66
|
-
pg_text_dec_string(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
89
|
+
pg_text_dec_string(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
67
90
|
{
|
|
68
|
-
VALUE ret =
|
|
91
|
+
VALUE ret = rb_str_new( val, len );
|
|
69
92
|
PG_ENCODING_SET_NOCHECK( ret, enc_idx );
|
|
70
93
|
return ret;
|
|
71
94
|
}
|
|
@@ -78,7 +101,7 @@ pg_text_dec_string(t_pg_coder *conv, char *val, int len, int tuple, int field, i
|
|
|
78
101
|
*
|
|
79
102
|
*/
|
|
80
103
|
static VALUE
|
|
81
|
-
pg_text_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
104
|
+
pg_text_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
82
105
|
{
|
|
83
106
|
long i;
|
|
84
107
|
int max_len;
|
|
@@ -103,7 +126,7 @@ pg_text_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field,
|
|
|
103
126
|
* conn.exec("select generate_series(1,1000000)").values }
|
|
104
127
|
* end
|
|
105
128
|
*/
|
|
106
|
-
char *val_pos = val;
|
|
129
|
+
const char *val_pos = val;
|
|
107
130
|
char digit = *val_pos;
|
|
108
131
|
int neg;
|
|
109
132
|
int error = 0;
|
|
@@ -134,6 +157,32 @@ pg_text_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field,
|
|
|
134
157
|
return rb_cstr2inum(val, 10);
|
|
135
158
|
}
|
|
136
159
|
|
|
160
|
+
/*
|
|
161
|
+
* Document-class: PG::TextDecoder::Numeric < PG::SimpleDecoder
|
|
162
|
+
*
|
|
163
|
+
* This is a decoder class for conversion of PostgreSQL numeric types
|
|
164
|
+
* to Ruby BigDecimal objects.
|
|
165
|
+
*
|
|
166
|
+
*/
|
|
167
|
+
static VALUE
|
|
168
|
+
pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
169
|
+
{
|
|
170
|
+
return rb_funcall(rb_cObject, s_id_BigDecimal, 1, rb_str_new(val, len));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* called per autoload when TextDecoder::Numeric is used */
|
|
174
|
+
static VALUE
|
|
175
|
+
init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
|
|
176
|
+
{
|
|
177
|
+
rb_require("bigdecimal");
|
|
178
|
+
s_id_BigDecimal = rb_intern("BigDecimal");
|
|
179
|
+
|
|
180
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
|
181
|
+
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
182
|
+
|
|
183
|
+
return Qnil;
|
|
184
|
+
}
|
|
185
|
+
|
|
137
186
|
/*
|
|
138
187
|
* Document-class: PG::TextDecoder::Float < PG::SimpleDecoder
|
|
139
188
|
*
|
|
@@ -142,9 +191,37 @@ pg_text_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field,
|
|
|
142
191
|
*
|
|
143
192
|
*/
|
|
144
193
|
static VALUE
|
|
145
|
-
pg_text_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
194
|
+
pg_text_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
146
195
|
{
|
|
147
|
-
|
|
196
|
+
switch(*val) {
|
|
197
|
+
case 'N':
|
|
198
|
+
return s_nan;
|
|
199
|
+
case 'I':
|
|
200
|
+
return s_pos_inf;
|
|
201
|
+
case '-':
|
|
202
|
+
if (val[1] == 'I') {
|
|
203
|
+
return s_neg_inf;
|
|
204
|
+
} else {
|
|
205
|
+
return rb_float_new(rb_cstr_to_dbl(val, Qfalse));
|
|
206
|
+
}
|
|
207
|
+
default:
|
|
208
|
+
return rb_float_new(rb_cstr_to_dbl(val, Qfalse));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
struct pg_blob_initialization {
|
|
213
|
+
char *blob_string;
|
|
214
|
+
size_t length;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
static VALUE pg_create_blob(VALUE v) {
|
|
218
|
+
struct pg_blob_initialization *bi = (struct pg_blob_initialization *)v;
|
|
219
|
+
return rb_str_new(bi->blob_string, bi->length);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
static VALUE pg_pq_freemem(VALUE mem) {
|
|
223
|
+
PQfreemem((void *)mem);
|
|
224
|
+
return Qfalse;
|
|
148
225
|
}
|
|
149
226
|
|
|
150
227
|
/*
|
|
@@ -155,18 +232,54 @@ pg_text_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, in
|
|
|
155
232
|
*
|
|
156
233
|
*/
|
|
157
234
|
static VALUE
|
|
158
|
-
pg_text_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
235
|
+
pg_text_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
159
236
|
{
|
|
160
|
-
|
|
161
|
-
size_t to_len;
|
|
162
|
-
VALUE ret;
|
|
237
|
+
struct pg_blob_initialization bi;
|
|
163
238
|
|
|
164
|
-
|
|
239
|
+
bi.blob_string = (char *)PQunescapeBytea((unsigned char*)val, &bi.length);
|
|
240
|
+
if (bi.blob_string == NULL) {
|
|
241
|
+
rb_raise(rb_eNoMemError, "PQunescapeBytea failure: probably not enough memory");
|
|
242
|
+
}
|
|
243
|
+
return rb_ensure(pg_create_blob, (VALUE)&bi, pg_pq_freemem, (VALUE)bi.blob_string);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/*
|
|
247
|
+
* array_isspace() --- a non-locale-dependent isspace()
|
|
248
|
+
*
|
|
249
|
+
* We used to use isspace() for parsing array values, but that has
|
|
250
|
+
* undesirable results: an array value might be silently interpreted
|
|
251
|
+
* differently depending on the locale setting. Now we just hard-wire
|
|
252
|
+
* the traditional ASCII definition of isspace().
|
|
253
|
+
*/
|
|
254
|
+
static int
|
|
255
|
+
array_isspace(char ch)
|
|
256
|
+
{
|
|
257
|
+
if (ch == ' ' ||
|
|
258
|
+
ch == '\t' ||
|
|
259
|
+
ch == '\n' ||
|
|
260
|
+
ch == '\r' ||
|
|
261
|
+
ch == '\v' ||
|
|
262
|
+
ch == '\f')
|
|
263
|
+
return 1;
|
|
264
|
+
return 0;
|
|
265
|
+
}
|
|
165
266
|
|
|
166
|
-
|
|
167
|
-
|
|
267
|
+
static int
|
|
268
|
+
array_isdim(char ch)
|
|
269
|
+
{
|
|
270
|
+
if ( (ch >= '0' && ch <= '9') ||
|
|
271
|
+
(ch == '-') ||
|
|
272
|
+
(ch == '+') ||
|
|
273
|
+
(ch == ':') )
|
|
274
|
+
return 1;
|
|
275
|
+
return 0;
|
|
276
|
+
}
|
|
168
277
|
|
|
169
|
-
|
|
278
|
+
static void
|
|
279
|
+
array_parser_error(t_pg_composite_coder *this, const char *text){
|
|
280
|
+
if( (this->comp.flags & PG_CODER_FORMAT_ERROR_MASK) == PG_CODER_FORMAT_ERROR_TO_RAISE ){
|
|
281
|
+
rb_raise( rb_eTypeError, "%s", text );
|
|
282
|
+
}
|
|
170
283
|
}
|
|
171
284
|
|
|
172
285
|
/*
|
|
@@ -174,7 +287,7 @@ pg_text_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, in
|
|
|
174
287
|
* https://github.com/dockyard/pg_array_parser
|
|
175
288
|
*/
|
|
176
289
|
static VALUE
|
|
177
|
-
|
|
290
|
+
read_array_without_dim(t_pg_composite_coder *this, int *index, const char *c_pg_array_string, int array_string_length, char *word, int enc_idx, int tuple, int field, t_pg_coder_dec_func dec_func)
|
|
178
291
|
{
|
|
179
292
|
/* Return value: array */
|
|
180
293
|
VALUE array;
|
|
@@ -198,7 +311,7 @@ read_array(t_pg_composite_coder *this, int *index, char *c_pg_array_string, int
|
|
|
198
311
|
|
|
199
312
|
/* Special case the empty array, so it doesn't need to be handled manually inside
|
|
200
313
|
* the loop. */
|
|
201
|
-
if(((*index) < array_string_length) && c_pg_array_string[
|
|
314
|
+
if(((*index) < array_string_length) && c_pg_array_string[*index] == '}')
|
|
202
315
|
{
|
|
203
316
|
return array;
|
|
204
317
|
}
|
|
@@ -238,10 +351,17 @@ read_array(t_pg_composite_coder *this, int *index, char *c_pg_array_string, int
|
|
|
238
351
|
}
|
|
239
352
|
else if(c == '{')
|
|
240
353
|
{
|
|
354
|
+
VALUE subarray;
|
|
241
355
|
(*index)++;
|
|
242
|
-
|
|
356
|
+
subarray = read_array_without_dim(this, index, c_pg_array_string, array_string_length, word, enc_idx, tuple, field, dec_func);
|
|
357
|
+
rb_ary_push(array, subarray);
|
|
243
358
|
escapeNext = 1;
|
|
244
359
|
}
|
|
360
|
+
else if(c == 0)
|
|
361
|
+
{
|
|
362
|
+
array_parser_error( this, "premature end of the array string" );
|
|
363
|
+
return array;
|
|
364
|
+
}
|
|
245
365
|
else
|
|
246
366
|
{
|
|
247
367
|
word[word_index] = c;
|
|
@@ -268,30 +388,112 @@ read_array(t_pg_composite_coder *this, int *index, char *c_pg_array_string, int
|
|
|
268
388
|
}
|
|
269
389
|
}
|
|
270
390
|
|
|
391
|
+
array_parser_error( this, "premature end of the array string" );
|
|
271
392
|
return array;
|
|
272
393
|
}
|
|
273
394
|
|
|
274
395
|
/*
|
|
275
396
|
* Document-class: PG::TextDecoder::Array < PG::CompositeDecoder
|
|
276
397
|
*
|
|
277
|
-
* This is
|
|
398
|
+
* This is a decoder class for PostgreSQL array types.
|
|
399
|
+
*
|
|
400
|
+
* It returns an Array with possibly an arbitrary number of sub-Arrays.
|
|
401
|
+
* All values are decoded according to the #elements_type accessor.
|
|
402
|
+
* Sub-arrays are decoded recursively.
|
|
278
403
|
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
404
|
+
* This decoder simply ignores any dimension decorations preceding the array values.
|
|
405
|
+
* It returns all array values as regular ruby Array with a zero based index, regardless of the index given in the dimension decoration.
|
|
406
|
+
*
|
|
407
|
+
* An array decoder which respects dimension decorations is waiting to be implemented.
|
|
281
408
|
*
|
|
282
409
|
*/
|
|
283
410
|
static VALUE
|
|
284
|
-
pg_text_dec_array(t_pg_coder *conv, char *
|
|
411
|
+
pg_text_dec_array(t_pg_coder *conv, const char *c_pg_array_string, int array_string_length, int tuple, int field, int enc_idx)
|
|
285
412
|
{
|
|
413
|
+
int index = 0;
|
|
414
|
+
int ndim = 0;
|
|
415
|
+
VALUE ret;
|
|
286
416
|
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
|
287
|
-
|
|
288
|
-
/*
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
417
|
+
|
|
418
|
+
/*
|
|
419
|
+
* If the input string starts with dimension info, read and use that.
|
|
420
|
+
* Otherwise, we require the input to be in curly-brace style, and we
|
|
421
|
+
* prescan the input to determine dimensions.
|
|
422
|
+
*
|
|
423
|
+
* Dimension info takes the form of one or more [n] or [m:n] items. The
|
|
424
|
+
* outer loop iterates once per dimension item.
|
|
425
|
+
*/
|
|
426
|
+
for (;;)
|
|
427
|
+
{
|
|
428
|
+
/*
|
|
429
|
+
* Note: we currently allow whitespace between, but not within,
|
|
430
|
+
* dimension items.
|
|
431
|
+
*/
|
|
432
|
+
while (array_isspace(c_pg_array_string[index]))
|
|
433
|
+
index++;
|
|
434
|
+
if (c_pg_array_string[index] != '[')
|
|
435
|
+
break; /* no more dimension items */
|
|
436
|
+
index++;
|
|
437
|
+
|
|
438
|
+
while (array_isdim(c_pg_array_string[index]))
|
|
439
|
+
index++;
|
|
440
|
+
|
|
441
|
+
if (c_pg_array_string[index] != ']'){
|
|
442
|
+
array_parser_error( this, "missing \"]\" in array dimensions");
|
|
443
|
+
break;
|
|
444
|
+
}
|
|
445
|
+
index++;
|
|
446
|
+
|
|
447
|
+
ndim++;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (ndim == 0)
|
|
451
|
+
{
|
|
452
|
+
/* No array dimensions */
|
|
453
|
+
}
|
|
454
|
+
else
|
|
455
|
+
{
|
|
456
|
+
/* If array dimensions are given, expect '=' operator */
|
|
457
|
+
if (c_pg_array_string[index] != '=') {
|
|
458
|
+
array_parser_error( this, "missing assignment operator");
|
|
459
|
+
index-=2; /* jump back to before "]" so that we don't break behavior to pg < 1.1 */
|
|
460
|
+
}
|
|
461
|
+
index++;
|
|
462
|
+
|
|
463
|
+
while (array_isspace(c_pg_array_string[index]))
|
|
464
|
+
index++;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (c_pg_array_string[index] != '{')
|
|
468
|
+
array_parser_error( this, "array value must start with \"{\" or dimension information");
|
|
469
|
+
index++;
|
|
470
|
+
|
|
471
|
+
if ( index < array_string_length && c_pg_array_string[index] == '}' ) {
|
|
472
|
+
/* avoid buffer allocation for empty array */
|
|
473
|
+
ret = rb_ary_new();
|
|
474
|
+
} else {
|
|
475
|
+
t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, 0);
|
|
476
|
+
/* create a buffer of the same length, as that will be the worst case */
|
|
477
|
+
VALUE buf = rb_str_new(NULL, array_string_length);
|
|
478
|
+
char *word = RSTRING_PTR(buf);
|
|
479
|
+
|
|
480
|
+
ret = read_array_without_dim(this, &index, c_pg_array_string, array_string_length, word, enc_idx, tuple, field, dec_func);
|
|
481
|
+
|
|
482
|
+
RB_GC_GUARD(buf);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (c_pg_array_string[index] != '}' )
|
|
486
|
+
array_parser_error( this, "array value must end with \"}\"");
|
|
487
|
+
index++;
|
|
488
|
+
|
|
489
|
+
/* only whitespace is allowed after the closing brace */
|
|
490
|
+
for(;index < array_string_length; ++index)
|
|
491
|
+
{
|
|
492
|
+
if (!array_isspace(c_pg_array_string[index]))
|
|
493
|
+
array_parser_error( this, "malformed array literal: Junk after closing right brace.");
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
return ret;
|
|
295
497
|
}
|
|
296
498
|
|
|
297
499
|
/*
|
|
@@ -305,7 +507,7 @@ pg_text_dec_array(t_pg_coder *conv, char *val, int len, int tuple, int field, in
|
|
|
305
507
|
*
|
|
306
508
|
*/
|
|
307
509
|
static VALUE
|
|
308
|
-
pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
510
|
+
pg_text_dec_identifier(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
309
511
|
{
|
|
310
512
|
/* Return value: array */
|
|
311
513
|
VALUE array;
|
|
@@ -367,13 +569,13 @@ pg_text_dec_identifier(t_pg_coder *conv, char *val, int len, int tuple, int fiel
|
|
|
367
569
|
*
|
|
368
570
|
*/
|
|
369
571
|
static VALUE
|
|
370
|
-
pg_text_dec_from_base64(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
|
572
|
+
pg_text_dec_from_base64(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
371
573
|
{
|
|
372
574
|
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
|
373
575
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
|
|
374
576
|
int decoded_len;
|
|
375
577
|
/* create a buffer of the expected decoded length */
|
|
376
|
-
VALUE out_value =
|
|
578
|
+
VALUE out_value = rb_str_new(NULL, BASE64_DECODED_SIZE(len));
|
|
377
579
|
|
|
378
580
|
decoded_len = base64_decode( RSTRING_PTR(out_value), val, len );
|
|
379
581
|
rb_str_set_len(out_value, decoded_len);
|
|
@@ -392,13 +594,393 @@ pg_text_dec_from_base64(t_pg_coder *conv, char *val, int len, int tuple, int fie
|
|
|
392
594
|
return out_value;
|
|
393
595
|
}
|
|
394
596
|
|
|
597
|
+
static inline int char_to_digit(char c)
|
|
598
|
+
{
|
|
599
|
+
return c - '0';
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
static int str2_to_int(const char *str)
|
|
603
|
+
{
|
|
604
|
+
return char_to_digit(str[0]) * 10
|
|
605
|
+
+ char_to_digit(str[1]);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
static int parse_year(const char **str) {
|
|
609
|
+
int year = 0;
|
|
610
|
+
int i;
|
|
611
|
+
const char * p = *str;
|
|
612
|
+
|
|
613
|
+
for(i = 0; isdigit(*p) && i < 7; i++, p++) {
|
|
614
|
+
year = 10 * year + char_to_digit(*p);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
*str = p;
|
|
618
|
+
return year;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
#define TZ_NEG 1
|
|
622
|
+
#define TZ_POS 2
|
|
623
|
+
|
|
624
|
+
/*
|
|
625
|
+
* Document-class: PG::TextDecoder::Timestamp < PG::SimpleDecoder
|
|
626
|
+
*
|
|
627
|
+
* This is a decoder class for conversion of PostgreSQL text timestamps
|
|
628
|
+
* to Ruby Time objects.
|
|
629
|
+
*
|
|
630
|
+
* The following flags can be used to specify time interpretation when no timezone is given:
|
|
631
|
+
* * +PG::Coder::TIMESTAMP_DB_UTC+ : Interpret timestamp as UTC time (default)
|
|
632
|
+
* * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Interpret timestamp as local time
|
|
633
|
+
* * +PG::Coder::TIMESTAMP_APP_UTC+ : Return timestamp as UTC time (default)
|
|
634
|
+
* * +PG::Coder::TIMESTAMP_APP_LOCAL+ : Return timestamp as local time
|
|
635
|
+
*
|
|
636
|
+
* Example:
|
|
637
|
+
* deco = PG::TextDecoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL)
|
|
638
|
+
* deco.decode("2000-01-01 00:00:00") # => 2000-01-01 01:00:00 +0100
|
|
639
|
+
* deco.decode("2000-01-01 00:00:00.123-06") # => 2000-01-01 00:00:00 -0600
|
|
640
|
+
*/
|
|
641
|
+
static VALUE pg_text_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
642
|
+
{
|
|
643
|
+
const char *str = val;
|
|
644
|
+
int year, mon, day;
|
|
645
|
+
int hour, min, sec;
|
|
646
|
+
int nsec = 0;
|
|
647
|
+
int tz_given = 0;
|
|
648
|
+
int tz_hour = 0;
|
|
649
|
+
int tz_min = 0;
|
|
650
|
+
int tz_sec = 0;
|
|
651
|
+
|
|
652
|
+
year = parse_year(&str);
|
|
653
|
+
|
|
654
|
+
if ( year > 0
|
|
655
|
+
&& str[0] == '-' && isdigit(str[1]) && isdigit(str[2])
|
|
656
|
+
&& str[3] == '-' && isdigit(str[4]) && isdigit(str[5])
|
|
657
|
+
&& str[6] == ' ' && isdigit(str[7]) && isdigit(str[8])
|
|
658
|
+
&& str[9] == ':' && isdigit(str[10]) && isdigit(str[11])
|
|
659
|
+
&& str[12] == ':' && isdigit(str[13]) && isdigit(str[14])
|
|
660
|
+
) {
|
|
661
|
+
|
|
662
|
+
mon = str2_to_int(str+1); str += 3;
|
|
663
|
+
day = str2_to_int(str+1); str += 3;
|
|
664
|
+
hour = str2_to_int(str+1); str += 3;
|
|
665
|
+
min = str2_to_int(str+1); str += 3;
|
|
666
|
+
sec = str2_to_int(str+1); str += 3;
|
|
667
|
+
|
|
668
|
+
if (str[0] == '.' && isdigit(str[1])) {
|
|
669
|
+
/* nano second part, up to 9 digits */
|
|
670
|
+
static const int coef[9] = {
|
|
671
|
+
100000000, 10000000, 1000000,
|
|
672
|
+
100000, 10000, 1000, 100, 10, 1
|
|
673
|
+
};
|
|
674
|
+
int i;
|
|
675
|
+
|
|
676
|
+
str++;
|
|
677
|
+
for (i = 0; i < 9 && isdigit(*str); i++)
|
|
678
|
+
{
|
|
679
|
+
nsec += coef[i] * char_to_digit(*str++);
|
|
680
|
+
}
|
|
681
|
+
/* consume digits smaller than nsec */
|
|
682
|
+
while(isdigit(*str)) str++;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
if ((str[0] == '+' || str[0] == '-') && isdigit(str[1]) && isdigit(str[2])) {
|
|
686
|
+
tz_given = str[0] == '-' ? TZ_NEG : TZ_POS;
|
|
687
|
+
tz_hour = str2_to_int(str+1); str += 3;
|
|
688
|
+
|
|
689
|
+
if (str[0] == ':' && isdigit(str[1]) && isdigit(str[2]))
|
|
690
|
+
{
|
|
691
|
+
tz_min = str2_to_int(str+1); str += 3;
|
|
692
|
+
}
|
|
693
|
+
if (str[0] == ':' && isdigit(str[1]) && isdigit(str[2]))
|
|
694
|
+
{
|
|
695
|
+
tz_sec = str2_to_int(str+1); str += 3;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if (str[0] == ' ' && str[1] == 'B' && str[2] == 'C') {
|
|
700
|
+
year = -year + 1;
|
|
701
|
+
str += 3;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (*str == '\0') { /* must have consumed all the string */
|
|
705
|
+
VALUE sec_value;
|
|
706
|
+
VALUE gmt_offset_value;
|
|
707
|
+
VALUE res;
|
|
708
|
+
|
|
709
|
+
#if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(HAVE_TIMEGM)
|
|
710
|
+
/* Fast path for time conversion */
|
|
711
|
+
struct tm tm;
|
|
712
|
+
struct timespec ts;
|
|
713
|
+
tm.tm_year = year - 1900;
|
|
714
|
+
tm.tm_mon = mon - 1;
|
|
715
|
+
tm.tm_mday = day;
|
|
716
|
+
tm.tm_hour = hour;
|
|
717
|
+
tm.tm_min = min;
|
|
718
|
+
tm.tm_sec = sec;
|
|
719
|
+
tm.tm_isdst = -1;
|
|
720
|
+
|
|
721
|
+
if (tz_given) {
|
|
722
|
+
/* with timezone */
|
|
723
|
+
time_t time = timegm(&tm);
|
|
724
|
+
if (time != -1){
|
|
725
|
+
int gmt_offset;
|
|
726
|
+
|
|
727
|
+
gmt_offset = tz_hour * 3600 + tz_min * 60 + tz_sec;
|
|
728
|
+
if (tz_given == TZ_NEG)
|
|
729
|
+
{
|
|
730
|
+
gmt_offset = - gmt_offset;
|
|
731
|
+
}
|
|
732
|
+
ts.tv_sec = time - gmt_offset;
|
|
733
|
+
ts.tv_nsec = nsec;
|
|
734
|
+
return rb_time_timespec_new(&ts, gmt_offset);
|
|
735
|
+
}
|
|
736
|
+
} else {
|
|
737
|
+
/* without timezone */
|
|
738
|
+
time_t time;
|
|
739
|
+
|
|
740
|
+
if( conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
|
|
741
|
+
time = mktime(&tm);
|
|
742
|
+
} else {
|
|
743
|
+
time = timegm(&tm);
|
|
744
|
+
}
|
|
745
|
+
if (time != -1){
|
|
746
|
+
ts.tv_sec = time;
|
|
747
|
+
ts.tv_nsec = nsec;
|
|
748
|
+
return rb_time_timespec_new(&ts, conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ? INT_MAX : INT_MAX-1);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
/* Some libc implementations fail to convert certain values,
|
|
752
|
+
* so that we fall through to the slow path.
|
|
753
|
+
*/
|
|
754
|
+
#endif
|
|
755
|
+
if (nsec) {
|
|
756
|
+
int sec_numerator = sec * 1000000 + nsec / 1000;
|
|
757
|
+
int sec_denominator = 1000000;
|
|
758
|
+
sec_value = rb_funcall(Qnil, s_id_Rational, 2,
|
|
759
|
+
INT2NUM(sec_numerator), INT2NUM(sec_denominator));
|
|
760
|
+
} else {
|
|
761
|
+
sec_value = INT2NUM(sec);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (tz_given) {
|
|
765
|
+
/* with timezone */
|
|
766
|
+
int gmt_offset;
|
|
767
|
+
|
|
768
|
+
gmt_offset = tz_hour * 3600 + tz_min * 60 + tz_sec;
|
|
769
|
+
if (tz_given == TZ_NEG)
|
|
770
|
+
{
|
|
771
|
+
gmt_offset = - gmt_offset;
|
|
772
|
+
}
|
|
773
|
+
gmt_offset_value = INT2NUM(gmt_offset);
|
|
774
|
+
} else {
|
|
775
|
+
/* without timezone */
|
|
776
|
+
gmt_offset_value = conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ? Qnil : INT2NUM(0);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
res = rb_funcall(rb_cTime, s_id_new, 7,
|
|
780
|
+
INT2NUM(year),
|
|
781
|
+
INT2NUM(mon),
|
|
782
|
+
INT2NUM(day),
|
|
783
|
+
INT2NUM(hour),
|
|
784
|
+
INT2NUM(min),
|
|
785
|
+
sec_value,
|
|
786
|
+
gmt_offset_value);
|
|
787
|
+
|
|
788
|
+
if (tz_given) {
|
|
789
|
+
/* with timezone */
|
|
790
|
+
return res;
|
|
791
|
+
} else {
|
|
792
|
+
/* without timezone */
|
|
793
|
+
if( (conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL) && (conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL) ) {
|
|
794
|
+
return res;
|
|
795
|
+
} else if( conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ) {
|
|
796
|
+
return rb_funcall(res, s_id_getlocal, 0);
|
|
797
|
+
} else {
|
|
798
|
+
return rb_funcall(res, s_id_utc, 0);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/* fall through to string conversion */
|
|
805
|
+
return pg_text_dec_string(conv, val, len, tuple, field, enc_idx);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/*
|
|
809
|
+
* Document-class: PG::TextDecoder::Inet < PG::SimpleDecoder
|
|
810
|
+
*
|
|
811
|
+
* This is a decoder class for conversion of PostgreSQL inet type
|
|
812
|
+
* to Ruby IPAddr values.
|
|
813
|
+
*
|
|
814
|
+
*/
|
|
815
|
+
static VALUE
|
|
816
|
+
pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
817
|
+
{
|
|
818
|
+
VALUE ip;
|
|
819
|
+
#if defined(_WIN32)
|
|
820
|
+
ip = rb_str_new(val, len);
|
|
821
|
+
ip = rb_class_new_instance(1, &ip, s_IPAddr);
|
|
822
|
+
#else
|
|
823
|
+
VALUE ip_int;
|
|
824
|
+
VALUE vmasks;
|
|
825
|
+
char dst[16];
|
|
826
|
+
char buf[64];
|
|
827
|
+
int af = strchr(val, '.') ? AF_INET : AF_INET6;
|
|
828
|
+
int mask = -1;
|
|
829
|
+
|
|
830
|
+
if (len >= 64) {
|
|
831
|
+
rb_raise(rb_eTypeError, "too long data for text inet converter in tuple %d field %d", tuple, field);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
if (len >= 4) {
|
|
835
|
+
if (val[len-2] == '/') {
|
|
836
|
+
mask = val[len-1] - '0';
|
|
837
|
+
memcpy(buf, val, len-2);
|
|
838
|
+
buf[len-2] = '\0';
|
|
839
|
+
val = buf;
|
|
840
|
+
} else if (val[len-3] == '/') {
|
|
841
|
+
mask = (val[len-2]- '0')*10 + val[len-1] - '0';
|
|
842
|
+
memcpy(buf, val, len-3);
|
|
843
|
+
buf[len-3] = '\0';
|
|
844
|
+
val = buf;
|
|
845
|
+
} else if (val[len-4] == '/') {
|
|
846
|
+
mask = (val[len-3]- '0')*100 + (val[len-2]- '0')*10 + val[len-1] - '0';
|
|
847
|
+
memcpy(buf, val, len-4);
|
|
848
|
+
buf[len-4] = '\0';
|
|
849
|
+
val = buf;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
if (1 != inet_pton(af, val, dst)) {
|
|
854
|
+
rb_raise(rb_eTypeError, "wrong data for text inet converter in tuple %d field %d val", tuple, field);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
if (af == AF_INET) {
|
|
858
|
+
unsigned int ip_int_native;
|
|
859
|
+
|
|
860
|
+
if (mask == -1) {
|
|
861
|
+
mask = 32;
|
|
862
|
+
} else if (mask < 0 || mask > 32) {
|
|
863
|
+
rb_raise(rb_eTypeError, "invalid mask for IPv4: %d", mask);
|
|
864
|
+
}
|
|
865
|
+
vmasks = s_vmasks4;
|
|
866
|
+
|
|
867
|
+
ip_int_native = read_nbo32(dst);
|
|
868
|
+
|
|
869
|
+
/* Work around broken IPAddr behavior of converting portion
|
|
870
|
+
of address after netmask to 0 */
|
|
871
|
+
switch (mask) {
|
|
872
|
+
case 0:
|
|
873
|
+
ip_int_native = 0;
|
|
874
|
+
break;
|
|
875
|
+
case 32:
|
|
876
|
+
/* nothing to do */
|
|
877
|
+
break;
|
|
878
|
+
default:
|
|
879
|
+
ip_int_native &= ~((1UL<<(32-mask))-1);
|
|
880
|
+
break;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
ip_int = UINT2NUM(ip_int_native);
|
|
884
|
+
} else {
|
|
885
|
+
unsigned long long * dstllp = (unsigned long long *)dst;
|
|
886
|
+
unsigned long long ip_int_native1;
|
|
887
|
+
unsigned long long ip_int_native2;
|
|
888
|
+
|
|
889
|
+
if (mask == -1) {
|
|
890
|
+
mask = 128;
|
|
891
|
+
} else if (mask < 0 || mask > 128) {
|
|
892
|
+
rb_raise(rb_eTypeError, "invalid mask for IPv6: %d", mask);
|
|
893
|
+
}
|
|
894
|
+
vmasks = s_vmasks6;
|
|
895
|
+
|
|
896
|
+
ip_int_native1 = read_nbo64(dstllp);
|
|
897
|
+
dstllp++;
|
|
898
|
+
ip_int_native2 = read_nbo64(dstllp);
|
|
899
|
+
|
|
900
|
+
if (mask == 128) {
|
|
901
|
+
/* nothing to do */
|
|
902
|
+
} else if (mask == 64) {
|
|
903
|
+
ip_int_native2 = 0;
|
|
904
|
+
} else if (mask == 0) {
|
|
905
|
+
ip_int_native1 = 0;
|
|
906
|
+
ip_int_native2 = 0;
|
|
907
|
+
} else if (mask < 64) {
|
|
908
|
+
ip_int_native1 &= ~((1ULL<<(64-mask))-1);
|
|
909
|
+
ip_int_native2 = 0;
|
|
910
|
+
} else {
|
|
911
|
+
ip_int_native2 &= ~((1ULL<<(128-mask))-1);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
/* 4 Bignum allocations */
|
|
915
|
+
ip_int = ULL2NUM(ip_int_native1);
|
|
916
|
+
ip_int = rb_funcall(ip_int, s_id_lshift, 1, INT2NUM(64));
|
|
917
|
+
ip_int = rb_funcall(ip_int, s_id_add, 1, ULL2NUM(ip_int_native2));
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (use_ipaddr_alloc) {
|
|
921
|
+
ip = rb_obj_alloc(s_IPAddr);
|
|
922
|
+
rb_ivar_set(ip, s_ivar_family, INT2NUM(af));
|
|
923
|
+
rb_ivar_set(ip, s_ivar_addr, ip_int);
|
|
924
|
+
rb_ivar_set(ip, s_ivar_mask_addr, RARRAY_AREF(vmasks, mask));
|
|
925
|
+
} else {
|
|
926
|
+
VALUE ip_args[2];
|
|
927
|
+
ip_args[0] = ip_int;
|
|
928
|
+
ip_args[1] = INT2NUM(af);
|
|
929
|
+
ip = rb_class_new_instance(2, ip_args, s_IPAddr);
|
|
930
|
+
ip = rb_funcall(ip, s_id_mask, 1, INT2NUM(mask));
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
#endif
|
|
934
|
+
return ip;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/* called per autoload when TextDecoder::Inet is used */
|
|
938
|
+
static VALUE
|
|
939
|
+
init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
|
|
940
|
+
{
|
|
941
|
+
rb_require("ipaddr");
|
|
942
|
+
s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
|
|
943
|
+
rb_global_variable(&s_IPAddr);
|
|
944
|
+
s_ivar_family = rb_intern("@family");
|
|
945
|
+
s_ivar_addr = rb_intern("@addr");
|
|
946
|
+
s_ivar_mask_addr = rb_intern("@mask_addr");
|
|
947
|
+
s_id_lshift = rb_intern("<<");
|
|
948
|
+
s_id_add = rb_intern("+");
|
|
949
|
+
s_id_mask = rb_intern("mask");
|
|
950
|
+
|
|
951
|
+
use_ipaddr_alloc = RTEST(rb_eval_string("IPAddr.new.instance_variables.sort == [:@addr, :@family, :@mask_addr]"));
|
|
952
|
+
|
|
953
|
+
s_vmasks4 = rb_eval_string("a = [0]*33; a[0] = 0; a[32] = 0xffffffff; 31.downto(1){|i| a[i] = a[i+1] - (1 << (31 - i))}; a.freeze");
|
|
954
|
+
rb_global_variable(&s_vmasks4);
|
|
955
|
+
s_vmasks6 = rb_eval_string("a = [0]*129; a[0] = 0; a[128] = 0xffffffffffffffffffffffffffffffff; 127.downto(1){|i| a[i] = a[i+1] - (1 << (127 - i))}; a.freeze");
|
|
956
|
+
rb_global_variable(&s_vmasks6);
|
|
957
|
+
|
|
958
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
|
959
|
+
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
|
960
|
+
|
|
961
|
+
return Qnil;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
|
|
395
965
|
void
|
|
396
|
-
init_pg_text_decoder()
|
|
966
|
+
init_pg_text_decoder(void)
|
|
397
967
|
{
|
|
398
|
-
|
|
968
|
+
s_id_Rational = rb_intern("Rational");
|
|
969
|
+
s_id_new = rb_intern("new");
|
|
970
|
+
s_id_utc = rb_intern("utc");
|
|
971
|
+
s_id_getlocal = rb_intern("getlocal");
|
|
972
|
+
|
|
973
|
+
s_nan = rb_eval_string("0.0/0.0");
|
|
974
|
+
rb_global_variable(&s_nan);
|
|
975
|
+
s_pos_inf = rb_eval_string("1.0/0.0");
|
|
976
|
+
rb_global_variable(&s_pos_inf);
|
|
977
|
+
s_neg_inf = rb_eval_string("-1.0/0.0");
|
|
978
|
+
rb_global_variable(&s_neg_inf);
|
|
399
979
|
|
|
400
980
|
/* This module encapsulates all decoder classes with text input format */
|
|
401
981
|
rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
|
|
982
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_inet", init_pg_text_decoder_inet, 0);
|
|
983
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_numeric", init_pg_text_decoder_numeric, 0);
|
|
402
984
|
|
|
403
985
|
/* Make RDoc aware of the decoder classes... */
|
|
404
986
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
|
|
@@ -413,6 +995,8 @@ init_pg_text_decoder()
|
|
|
413
995
|
pg_define_coder( "Bytea", pg_text_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
414
996
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Identifier", rb_cPG_SimpleDecoder ); */
|
|
415
997
|
pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
998
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
|
|
999
|
+
pg_define_coder( "Timestamp", pg_text_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
|
416
1000
|
|
|
417
1001
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
|
|
418
1002
|
pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|