sequel_pg 1.9.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +20 -0
- data/ext/sequel_pg/extconf.rb +1 -0
- data/ext/sequel_pg/sequel_pg.c +625 -194
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5e59a1152aaf6b21d44b1d57ce4653b6248a61db684a443bcdbbb86fb7c7ff8
|
4
|
+
data.tar.gz: 5f3392deba2a7286b6fa24a8c3b93ea8ee362f027c6df75a55574910b62a4c7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04d3ac1ba009d05ba2dd46d32865926a79a3cae63ef3f29a9d26d5874409fedfc54e6855a0a9ea9e7dd4dd9ef5e8603bda134368e040d9e3858f00b063ca8363
|
7
|
+
data.tar.gz: 0d147bca275b89d70255430fdadf4c7afc0a83a5f48414a656c1b583297ac05dea61b0d03d43a78b6bcff31f27adc8d62462e98de4228348171131f4e71144be
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
=== 1.10.0 (2018-06-25)
|
2
|
+
|
3
|
+
* Add native inet/cidr parsers (jeremyevans)
|
4
|
+
|
5
|
+
* Don't leak memory if unable to create a Sequel::SQL::Blob string when parsing bytea (jeremyevans)
|
6
|
+
|
7
|
+
* Improve performance of bytea parsing (jeremyevans)
|
8
|
+
|
9
|
+
* Drop Sequel <4.38.0 support (jeremyevans)
|
10
|
+
|
11
|
+
* Respect Sequel.application_timezone setting when parsing values for time and timetz columns (jeremyevans)
|
12
|
+
|
13
|
+
* Respect Sequel::SQLTime.date setting when parsing values for time and timetz columns (jeremyevans)
|
14
|
+
|
15
|
+
* Improve performance of time parsing (jeremyevans)
|
16
|
+
|
17
|
+
* Improve performance of date parsing (jeremyevans)
|
18
|
+
|
19
|
+
* Improve performance of timestamp parsing by borrowing and optimizing ruby-pg's parser (jeremyevans)
|
20
|
+
|
1
21
|
=== 1.9.0 (2018-06-06)
|
2
22
|
|
3
23
|
* Return arrays of common data types as PGArray instances automatically with much improved performance (jeremyevans)
|
data/ext/sequel_pg/extconf.rb
CHANGED
@@ -6,6 +6,7 @@ dir_config('pg', ENV["POSTGRES_INCLUDE"] || (IO.popen("pg_config --includedir").
|
|
6
6
|
|
7
7
|
if (have_library('pq') || have_library('libpq') || have_library('ms/libpq')) && have_header('libpq-fe.h')
|
8
8
|
have_func 'PQsetSingleRowMode'
|
9
|
+
have_func 'timegm'
|
9
10
|
create_makefile("sequel_pg")
|
10
11
|
else
|
11
12
|
puts 'Could not find PostgreSQL build environment (libraries & headers): Makefile not created'
|
data/ext/sequel_pg/sequel_pg.c
CHANGED
@@ -1,11 +1,18 @@
|
|
1
|
-
#define SEQUEL_PG_VERSION_INTEGER
|
1
|
+
#define SEQUEL_PG_VERSION_INTEGER 11000
|
2
2
|
|
3
3
|
#include <string.h>
|
4
4
|
#include <stdio.h>
|
5
5
|
#include <math.h>
|
6
6
|
#include <libpq-fe.h>
|
7
7
|
#include <ruby.h>
|
8
|
+
#include <ctype.h>
|
9
|
+
#include <sys/types.h>
|
10
|
+
#include <time.h>
|
11
|
+
#include <arpa/inet.h>
|
12
|
+
#include <sys/socket.h>
|
13
|
+
#include <string.h>
|
8
14
|
|
15
|
+
#include <ruby/version.h>
|
9
16
|
#include <ruby/encoding.h>
|
10
17
|
|
11
18
|
#ifndef SPG_MAX_FIELDS
|
@@ -16,11 +23,36 @@
|
|
16
23
|
|
17
24
|
#define SPG_DT_ADD_USEC if (usec != 0) { dt = rb_funcall(dt, spg_id_op_plus, 1, rb_Rational2(INT2NUM(usec), spg_usec_per_day)); }
|
18
25
|
|
19
|
-
#
|
20
|
-
#define
|
21
|
-
#
|
22
|
-
|
23
|
-
#define
|
26
|
+
#ifndef RARRAY_AREF
|
27
|
+
#define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#define ntohll(c) ((uint64_t)( \
|
31
|
+
(((uint64_t)(*((unsigned char*)(c)+0)))<<56LL) | \
|
32
|
+
(((uint64_t)(*((unsigned char*)(c)+1)))<<48LL) | \
|
33
|
+
(((uint64_t)(*((unsigned char*)(c)+2)))<<40LL) | \
|
34
|
+
(((uint64_t)(*((unsigned char*)(c)+3)))<<32LL) | \
|
35
|
+
(((uint64_t)(*((unsigned char*)(c)+4)))<<24LL) | \
|
36
|
+
(((uint64_t)(*((unsigned char*)(c)+5)))<<16LL) | \
|
37
|
+
(((uint64_t)(*((unsigned char*)(c)+6)))<< 8LL) | \
|
38
|
+
(((uint64_t)(*((unsigned char*)(c)+7))) ) \
|
39
|
+
))
|
40
|
+
|
41
|
+
#define SPG_DB_LOCAL (1)
|
42
|
+
#define SPG_DB_UTC (1<<1)
|
43
|
+
#define SPG_DB_CUSTOM (1<<2)
|
44
|
+
#define SPG_APP_LOCAL (1<<3)
|
45
|
+
#define SPG_APP_UTC (1<<4)
|
46
|
+
#define SPG_APP_CUSTOM (1<<5)
|
47
|
+
#define SPG_TZ_INITIALIZED (1<<6)
|
48
|
+
#define SPG_USE_TIME (1<<7)
|
49
|
+
#define SPG_HAS_TIMEZONE (1<<8)
|
50
|
+
|
51
|
+
#define SPG_YEAR_SHIFT 16
|
52
|
+
#define SPG_MONTH_SHIFT 8
|
53
|
+
#define SPG_MONTH_MASK 0x0000ffff
|
54
|
+
#define SPG_DAY_MASK 0x0000001f
|
55
|
+
#define SPG_TIME_UTC 32
|
24
56
|
|
25
57
|
#define SPG_YIELD_NORMAL 0
|
26
58
|
#define SPG_YIELD_COLUMN 1
|
@@ -37,17 +69,24 @@
|
|
37
69
|
#define SPG_YIELD_KMV_HASH_GROUPS 12
|
38
70
|
#define SPG_YIELD_MKMV_HASH_GROUPS 13
|
39
71
|
|
40
|
-
/* External functions defined by ruby-pg
|
72
|
+
/* External functions defined by ruby-pg */
|
41
73
|
PGconn* pg_get_pgconn(VALUE);
|
42
74
|
PGresult* pgresult_get(VALUE);
|
43
75
|
|
76
|
+
static int spg_use_ipaddr_alloc;
|
77
|
+
|
44
78
|
static VALUE spg_Sequel;
|
45
79
|
static VALUE spg_PGArray;
|
46
80
|
static VALUE spg_Blob;
|
81
|
+
static VALUE spg_Blob_instance;
|
47
82
|
static VALUE spg_Kernel;
|
48
83
|
static VALUE spg_Date;
|
84
|
+
static VALUE spg_DateTime;
|
49
85
|
static VALUE spg_SQLTime;
|
50
86
|
static VALUE spg_PGError;
|
87
|
+
static VALUE spg_IPAddr;
|
88
|
+
static VALUE spg_vmasks4;
|
89
|
+
static VALUE spg_vmasks6;
|
51
90
|
|
52
91
|
static VALUE spg_sym_utc;
|
53
92
|
static VALUE spg_sym_local;
|
@@ -86,6 +125,8 @@ static VALUE spg_sym_cid;
|
|
86
125
|
static VALUE spg_sym_name;
|
87
126
|
static VALUE spg_sym_tid;
|
88
127
|
static VALUE spg_sym_int2vector;
|
128
|
+
static VALUE spg_sym_inet;
|
129
|
+
static VALUE spg_sym_cidr;
|
89
130
|
|
90
131
|
static VALUE spg_nan;
|
91
132
|
static VALUE spg_pos_inf;
|
@@ -94,6 +135,7 @@ static VALUE spg_usec_per_day;
|
|
94
135
|
|
95
136
|
static ID spg_id_BigDecimal;
|
96
137
|
static ID spg_id_new;
|
138
|
+
static ID spg_id_date;
|
97
139
|
static ID spg_id_local;
|
98
140
|
static ID spg_id_year;
|
99
141
|
static ID spg_id_month;
|
@@ -123,12 +165,23 @@ static ID spg_id_columns;
|
|
123
165
|
static ID spg_id_encoding;
|
124
166
|
static ID spg_id_values;
|
125
167
|
|
168
|
+
static ID spg_id_lshift;
|
169
|
+
static ID spg_id_mask;
|
170
|
+
static ID spg_id_family;
|
171
|
+
static ID spg_id_addr;
|
172
|
+
static ID spg_id_mask_addr;
|
173
|
+
|
126
174
|
#if HAVE_PQSETSINGLEROWMODE
|
127
175
|
static ID spg_id_get_result;
|
128
176
|
static ID spg_id_clear;
|
129
177
|
static ID spg_id_check;
|
130
178
|
#endif
|
131
179
|
|
180
|
+
struct spg_blob_initialization {
|
181
|
+
char *blob_string;
|
182
|
+
size_t length;
|
183
|
+
};
|
184
|
+
|
132
185
|
static int enc_get_index(VALUE val) {
|
133
186
|
int i = ENCODING_GET_INLINED(val);
|
134
187
|
if (i == ENCODING_INLINE_MAX) {
|
@@ -138,68 +191,68 @@ static int enc_get_index(VALUE val) {
|
|
138
191
|
}
|
139
192
|
|
140
193
|
#define PG_ENCODING_SET_NOCHECK(obj,i) \
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
194
|
+
do { \
|
195
|
+
if ((i) < ENCODING_INLINE_MAX) \
|
196
|
+
ENCODING_SET_INLINED((obj), (i)); \
|
197
|
+
else \
|
198
|
+
rb_enc_set_index((obj), (i)); \
|
199
|
+
} while(0)
|
147
200
|
|
148
201
|
static VALUE
|
149
202
|
pg_text_dec_integer(char *val, int len)
|
150
203
|
{
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
204
|
+
long i;
|
205
|
+
int max_len;
|
206
|
+
|
207
|
+
if( sizeof(i) >= 8 && FIXNUM_MAX >= 1000000000000000000LL ){
|
208
|
+
/* 64 bit system can safely handle all numbers up to 18 digits as Fixnum */
|
209
|
+
max_len = 18;
|
210
|
+
} else if( sizeof(i) >= 4 && FIXNUM_MAX >= 1000000000LL ){
|
211
|
+
/* 32 bit system can safely handle all numbers up to 9 digits as Fixnum */
|
212
|
+
max_len = 9;
|
213
|
+
} else {
|
214
|
+
/* unknown -> don't use fast path for int conversion */
|
215
|
+
max_len = 0;
|
216
|
+
}
|
217
|
+
|
218
|
+
if( len <= max_len ){
|
219
|
+
/* rb_cstr2inum() seems to be slow, so we do the int conversion by hand.
|
220
|
+
* This proved to be 40% faster by the following benchmark:
|
221
|
+
*
|
222
|
+
* conn.type_mapping_for_results = PG::BasicTypeMapForResults.new conn
|
223
|
+
* Benchmark.measure do
|
224
|
+
* conn.exec("select generate_series(1,1000000)").values }
|
225
|
+
* end
|
226
|
+
*/
|
227
|
+
char *val_pos = val;
|
228
|
+
char digit = *val_pos;
|
229
|
+
int neg;
|
230
|
+
int error = 0;
|
231
|
+
|
232
|
+
if( digit=='-' ){
|
233
|
+
neg = 1;
|
234
|
+
i = 0;
|
235
|
+
}else if( digit>='0' && digit<='9' ){
|
236
|
+
neg = 0;
|
237
|
+
i = digit - '0';
|
238
|
+
} else {
|
239
|
+
error = 1;
|
240
|
+
}
|
241
|
+
|
242
|
+
while (!error && (digit=*++val_pos)) {
|
243
|
+
if( digit>='0' && digit<='9' ){
|
244
|
+
i = i * 10 + (digit - '0');
|
245
|
+
} else {
|
246
|
+
error = 1;
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
if( !error ){
|
251
|
+
return LONG2FIX(neg ? -i : i);
|
252
|
+
}
|
253
|
+
}
|
254
|
+
/* Fallback to ruby method if number too big or unrecognized. */
|
255
|
+
return rb_cstr2inum(val, 10);
|
203
256
|
}
|
204
257
|
|
205
258
|
static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int enc_index, int oid, VALUE db);
|
@@ -349,43 +402,108 @@ static VALUE parse_pg_array(VALUE self, VALUE pg_array_string, VALUE converter)
|
|
349
402
|
Qnil);
|
350
403
|
}
|
351
404
|
|
352
|
-
static VALUE
|
353
|
-
|
354
|
-
|
355
|
-
|
405
|
+
static VALUE spg_timestamp_error(const char *s, VALUE self, const char *error_msg) {
|
406
|
+
self = rb_funcall(self, spg_id_db, 0);
|
407
|
+
if(RTEST(rb_funcall(self, spg_id_convert_infinite_timestamps, 0))) {
|
408
|
+
if((strcmp(s, "infinity") == 0) || (strcmp(s, "-infinity") == 0)) {
|
409
|
+
return rb_funcall(self, spg_id_infinite_timestamp_value, 1, rb_tainted_str_new2(s));
|
410
|
+
}
|
411
|
+
}
|
412
|
+
rb_raise(rb_eArgError, "%s", error_msg);
|
413
|
+
}
|
414
|
+
|
415
|
+
static inline int char_to_digit(char c)
|
416
|
+
{
|
417
|
+
return c - '0';
|
418
|
+
}
|
419
|
+
|
420
|
+
static int str4_to_int(const char *str)
|
421
|
+
{
|
422
|
+
return char_to_digit(str[0]) * 1000
|
423
|
+
+ char_to_digit(str[1]) * 100
|
424
|
+
+ char_to_digit(str[2]) * 10
|
425
|
+
+ char_to_digit(str[3]);
|
426
|
+
}
|
427
|
+
|
428
|
+
static int str2_to_int(const char *str)
|
429
|
+
{
|
430
|
+
return char_to_digit(str[0]) * 10
|
431
|
+
+ char_to_digit(str[1]);
|
432
|
+
}
|
433
|
+
|
434
|
+
static VALUE spg_time(const char *p, size_t length, int current) {
|
435
|
+
int hour, minute, second, i;
|
356
436
|
int usec = 0;
|
437
|
+
ID meth = spg_id_local;
|
438
|
+
|
439
|
+
if (length < 8) {
|
440
|
+
rb_raise(rb_eArgError, "unexpected time format, too short");
|
441
|
+
}
|
442
|
+
|
443
|
+
if (p[2] == ':' && p[5] == ':') {
|
444
|
+
hour = str2_to_int(p);
|
445
|
+
minute = str2_to_int(p+3);
|
446
|
+
second = str2_to_int(p+6);
|
447
|
+
p += 8;
|
357
448
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
449
|
+
if (length >= 10 && p[0] == '.') {
|
450
|
+
static const int coef[6] = { 100000, 10000, 1000, 100, 10, 1 };
|
451
|
+
|
452
|
+
p++;
|
453
|
+
for (i = 0; i < 6 && isdigit(*p); i++) {
|
454
|
+
usec += coef[i] * char_to_digit(*p++);
|
363
455
|
}
|
364
456
|
}
|
365
|
-
|
366
|
-
usec *= (int) pow(10, (6 - strlen(subsec)));
|
367
|
-
} else if(tokens < 3) {
|
457
|
+
} else {
|
368
458
|
rb_raise(rb_eArgError, "unexpected time format");
|
369
459
|
}
|
370
460
|
|
371
|
-
|
372
|
-
|
461
|
+
if (current & SPG_TIME_UTC) {
|
462
|
+
meth = spg_id_utc;
|
463
|
+
}
|
464
|
+
return rb_funcall(spg_SQLTime, meth, 7,
|
465
|
+
INT2NUM(current >> SPG_YEAR_SHIFT),
|
466
|
+
INT2NUM((current & SPG_MONTH_MASK) >> SPG_MONTH_SHIFT),
|
467
|
+
INT2NUM(current & SPG_DAY_MASK),
|
468
|
+
INT2NUM(hour),
|
469
|
+
INT2NUM(minute),
|
470
|
+
INT2NUM(second),
|
471
|
+
INT2NUM(usec));
|
373
472
|
}
|
374
473
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
474
|
+
/* Caller should check length is at least 4 */
|
475
|
+
static int parse_year(const char **str, size_t *length) {
|
476
|
+
int year, i;
|
477
|
+
size_t remaining = *length;
|
478
|
+
const char * p = *str;
|
479
|
+
|
480
|
+
year = str4_to_int(p);
|
481
|
+
p += 4;
|
482
|
+
remaining -= 4;
|
483
|
+
|
484
|
+
for(i = 0; isdigit(*p) && i < 3; i++, p++, remaining--) {
|
485
|
+
year = 10 * year + char_to_digit(*p);
|
381
486
|
}
|
382
|
-
|
487
|
+
|
488
|
+
*str = p;
|
489
|
+
*length = remaining;
|
490
|
+
return year;
|
383
491
|
}
|
384
492
|
|
385
|
-
static VALUE spg_date(const char *s, VALUE self) {
|
493
|
+
static VALUE spg_date(const char *s, VALUE self, size_t length) {
|
386
494
|
int year, month, day;
|
495
|
+
const char *p = s;
|
387
496
|
|
388
|
-
if
|
497
|
+
if (length < 10) {
|
498
|
+
return spg_timestamp_error(s, self, "unexpected date format, too short");
|
499
|
+
}
|
500
|
+
|
501
|
+
year = parse_year(&p, &length);
|
502
|
+
|
503
|
+
if (length >= 5 && p[0] == '-' && p[3] == '-') {
|
504
|
+
month = str2_to_int(p+1);
|
505
|
+
day = str2_to_int(p+4);
|
506
|
+
} else {
|
389
507
|
return spg_timestamp_error(s, self, "unexpected date format");
|
390
508
|
}
|
391
509
|
|
@@ -397,85 +515,148 @@ static VALUE spg_date(const char *s, VALUE self) {
|
|
397
515
|
return rb_funcall(spg_Date, spg_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
|
398
516
|
}
|
399
517
|
|
400
|
-
static VALUE spg_timestamp(const char *s, VALUE self) {
|
401
|
-
VALUE
|
402
|
-
int
|
403
|
-
int year, month, day, hour, min, sec, usec, tokens, utc_offset, len;
|
404
|
-
int usec_start, usec_stop;
|
518
|
+
static VALUE spg_timestamp(const char *s, VALUE self, size_t length, int tz) {
|
519
|
+
VALUE dt;
|
520
|
+
int year, month, day, hour, min, sec, utc_offset;
|
405
521
|
char offset_sign = 0;
|
406
|
-
int offset_hour = 0;
|
407
|
-
int offset_minute = 0;
|
408
522
|
int offset_seconds = 0;
|
409
|
-
|
523
|
+
int usec = 0;
|
524
|
+
int i;
|
525
|
+
const char *p = s;
|
526
|
+
size_t remaining = length;
|
410
527
|
|
411
|
-
|
412
|
-
|
413
|
-
if (rtz != Qnil) {
|
414
|
-
if (rtz == spg_sym_local) {
|
415
|
-
tz += SPG_DB_LOCAL;
|
416
|
-
} else if (rtz == spg_sym_utc) {
|
417
|
-
tz += SPG_DB_UTC;
|
418
|
-
} else {
|
419
|
-
return rb_funcall(db, spg_id_to_application_timestamp, 1, rb_str_new2(s));
|
420
|
-
}
|
528
|
+
if (tz & SPG_DB_CUSTOM || tz & SPG_APP_CUSTOM) {
|
529
|
+
return rb_funcall(rb_funcall(self, spg_id_db, 0), spg_id_to_application_timestamp, 1, rb_str_new2(s));
|
421
530
|
}
|
422
531
|
|
423
|
-
|
424
|
-
|
425
|
-
if (rtz == spg_sym_local) {
|
426
|
-
tz += SPG_APP_LOCAL;
|
427
|
-
} else if (rtz == spg_sym_utc) {
|
428
|
-
tz += SPG_APP_UTC;
|
429
|
-
} else {
|
430
|
-
return rb_funcall(db, spg_id_to_application_timestamp, 1, rb_str_new2(s));
|
431
|
-
}
|
532
|
+
if (remaining < 19) {
|
533
|
+
return spg_timestamp_error(s, self, "unexpected timetamp format, too short");
|
432
534
|
}
|
433
535
|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
536
|
+
year = parse_year(&p, &remaining);
|
537
|
+
|
538
|
+
if (remaining >= 15 && p[0] == '-' && p[3] == '-' && p[6] == ' ' && p[9] == ':' && p[12] == ':') {
|
539
|
+
month = str2_to_int(p+1);
|
540
|
+
day = str2_to_int(p+4);
|
541
|
+
hour = str2_to_int(p+7);
|
542
|
+
min = str2_to_int(p+10);
|
543
|
+
sec = str2_to_int(p+13);
|
544
|
+
p += 15;
|
545
|
+
remaining -= 15;
|
546
|
+
|
547
|
+
if (remaining >= 2 && p[0] == '.') {
|
548
|
+
/* microsecond part, up to 6 digits */
|
549
|
+
static const int coef[6] = { 100000, 10000, 1000, 100, 10, 1 };
|
550
|
+
|
551
|
+
p++;
|
552
|
+
remaining--;
|
553
|
+
for (i = 0; i < 6 && isdigit(*p); i++)
|
554
|
+
{
|
555
|
+
usec += coef[i] * char_to_digit(*p++);
|
556
|
+
remaining--;
|
557
|
+
}
|
441
558
|
}
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
559
|
+
|
560
|
+
if ((tz & SPG_HAS_TIMEZONE) && remaining >= 3 && (p[0] == '+' || p[0] == '-')) {
|
561
|
+
offset_sign = p[0];
|
562
|
+
offset_seconds += str2_to_int(p+1)*3600;
|
563
|
+
p += 3;
|
564
|
+
remaining -= 3;
|
565
|
+
|
566
|
+
if (p[0] == ':') {
|
567
|
+
p++;
|
568
|
+
remaining--;
|
569
|
+
}
|
570
|
+
if (remaining >= 2 && isdigit(p[0]) && isdigit(p[1]))
|
571
|
+
{
|
572
|
+
offset_seconds += str2_to_int(p)*60;
|
573
|
+
p += 2;
|
574
|
+
remaining -= 2;
|
575
|
+
}
|
576
|
+
if (p[0] == ':')
|
577
|
+
{
|
578
|
+
p++;
|
579
|
+
remaining--;
|
580
|
+
}
|
581
|
+
if (remaining >= 2 && isdigit(p[0]) && isdigit(p[1]))
|
582
|
+
{
|
583
|
+
offset_seconds += str2_to_int(p);
|
584
|
+
p += 2;
|
585
|
+
remaining -= 2;
|
586
|
+
}
|
587
|
+
if (offset_sign == '-') {
|
588
|
+
offset_seconds *= -1;
|
589
|
+
}
|
453
590
|
}
|
454
|
-
usec = 0;
|
455
|
-
}
|
456
591
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
592
|
+
if (remaining == 3 && p[0] == ' ' && p[1] == 'B' && p[2] == 'C') {
|
593
|
+
year = -year;
|
594
|
+
year++;
|
595
|
+
} else if (remaining != 0) {
|
596
|
+
return spg_timestamp_error(s, self, "unexpected timestamp format, remaining data left");
|
597
|
+
}
|
598
|
+
} else {
|
599
|
+
return spg_timestamp_error(s, self, "unexpected timestamp format");
|
461
600
|
}
|
601
|
+
|
462
602
|
|
463
|
-
if (
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
603
|
+
if (tz & SPG_USE_TIME) {
|
604
|
+
#if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(HAVE_TIMEGM)
|
605
|
+
/* Fast path for time conversion */
|
606
|
+
struct tm tm;
|
607
|
+
struct timespec ts;
|
608
|
+
time_t time;
|
468
609
|
|
469
|
-
|
610
|
+
tm.tm_year = year - 1900;
|
611
|
+
tm.tm_mon = month - 1;
|
612
|
+
tm.tm_mday = day;
|
613
|
+
tm.tm_hour = hour;
|
614
|
+
tm.tm_min = min;
|
615
|
+
tm.tm_sec = sec;
|
616
|
+
tm.tm_isdst = -1;
|
617
|
+
|
618
|
+
ts.tv_nsec = usec*1000;
|
619
|
+
|
620
|
+
if (offset_sign) {
|
621
|
+
time = timegm(&tm);
|
622
|
+
if (time != -1) {
|
623
|
+
ts.tv_sec = time - offset_seconds;
|
624
|
+
dt = rb_time_timespec_new(&ts, offset_seconds);
|
625
|
+
|
626
|
+
if (tz & SPG_APP_UTC) {
|
627
|
+
dt = rb_funcall(dt, spg_id_utc, 0);
|
628
|
+
} else if (tz & SPG_APP_LOCAL) {
|
629
|
+
dt = rb_funcall(dt, spg_id_local, 0);
|
630
|
+
}
|
631
|
+
|
632
|
+
return dt;
|
633
|
+
}
|
634
|
+
} else {
|
635
|
+
if (tz & SPG_DB_UTC) {
|
636
|
+
time = timegm(&tm);
|
637
|
+
} else {
|
638
|
+
time = mktime(&tm);
|
639
|
+
}
|
640
|
+
|
641
|
+
if (time != -1) {
|
642
|
+
ts.tv_sec = time;
|
643
|
+
if (tz & SPG_APP_UTC) {
|
644
|
+
offset_seconds = INT_MAX-1;
|
645
|
+
} else {
|
646
|
+
offset_seconds = INT_MAX;
|
647
|
+
}
|
648
|
+
|
649
|
+
return rb_time_timespec_new(&ts, offset_seconds);
|
650
|
+
}
|
651
|
+
}
|
652
|
+
#endif
|
470
653
|
|
471
|
-
if (dtc == rb_cTime) {
|
472
654
|
if (offset_sign) {
|
473
655
|
/* Offset given, convert to local time if not already in local time.
|
474
656
|
* While PostgreSQL generally returns timestamps in local time, it's unwise to rely on this.
|
475
657
|
*/
|
476
658
|
dt = rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
477
659
|
utc_offset = NUM2INT(rb_funcall(dt, spg_id_utc_offset, 0));
|
478
|
-
offset_seconds += offset_hour * 3600 + offset_minute * 60;
|
479
660
|
if (utc_offset != offset_seconds) {
|
480
661
|
dt = rb_funcall(dt, spg_id_op_plus, 1, INT2NUM(utc_offset - offset_seconds));
|
481
662
|
}
|
@@ -484,7 +665,7 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
484
665
|
dt = rb_funcall(dt, spg_id_utc, 0);
|
485
666
|
}
|
486
667
|
return dt;
|
487
|
-
} else if (tz
|
668
|
+
} else if (!(tz & (SPG_APP_LOCAL|SPG_DB_LOCAL|SPG_APP_UTC|SPG_DB_UTC))) {
|
488
669
|
return rb_funcall(rb_cTime, spg_id_local, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), INT2NUM(usec));
|
489
670
|
}
|
490
671
|
|
@@ -506,12 +687,14 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
506
687
|
}
|
507
688
|
} else {
|
508
689
|
/* datetime.class == DateTime */
|
690
|
+
double offset_fraction;
|
691
|
+
|
509
692
|
if (offset_sign) {
|
510
693
|
/* Offset given, handle correct local time.
|
511
694
|
* While PostgreSQL generally returns timestamps in local time, it's unwise to rely on this.
|
512
695
|
*/
|
513
|
-
offset_fraction =
|
514
|
-
dt = rb_funcall(
|
696
|
+
offset_fraction = offset_seconds/(double)SPG_SECONDS_PER_DAY;
|
697
|
+
dt = rb_funcall(spg_DateTime, spg_id_new, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), rb_float_new(offset_fraction));
|
515
698
|
SPG_DT_ADD_USEC
|
516
699
|
|
517
700
|
if (tz & SPG_APP_LOCAL) {
|
@@ -521,8 +704,8 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
521
704
|
dt = rb_funcall(dt, spg_id_new_offset, 1, INT2NUM(0));
|
522
705
|
}
|
523
706
|
return dt;
|
524
|
-
} else if (tz
|
525
|
-
dt = rb_funcall(
|
707
|
+
} else if (!(tz & (SPG_APP_LOCAL|SPG_DB_LOCAL|SPG_APP_UTC|SPG_DB_UTC))) {
|
708
|
+
dt = rb_funcall(spg_DateTime, spg_id_new, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
526
709
|
SPG_DT_ADD_USEC
|
527
710
|
return dt;
|
528
711
|
}
|
@@ -530,7 +713,7 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
530
713
|
/* No offset given, and some timezone combination given */
|
531
714
|
if (tz & SPG_DB_LOCAL) {
|
532
715
|
offset_fraction = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
|
533
|
-
dt = rb_funcall(
|
716
|
+
dt = rb_funcall(spg_DateTime, spg_id_new, 7, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec), rb_float_new(offset_fraction));
|
534
717
|
SPG_DT_ADD_USEC
|
535
718
|
if (tz & SPG_APP_UTC) {
|
536
719
|
return rb_funcall(dt, spg_id_new_offset, 1, INT2NUM(0));
|
@@ -538,11 +721,12 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
538
721
|
return dt;
|
539
722
|
}
|
540
723
|
} else {
|
541
|
-
dt = rb_funcall(
|
724
|
+
dt = rb_funcall(spg_DateTime, spg_id_new, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec));
|
542
725
|
SPG_DT_ADD_USEC
|
543
726
|
if (tz & SPG_APP_LOCAL) {
|
544
727
|
offset_fraction = NUM2INT(rb_funcall(rb_funcall(rb_cTime, spg_id_local, 6, INT2NUM(year), INT2NUM(month), INT2NUM(day), INT2NUM(hour), INT2NUM(min), INT2NUM(sec)), spg_id_utc_offset, 0))/SPG_SECONDS_PER_DAY;
|
545
|
-
|
728
|
+
dt = rb_funcall(dt, spg_id_new_offset, 1, rb_float_new(offset_fraction));
|
729
|
+
return dt;
|
546
730
|
} else {
|
547
731
|
return dt;
|
548
732
|
}
|
@@ -550,22 +734,144 @@ static VALUE spg_timestamp(const char *s, VALUE self) {
|
|
550
734
|
}
|
551
735
|
}
|
552
736
|
|
737
|
+
static VALUE spg_inet(char *val, size_t len)
|
738
|
+
{
|
739
|
+
VALUE ip;
|
740
|
+
VALUE ip_int;
|
741
|
+
VALUE vmasks;
|
742
|
+
unsigned int dst[4];
|
743
|
+
char buf[64];
|
744
|
+
int af = strchr(val, '.') ? AF_INET : AF_INET6;
|
745
|
+
int mask = -1;
|
746
|
+
|
747
|
+
if (len >= 64) {
|
748
|
+
rb_raise(rb_eTypeError, "unable to parse IP address, too long");
|
749
|
+
}
|
750
|
+
|
751
|
+
if (len >= 4) {
|
752
|
+
if (val[len-2] == '/') {
|
753
|
+
mask = val[len-1] - '0';
|
754
|
+
memcpy(buf, val, len-2);
|
755
|
+
val = buf;
|
756
|
+
val[len-2] = '\0';
|
757
|
+
} else if (val[len-3] == '/') {
|
758
|
+
mask = (val[len-2]- '0')*10 + val[len-1] - '0';
|
759
|
+
memcpy(buf, val, len-3);
|
760
|
+
val = buf;
|
761
|
+
val[len-3] = '\0';
|
762
|
+
} else if (val[len-4] == '/') {
|
763
|
+
mask = (val[len-3]- '0')*100 + (val[len-2]- '0')*10 + val[len-1] - '0';
|
764
|
+
memcpy(buf, val, len-4);
|
765
|
+
val = buf;
|
766
|
+
val[len-4] = '\0';
|
767
|
+
}
|
768
|
+
}
|
769
|
+
|
770
|
+
if (1 != inet_pton(af, val, (char *)dst)) {
|
771
|
+
rb_raise(rb_eTypeError, "unable to parse IP address: %s", val);
|
772
|
+
}
|
773
|
+
|
774
|
+
if (af == AF_INET) {
|
775
|
+
unsigned int ip_int_native;
|
776
|
+
|
777
|
+
if (mask == -1) {
|
778
|
+
mask = 32;
|
779
|
+
} else if (mask < 0 || mask > 32) {
|
780
|
+
rb_raise(rb_eTypeError, "invalid mask for IPv4: %d", mask);
|
781
|
+
}
|
782
|
+
vmasks = spg_vmasks4;
|
783
|
+
|
784
|
+
ip_int_native = ntohl(*dst);
|
785
|
+
|
786
|
+
/* Work around broken IPAddr behavior of convering portion
|
787
|
+
of address after netmask to 0 */
|
788
|
+
switch (mask) {
|
789
|
+
case 0:
|
790
|
+
ip_int_native = 0;
|
791
|
+
break;
|
792
|
+
case 32:
|
793
|
+
/* nothing to do */
|
794
|
+
break;
|
795
|
+
default:
|
796
|
+
ip_int_native &= ~((1UL<<(32-mask))-1);
|
797
|
+
break;
|
798
|
+
}
|
799
|
+
ip_int = UINT2NUM(ip_int_native);
|
800
|
+
} else {
|
801
|
+
unsigned long long * dstllp = (unsigned long long *)dst;
|
802
|
+
unsigned long long ip_int_native1;
|
803
|
+
unsigned long long ip_int_native2;
|
804
|
+
|
805
|
+
if (mask == -1) {
|
806
|
+
mask = 128;
|
807
|
+
} else if (mask < 0 || mask > 128) {
|
808
|
+
rb_raise(rb_eTypeError, "invalid mask for IPv6: %d", mask);
|
809
|
+
}
|
810
|
+
vmasks = spg_vmasks6;
|
811
|
+
|
812
|
+
ip_int_native1 = ntohll(dstllp);
|
813
|
+
dstllp++;
|
814
|
+
ip_int_native2 = ntohll(dstllp);
|
815
|
+
|
816
|
+
if (mask == 128) {
|
817
|
+
/* nothing to do */
|
818
|
+
} else if (mask == 64) {
|
819
|
+
ip_int_native2 = 0;
|
820
|
+
} else if (mask == 0) {
|
821
|
+
ip_int_native1 = 0;
|
822
|
+
ip_int_native2 = 0;
|
823
|
+
} else if (mask < 64) {
|
824
|
+
ip_int_native1 &= ~((1ULL<<(64-mask))-1);
|
825
|
+
ip_int_native2 = 0;
|
826
|
+
} else {
|
827
|
+
ip_int_native2 &= ~((1ULL<<(128-mask))-1);
|
828
|
+
}
|
829
|
+
|
830
|
+
/* 4 Bignum allocations */
|
831
|
+
ip_int = ULL2NUM(ip_int_native1);
|
832
|
+
ip_int = rb_funcall(ip_int, spg_id_lshift, 1, INT2NUM(64));
|
833
|
+
ip_int = rb_funcall(ip_int, spg_id_op_plus, 1, ULL2NUM(ip_int_native2));
|
834
|
+
}
|
835
|
+
|
836
|
+
if (spg_use_ipaddr_alloc) {
|
837
|
+
ip = rb_obj_alloc(spg_IPAddr);
|
838
|
+
rb_ivar_set(ip, spg_id_family, INT2NUM(af));
|
839
|
+
rb_ivar_set(ip, spg_id_addr, ip_int);
|
840
|
+
rb_ivar_set(ip, spg_id_mask_addr, RARRAY_AREF(vmasks, mask));
|
841
|
+
} else {
|
842
|
+
VALUE ip_args[2];
|
843
|
+
ip_args[0] = ip_int;
|
844
|
+
ip_args[1] = INT2NUM(af);
|
845
|
+
ip = rb_class_new_instance(2, ip_args, spg_IPAddr);
|
846
|
+
ip = rb_funcall(ip, spg_id_mask, 1, INT2NUM(mask));
|
847
|
+
}
|
848
|
+
|
849
|
+
return ip;
|
850
|
+
}
|
851
|
+
|
852
|
+
static VALUE spg_create_Blob(VALUE v) {
|
853
|
+
struct spg_blob_initialization *bi = (struct spg_blob_initialization *)v;
|
854
|
+
if (bi->blob_string == NULL) {
|
855
|
+
rb_raise(rb_eNoMemError, "PQunescapeBytea failure: probably not enough memory");
|
856
|
+
}
|
857
|
+
return rb_obj_taint(rb_str_new_with_class(spg_Blob_instance, bi->blob_string, bi->length));
|
858
|
+
}
|
859
|
+
|
553
860
|
static VALUE spg_fetch_rows_set_cols(VALUE self, VALUE ignore) {
|
554
861
|
return Qnil;
|
555
862
|
}
|
556
863
|
|
557
864
|
static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int enc_index, int oid, VALUE db) {
|
558
865
|
VALUE rv;
|
559
|
-
|
866
|
+
struct spg_blob_initialization bi;
|
560
867
|
|
561
868
|
switch(oid) {
|
562
869
|
case 16: /* boolean */
|
563
870
|
rv = *v == 't' ? Qtrue : Qfalse;
|
564
871
|
break;
|
565
872
|
case 17: /* bytea */
|
566
|
-
|
567
|
-
rv =
|
568
|
-
PQfreemem(v);
|
873
|
+
bi.blob_string = (char *)PQunescapeBytea((unsigned char*)v, &bi.length);
|
874
|
+
rv = rb_ensure(spg_create_Blob, (VALUE)&bi, (VALUE(*)())PQfreemem, (VALUE)bi.blob_string);
|
569
875
|
break;
|
570
876
|
case 20: /* integer */
|
571
877
|
case 21:
|
@@ -589,15 +895,15 @@ static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int e
|
|
589
895
|
rv = rb_funcall(spg_Kernel, spg_id_BigDecimal, 1, rb_str_new(v, length));
|
590
896
|
break;
|
591
897
|
case 1082: /* date */
|
592
|
-
rv = spg_date(v, db);
|
898
|
+
rv = spg_date(v, db, length);
|
593
899
|
break;
|
594
900
|
case 1083: /* time */
|
595
901
|
case 1266:
|
596
|
-
rv = spg_time(v);
|
902
|
+
rv = spg_time(v, length, (int)converter);
|
597
903
|
break;
|
598
904
|
case 1114: /* timestamp */
|
599
905
|
case 1184:
|
600
|
-
rv = spg_timestamp(v, db);
|
906
|
+
rv = spg_timestamp(v, db, length, (int)converter);
|
601
907
|
break;
|
602
908
|
case 18: /* char */
|
603
909
|
case 25: /* text */
|
@@ -605,6 +911,10 @@ static VALUE spg__array_col_value(char *v, size_t length, VALUE converter, int e
|
|
605
911
|
rv = rb_tainted_str_new(v, length);
|
606
912
|
PG_ENCODING_SET_NOCHECK(rv, enc_index);
|
607
913
|
break;
|
914
|
+
case 869: /* inet */
|
915
|
+
case 650: /* cidr */
|
916
|
+
rv = spg_inet(v, length);
|
917
|
+
break;
|
608
918
|
default:
|
609
919
|
rv = rb_tainted_str_new(v, length);
|
610
920
|
PG_ENCODING_SET_NOCHECK(rv, enc_index);
|
@@ -629,13 +939,63 @@ static VALUE spg_array_value(char *c_pg_array_string, int array_string_length, V
|
|
629
939
|
return rb_class_new_instance(2, args, spg_PGArray);
|
630
940
|
}
|
631
941
|
|
942
|
+
static int spg_time_info_bitmask(void) {
|
943
|
+
int info = 0;
|
944
|
+
VALUE now = rb_funcall(spg_SQLTime, spg_id_date, 0);
|
945
|
+
|
946
|
+
info = NUM2INT(rb_funcall(now, spg_id_year, 0)) << SPG_YEAR_SHIFT;
|
947
|
+
info += NUM2INT(rb_funcall(now, spg_id_month, 0)) << SPG_MONTH_SHIFT;
|
948
|
+
info += NUM2INT(rb_funcall(now, spg_id_day, 0));
|
949
|
+
|
950
|
+
if (rb_funcall(spg_Sequel, spg_id_application_timezone, 0) == spg_sym_utc) {
|
951
|
+
info += SPG_TIME_UTC;
|
952
|
+
}
|
953
|
+
|
954
|
+
return info;
|
955
|
+
}
|
956
|
+
|
957
|
+
static int spg_timestamp_info_bitmask(VALUE self) {
|
958
|
+
VALUE db, rtz;
|
959
|
+
int tz = 0;
|
960
|
+
|
961
|
+
db = rb_funcall(self, spg_id_db, 0);
|
962
|
+
rtz = rb_funcall(db, spg_id_timezone, 0);
|
963
|
+
if (rtz != Qnil) {
|
964
|
+
if (rtz == spg_sym_local) {
|
965
|
+
tz |= SPG_DB_LOCAL;
|
966
|
+
} else if (rtz == spg_sym_utc) {
|
967
|
+
tz |= SPG_DB_UTC;
|
968
|
+
} else {
|
969
|
+
tz |= SPG_DB_CUSTOM;
|
970
|
+
}
|
971
|
+
}
|
972
|
+
|
973
|
+
rtz = rb_funcall(spg_Sequel, spg_id_application_timezone, 0);
|
974
|
+
if (rtz != Qnil) {
|
975
|
+
if (rtz == spg_sym_local) {
|
976
|
+
tz |= SPG_APP_LOCAL;
|
977
|
+
} else if (rtz == spg_sym_utc) {
|
978
|
+
tz |= SPG_APP_UTC;
|
979
|
+
} else {
|
980
|
+
tz |= SPG_APP_CUSTOM;
|
981
|
+
}
|
982
|
+
}
|
983
|
+
|
984
|
+
if (rb_cTime == rb_funcall(spg_Sequel, spg_id_datetime_class, 0)) {
|
985
|
+
tz |= SPG_USE_TIME;
|
986
|
+
}
|
987
|
+
|
988
|
+
tz |= SPG_TZ_INITIALIZED;
|
989
|
+
return tz;
|
990
|
+
}
|
991
|
+
|
632
992
|
static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* colconvert, int enc_index) {
|
633
993
|
char *v;
|
634
994
|
VALUE rv;
|
635
|
-
size_t l;
|
636
995
|
int ftype = PQftype(res, j);
|
637
996
|
VALUE array_type;
|
638
997
|
VALUE scalar_oid;
|
998
|
+
struct spg_blob_initialization bi;
|
639
999
|
|
640
1000
|
if(PQgetisnull(res, i, j)) {
|
641
1001
|
rv = Qnil;
|
@@ -647,9 +1007,8 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co
|
|
647
1007
|
rv = *v == 't' ? Qtrue : Qfalse;
|
648
1008
|
break;
|
649
1009
|
case 17: /* bytea */
|
650
|
-
|
651
|
-
rv =
|
652
|
-
PQfreemem(v);
|
1010
|
+
bi.blob_string = (char *)PQunescapeBytea((unsigned char*)v, &bi.length);
|
1011
|
+
rv = rb_ensure(spg_create_Blob, (VALUE)&bi, (VALUE(*)())PQfreemem, (VALUE)bi.blob_string);
|
653
1012
|
break;
|
654
1013
|
case 20: /* integer */
|
655
1014
|
case 21:
|
@@ -673,15 +1032,15 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co
|
|
673
1032
|
rv = rb_funcall(spg_Kernel, spg_id_BigDecimal, 1, rb_str_new(v, PQgetlength(res, i, j)));
|
674
1033
|
break;
|
675
1034
|
case 1082: /* date */
|
676
|
-
rv = spg_date(v, self);
|
1035
|
+
rv = spg_date(v, self, PQgetlength(res, i, j));
|
677
1036
|
break;
|
678
1037
|
case 1083: /* time */
|
679
1038
|
case 1266:
|
680
|
-
rv = spg_time(v);
|
1039
|
+
rv = spg_time(v, PQgetlength(res, i, j), (int)colconvert[j]);
|
681
1040
|
break;
|
682
1041
|
case 1114: /* timestamp */
|
683
1042
|
case 1184:
|
684
|
-
rv = spg_timestamp(v, self);
|
1043
|
+
rv = spg_timestamp(v, self, PQgetlength(res, i, j), (int)colconvert[j]);
|
685
1044
|
break;
|
686
1045
|
case 18: /* char */
|
687
1046
|
case 25: /* text */
|
@@ -689,6 +1048,10 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co
|
|
689
1048
|
rv = rb_tainted_str_new(v, PQgetlength(res, i, j));
|
690
1049
|
PG_ENCODING_SET_NOCHECK(rv, enc_index);
|
691
1050
|
break;
|
1051
|
+
case 869: /* inet */
|
1052
|
+
case 650: /* cidr */
|
1053
|
+
rv = spg_inet(v, PQgetlength(res, i, j));
|
1054
|
+
break;
|
692
1055
|
/* array types */
|
693
1056
|
case 1009:
|
694
1057
|
case 1014:
|
@@ -717,6 +1080,8 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co
|
|
717
1080
|
case 1003:
|
718
1081
|
case 1010:
|
719
1082
|
case 1006:
|
1083
|
+
case 1041:
|
1084
|
+
case 651:
|
720
1085
|
switch(ftype) {
|
721
1086
|
case 1009:
|
722
1087
|
case 1014:
|
@@ -823,8 +1188,16 @@ static VALUE spg__col_value(VALUE self, PGresult *res, long i, long j, VALUE* co
|
|
823
1188
|
array_type = spg_sym_int2vector;
|
824
1189
|
scalar_oid = 22;
|
825
1190
|
break;
|
1191
|
+
case 1041:
|
1192
|
+
array_type = spg_sym_inet;
|
1193
|
+
scalar_oid = 869;
|
1194
|
+
break;
|
1195
|
+
case 651:
|
1196
|
+
array_type = spg_sym_cidr;
|
1197
|
+
scalar_oid = 650;
|
1198
|
+
break;
|
826
1199
|
}
|
827
|
-
rv = spg_array_value(v, PQgetlength(res, i, j),
|
1200
|
+
rv = spg_array_value(v, PQgetlength(res, i, j), colconvert[j], enc_index, scalar_oid, self, array_type);
|
828
1201
|
break;
|
829
1202
|
default:
|
830
1203
|
rv = rb_tainted_str_new(v, PQgetlength(res, i, j));
|
@@ -877,6 +1250,8 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE
|
|
877
1250
|
long i;
|
878
1251
|
long j;
|
879
1252
|
long nfields;
|
1253
|
+
int timestamp_info = 0;
|
1254
|
+
int time_info = 0;
|
880
1255
|
VALUE conv_procs = 0;
|
881
1256
|
|
882
1257
|
nfields = PQnfields(res);
|
@@ -885,6 +1260,7 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE
|
|
885
1260
|
colsyms[j] = rb_funcall(self, spg_id_output_identifier, 1, rb_str_new2(PQfname(res, j)));
|
886
1261
|
i = PQftype(res, j);
|
887
1262
|
switch (i) {
|
1263
|
+
/* scalar types */
|
888
1264
|
case 16:
|
889
1265
|
case 17:
|
890
1266
|
case 20:
|
@@ -896,15 +1272,57 @@ static void spg_set_column_info(VALUE self, PGresult *res, VALUE *colsyms, VALUE
|
|
896
1272
|
case 790:
|
897
1273
|
case 1700:
|
898
1274
|
case 1082:
|
899
|
-
case 1083:
|
900
|
-
case 1266:
|
901
|
-
case 1114:
|
902
|
-
case 1184:
|
903
1275
|
case 18:
|
904
1276
|
case 25:
|
905
1277
|
case 1043:
|
1278
|
+
/* array types */
|
1279
|
+
case 1009:
|
1280
|
+
case 1014:
|
1281
|
+
case 1015:
|
1282
|
+
case 1007:
|
1283
|
+
case 1016:
|
1284
|
+
case 1231:
|
1285
|
+
case 1022:
|
1286
|
+
case 1000:
|
1287
|
+
case 1001:
|
1288
|
+
case 1182:
|
1289
|
+
case 1005:
|
1290
|
+
case 1028:
|
1291
|
+
case 1021:
|
1292
|
+
case 143:
|
1293
|
+
case 791:
|
1294
|
+
case 1561:
|
1295
|
+
case 1563:
|
1296
|
+
case 2951:
|
1297
|
+
case 1011:
|
1298
|
+
case 1012:
|
1299
|
+
case 1003:
|
1300
|
+
case 1010:
|
906
1301
|
colconvert[j] = Qnil;
|
907
1302
|
break;
|
1303
|
+
|
1304
|
+
/* time types */
|
1305
|
+
case 1183:
|
1306
|
+
case 1083:
|
1307
|
+
case 1270:
|
1308
|
+
case 1266:
|
1309
|
+
if (time_info == 0) {
|
1310
|
+
time_info = spg_time_info_bitmask();
|
1311
|
+
}
|
1312
|
+
colconvert[j] = time_info;
|
1313
|
+
break;
|
1314
|
+
|
1315
|
+
/* timestamp types */
|
1316
|
+
case 1115:
|
1317
|
+
case 1185:
|
1318
|
+
case 1114:
|
1319
|
+
case 1184:
|
1320
|
+
if (timestamp_info == 0) {
|
1321
|
+
timestamp_info = spg_timestamp_info_bitmask(self);
|
1322
|
+
}
|
1323
|
+
colconvert[j] = (VALUE)((i == 1184 || i == 1185) ? (timestamp_info | SPG_HAS_TIMEZONE) : timestamp_info);
|
1324
|
+
break;
|
1325
|
+
|
908
1326
|
default:
|
909
1327
|
if (conv_procs == 0) {
|
910
1328
|
conv_procs = rb_funcall(rb_funcall(self, spg_id_db, 0), spg_id_conversion_procs, 0);
|
@@ -930,14 +1348,13 @@ static VALUE spg_yield_hash_rows(VALUE self, VALUE rres, VALUE ignore) {
|
|
930
1348
|
VALUE pg_type;
|
931
1349
|
VALUE pg_value;
|
932
1350
|
char type = SPG_YIELD_NORMAL;
|
1351
|
+
int enc_index;
|
933
1352
|
|
934
1353
|
if (!RTEST(rres)) {
|
935
1354
|
return self;
|
936
1355
|
}
|
937
|
-
Check_Type(rres, T_DATA);
|
938
1356
|
res = pgresult_get(rres);
|
939
1357
|
|
940
|
-
int enc_index;
|
941
1358
|
enc_index = enc_get_index(rres);
|
942
1359
|
|
943
1360
|
ntuples = PQntuples(res);
|
@@ -1174,7 +1591,6 @@ static VALUE spg_supports_streaming_p(VALUE self) {
|
|
1174
1591
|
#if HAVE_PQSETSINGLEROWMODE
|
1175
1592
|
static VALUE spg_set_single_row_mode(VALUE self) {
|
1176
1593
|
PGconn *conn;
|
1177
|
-
Check_Type(self, T_DATA);
|
1178
1594
|
conn = pg_get_pgconn(self);
|
1179
1595
|
if (PQsetSingleRowMode(conn) != 1) {
|
1180
1596
|
rb_raise(spg_PGError, "cannot set single row mode");
|
@@ -1183,7 +1599,6 @@ static VALUE spg_set_single_row_mode(VALUE self) {
|
|
1183
1599
|
}
|
1184
1600
|
|
1185
1601
|
static VALUE spg__yield_each_row(VALUE self) {
|
1186
|
-
PGconn *conn;
|
1187
1602
|
PGresult *res;
|
1188
1603
|
VALUE rres;
|
1189
1604
|
VALUE rconn;
|
@@ -1196,21 +1611,18 @@ static VALUE spg__yield_each_row(VALUE self) {
|
|
1196
1611
|
VALUE pg_type;
|
1197
1612
|
VALUE pg_value = Qnil;
|
1198
1613
|
char type = SPG_YIELD_NORMAL;
|
1614
|
+
int enc_index;
|
1199
1615
|
|
1200
1616
|
rconn = rb_ary_entry(self, 1);
|
1201
1617
|
self = rb_ary_entry(self, 0);
|
1202
|
-
Check_Type(rconn, T_DATA);
|
1203
|
-
conn = pg_get_pgconn(rconn);
|
1204
1618
|
|
1205
1619
|
rres = rb_funcall(rconn, spg_id_get_result, 0);
|
1206
1620
|
if (rres == Qnil) {
|
1207
1621
|
goto end_yield_each_row;
|
1208
1622
|
}
|
1209
1623
|
rb_funcall(rres, spg_id_check, 0);
|
1210
|
-
Check_Type(rres, T_DATA);
|
1211
1624
|
res = pgresult_get(rres);
|
1212
1625
|
|
1213
|
-
int enc_index;
|
1214
1626
|
enc_index = enc_get_index(rres);
|
1215
1627
|
|
1216
1628
|
/* Only handle regular and model types. All other types require compiling all
|
@@ -1255,7 +1667,6 @@ static VALUE spg__yield_each_row(VALUE self) {
|
|
1255
1667
|
goto end_yield_each_row;
|
1256
1668
|
}
|
1257
1669
|
rb_funcall(rres, spg_id_check, 0);
|
1258
|
-
Check_Type(rres, T_DATA);
|
1259
1670
|
res = pgresult_get(rres);
|
1260
1671
|
}
|
1261
1672
|
rb_funcall(rres, spg_id_clear, 0);
|
@@ -1268,7 +1679,6 @@ static VALUE spg__flush_results(VALUE rconn) {
|
|
1268
1679
|
PGconn *conn;
|
1269
1680
|
PGresult *res;
|
1270
1681
|
VALUE error = 0;
|
1271
|
-
Check_Type(rconn, T_DATA);
|
1272
1682
|
conn = pg_get_pgconn(rconn);
|
1273
1683
|
|
1274
1684
|
while ((res = PQgetResult(conn)) != NULL) {
|
@@ -1310,6 +1720,7 @@ void Init_sequel_pg(void) {
|
|
1310
1720
|
|
1311
1721
|
spg_Sequel = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Sequel"));
|
1312
1722
|
spg_Postgres = rb_funcall(spg_Sequel, cg, 1, rb_str_new2("Postgres"));
|
1723
|
+
rb_global_variable(&spg_Sequel);
|
1313
1724
|
|
1314
1725
|
if(rb_obj_respond_to(spg_Postgres, rb_intern("sequel_pg_version_supported?"), 0)) {
|
1315
1726
|
if(!RTEST(rb_funcall(spg_Postgres, rb_intern("sequel_pg_version_supported?"), 1, INT2FIX(SEQUEL_PG_VERSION_INTEGER)))) {
|
@@ -1321,6 +1732,7 @@ void Init_sequel_pg(void) {
|
|
1321
1732
|
|
1322
1733
|
spg_id_BigDecimal = rb_intern("BigDecimal");
|
1323
1734
|
spg_id_new = rb_intern("new");
|
1735
|
+
spg_id_date = rb_intern("date");
|
1324
1736
|
spg_id_local = rb_intern("local");
|
1325
1737
|
spg_id_year = rb_intern("year");
|
1326
1738
|
spg_id_month = rb_intern("month");
|
@@ -1351,6 +1763,12 @@ void Init_sequel_pg(void) {
|
|
1351
1763
|
spg_id_encoding = rb_intern("@encoding");
|
1352
1764
|
spg_id_values = rb_intern("@values");
|
1353
1765
|
|
1766
|
+
spg_id_family = rb_intern("@family");
|
1767
|
+
spg_id_addr = rb_intern("@addr");
|
1768
|
+
spg_id_mask_addr = rb_intern("@mask_addr");
|
1769
|
+
spg_id_lshift = rb_intern("<<");
|
1770
|
+
spg_id_mask = rb_intern("mask");
|
1771
|
+
|
1354
1772
|
spg_sym_utc = ID2SYM(rb_intern("utc"));
|
1355
1773
|
spg_sym_local = ID2SYM(rb_intern("local"));
|
1356
1774
|
spg_sym_map = ID2SYM(rb_intern("map"));
|
@@ -1388,29 +1806,42 @@ void Init_sequel_pg(void) {
|
|
1388
1806
|
spg_sym_name = ID2SYM(rb_intern("name"));
|
1389
1807
|
spg_sym_tid = ID2SYM(rb_intern("tid"));
|
1390
1808
|
spg_sym_int2vector = ID2SYM(rb_intern("int2vector"));
|
1809
|
+
spg_sym_inet = ID2SYM(rb_intern("inet"));
|
1810
|
+
spg_sym_cidr = ID2SYM(rb_intern("cidr"));
|
1391
1811
|
|
1392
1812
|
spg_Blob = rb_funcall(rb_funcall(spg_Sequel, cg, 1, rb_str_new2("SQL")), cg, 1, rb_str_new2("Blob"));
|
1813
|
+
rb_global_variable(&spg_Blob);
|
1814
|
+
spg_Blob_instance = rb_obj_freeze(rb_funcall(spg_Blob, spg_id_new, 0));
|
1815
|
+
rb_global_variable(&spg_Blob_instance);
|
1393
1816
|
spg_SQLTime= rb_funcall(spg_Sequel, cg, 1, rb_str_new2("SQLTime"));
|
1817
|
+
rb_global_variable(&spg_SQLTime);
|
1394
1818
|
spg_Kernel = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Kernel"));
|
1819
|
+
rb_global_variable(&spg_Kernel);
|
1395
1820
|
spg_Date = rb_funcall(rb_cObject, cg, 1, rb_str_new2("Date"));
|
1821
|
+
rb_global_variable(&spg_Date);
|
1822
|
+
spg_DateTime = rb_funcall(rb_cObject, cg, 1, rb_str_new2("DateTime"));
|
1823
|
+
rb_global_variable(&spg_DateTime);
|
1396
1824
|
spg_PGError = rb_funcall(rb_funcall(rb_cObject, cg, 1, rb_str_new2("PG")), cg, 1, rb_str_new2("Error"));
|
1825
|
+
rb_global_variable(&spg_PGError);
|
1397
1826
|
|
1398
1827
|
spg_nan = rb_eval_string("0.0/0.0");
|
1399
|
-
spg_pos_inf = rb_eval_string("1.0/0.0");
|
1400
|
-
spg_neg_inf = rb_eval_string("-1.0/0.0");
|
1401
|
-
spg_usec_per_day = ULL2NUM(86400000000ULL);
|
1402
|
-
|
1403
|
-
rb_global_variable(&spg_Sequel);
|
1404
|
-
rb_global_variable(&spg_Blob);
|
1405
|
-
rb_global_variable(&spg_Kernel);
|
1406
|
-
rb_global_variable(&spg_Date);
|
1407
|
-
rb_global_variable(&spg_SQLTime);
|
1408
|
-
rb_global_variable(&spg_PGError);
|
1409
1828
|
rb_global_variable(&spg_nan);
|
1829
|
+
spg_pos_inf = rb_eval_string("1.0/0.0");
|
1410
1830
|
rb_global_variable(&spg_pos_inf);
|
1831
|
+
spg_neg_inf = rb_eval_string("-1.0/0.0");
|
1411
1832
|
rb_global_variable(&spg_neg_inf);
|
1833
|
+
spg_usec_per_day = ULL2NUM(86400000000ULL);
|
1412
1834
|
rb_global_variable(&spg_usec_per_day);
|
1413
1835
|
|
1836
|
+
rb_require("ipaddr");
|
1837
|
+
spg_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
|
1838
|
+
rb_global_variable(&spg_IPAddr);
|
1839
|
+
spg_use_ipaddr_alloc = RTEST(rb_eval_string("IPAddr.new.instance_variables.sort == [:@addr, :@family, :@mask_addr]"));
|
1840
|
+
spg_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");
|
1841
|
+
rb_global_variable(&spg_vmasks4);
|
1842
|
+
spg_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");
|
1843
|
+
rb_global_variable(&spg_vmasks6);
|
1844
|
+
|
1414
1845
|
c = rb_funcall(spg_Postgres, cg, 1, rb_str_new2("Dataset"));
|
1415
1846
|
rb_undef_method(c, "yield_hash_rows");
|
1416
1847
|
rb_define_private_method(c, "yield_hash_rows", spg_yield_hash_rows, 2);
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_pg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pg
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 4.
|
33
|
+
version: 4.38.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 4.
|
40
|
+
version: 4.38.0
|
41
41
|
description: |
|
42
42
|
sequel_pg overwrites the inner loop of the Sequel postgres
|
43
43
|
adapter row fetching code with a C version. The C version
|
@@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
version: '0'
|
92
92
|
requirements: []
|
93
93
|
rubyforge_project:
|
94
|
-
rubygems_version:
|
94
|
+
rubygems_version: 2.7.6
|
95
95
|
signing_key:
|
96
96
|
specification_version: 4
|
97
97
|
summary: Faster SELECTs when using Sequel with pg
|