sequel_pg 1.9.0 → 1.10.0
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 +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
|