pg 0.18.0 → 1.1.4
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/BSDL +2 -2
- data/ChangeLog +1221 -4
- data/History.rdoc +200 -0
- data/Manifest.txt +5 -18
- data/README-Windows.rdoc +15 -26
- data/README.rdoc +27 -10
- data/Rakefile +33 -24
- data/Rakefile.cross +57 -39
- data/ext/errorcodes.def +37 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +16 -1
- data/ext/extconf.rb +29 -35
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +27 -39
- data/ext/pg.c +27 -53
- data/ext/pg.h +66 -83
- data/ext/pg_binary_decoder.c +75 -6
- data/ext/pg_binary_encoder.c +14 -12
- data/ext/pg_coder.c +83 -13
- data/ext/pg_connection.c +627 -351
- data/ext/pg_copy_coder.c +44 -9
- data/ext/pg_result.c +364 -134
- data/ext/pg_text_decoder.c +605 -46
- data/ext/pg_text_encoder.c +95 -76
- data/ext/pg_tuple.c +541 -0
- data/ext/pg_type_map.c +20 -13
- data/ext/pg_type_map_by_column.c +7 -7
- data/ext/pg_type_map_by_mri_type.c +2 -2
- data/ext/pg_type_map_in_ruby.c +4 -7
- data/ext/util.c +7 -7
- data/ext/util.h +3 -3
- data/lib/pg/basic_type_mapping.rb +105 -45
- data/lib/pg/binary_decoder.rb +22 -0
- data/lib/pg/coder.rb +1 -1
- data/lib/pg/connection.rb +109 -39
- data/lib/pg/constants.rb +1 -1
- data/lib/pg/exceptions.rb +1 -1
- data/lib/pg/result.rb +11 -6
- data/lib/pg/text_decoder.rb +25 -20
- data/lib/pg/text_encoder.rb +43 -1
- data/lib/pg/tuple.rb +30 -0
- data/lib/pg/type_map_by_column.rb +1 -1
- data/lib/pg.rb +21 -11
- data/spec/helpers.rb +50 -25
- data/spec/pg/basic_type_mapping_spec.rb +287 -30
- data/spec/pg/connection_spec.rb +695 -282
- data/spec/pg/connection_sync_spec.rb +41 -0
- data/spec/pg/result_spec.rb +59 -17
- data/spec/pg/tuple_spec.rb +280 -0
- data/spec/pg/type_map_by_class_spec.rb +3 -3
- data/spec/pg/type_map_by_column_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +2 -2
- data/spec/pg/type_map_by_oid_spec.rb +1 -1
- data/spec/pg/type_map_in_ruby_spec.rb +1 -1
- data/spec/pg/type_map_spec.rb +1 -1
- data/spec/pg/type_spec.rb +319 -35
- data/spec/pg_spec.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +68 -68
- metadata.gz.sig +0 -0
- data/sample/array_insert.rb +0 -20
- data/sample/async_api.rb +0 -106
- data/sample/async_copyto.rb +0 -39
- data/sample/async_mixed.rb +0 -56
- data/sample/check_conn.rb +0 -21
- data/sample/copyfrom.rb +0 -81
- data/sample/copyto.rb +0 -19
- data/sample/cursor.rb +0 -21
- data/sample/disk_usage_report.rb +0 -186
- data/sample/issue-119.rb +0 -94
- data/sample/losample.rb +0 -69
- data/sample/minimal-testcase.rb +0 -17
- data/sample/notify_wait.rb +0 -72
- data/sample/pg_statistics.rb +0 -294
- data/sample/replication_monitor.rb +0 -231
- data/sample/test_binary_values.rb +0 -33
- data/sample/wal_shipper.rb +0 -434
- data/sample/warehouse_partitions.rb +0 -320
data/ext/pg.c
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
/*
|
2
2
|
* pg.c - Toplevel extension
|
3
|
-
* $Id: pg.c,v
|
3
|
+
* $Id: pg.c,v 2d334508484a 2018/08/27 11:33:43 lars $
|
4
4
|
*
|
5
5
|
* Author/s:
|
6
6
|
*
|
7
7
|
* - Jeff Davis <ruby-pg@j-davis.com>
|
8
8
|
* - Guy Decoux (ts) <decoux@moulon.inra.fr>
|
9
9
|
* - Michael Granger <ged@FaerieMUD.org>
|
10
|
+
* - Lars Kanis <lars@greiz-reinsdorf.de>
|
10
11
|
* - Dave Lee
|
11
12
|
* - Eiji Matsumoto <usagi@ruby.club.or.jp>
|
12
13
|
* - Yukihiro Matsumoto <matz@ruby-lang.org>
|
@@ -15,10 +16,10 @@
|
|
15
16
|
* See Contributors.rdoc for the many additional fine people that have contributed
|
16
17
|
* to this library over the years.
|
17
18
|
*
|
18
|
-
* Copyright (c) 1997-
|
19
|
+
* Copyright (c) 1997-2016 by the authors.
|
19
20
|
*
|
20
21
|
* You may redistribute this software under the same terms as Ruby itself; see
|
21
|
-
*
|
22
|
+
* https://www.ruby-lang.org/en/about/license.txt or the BSDL file in the source
|
22
23
|
* for details.
|
23
24
|
*
|
24
25
|
* Portions of the code are from the PostgreSQL project, and are distributed
|
@@ -47,6 +48,7 @@
|
|
47
48
|
|
48
49
|
#include "pg.h"
|
49
50
|
|
51
|
+
int pg_skip_deprecation_warning;
|
50
52
|
VALUE rb_mPG;
|
51
53
|
VALUE rb_mPGconstants;
|
52
54
|
|
@@ -68,7 +70,6 @@ VALUE rb_mPGconstants;
|
|
68
70
|
* M17n functions
|
69
71
|
*/
|
70
72
|
|
71
|
-
#ifdef M17N_SUPPORTED
|
72
73
|
/**
|
73
74
|
* The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
|
74
75
|
*/
|
@@ -142,9 +143,6 @@ pg_find_or_create_johab(void)
|
|
142
143
|
}
|
143
144
|
|
144
145
|
enc_index = rb_define_dummy_encoding(aliases[0]);
|
145
|
-
for (i = 1; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
|
146
|
-
ENC_ALIAS(aliases[i], aliases[0]);
|
147
|
-
}
|
148
146
|
return rb_enc_from_index(enc_index);
|
149
147
|
}
|
150
148
|
|
@@ -228,8 +226,6 @@ pg_get_rb_encoding_as_pg_encoding( rb_encoding *enc )
|
|
228
226
|
return encname;
|
229
227
|
}
|
230
228
|
|
231
|
-
#endif /* M17N_SUPPORTED */
|
232
|
-
|
233
229
|
|
234
230
|
/*
|
235
231
|
* Ensures that the given string has enough capacity to take expand_len
|
@@ -252,52 +248,33 @@ pg_get_rb_encoding_as_pg_encoding( rb_encoding *enc )
|
|
252
248
|
* char *current_out, *end_capa;
|
253
249
|
* PG_RB_STR_NEW( string, current_out, end_capa );
|
254
250
|
* while( data_is_going_to_be_processed ){
|
255
|
-
* PG_RB_STR_ENSURE_CAPA( string, 2 current_out, end_capa );
|
251
|
+
* PG_RB_STR_ENSURE_CAPA( string, 2, current_out, end_capa );
|
256
252
|
* *current_out++ = databyte1;
|
257
253
|
* *current_out++ = databyte2;
|
258
254
|
* }
|
259
255
|
* rb_str_set_len( string, current_out - RSTRING_PTR(string) );
|
260
256
|
*
|
261
257
|
*/
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
rb_str_modify_expand( str, (curr_len + expand_len) * 2 - curr_capa );
|
272
|
-
curr_ptr = RSTRING_PTR(str) + curr_len;
|
273
|
-
}
|
274
|
-
if( end_ptr )
|
275
|
-
*end_ptr = RSTRING_PTR(str) + rb_str_capacity( str );
|
276
|
-
return curr_ptr;
|
277
|
-
}
|
278
|
-
#else
|
279
|
-
/* Use the more portable version */
|
280
|
-
char *
|
281
|
-
pg_rb_str_ensure_capa( VALUE str, long expand_len, char *curr_ptr, char **end_ptr )
|
282
|
-
{
|
283
|
-
long curr_len = curr_ptr - RSTRING_PTR(str);
|
284
|
-
long curr_capa = RSTRING_LEN( str );
|
285
|
-
if( curr_capa < curr_len + expand_len ){
|
286
|
-
rb_str_resize( str, (curr_len + expand_len) * 2 - curr_capa );
|
287
|
-
curr_ptr = RSTRING_PTR(str) + curr_len;
|
288
|
-
}
|
289
|
-
if( end_ptr )
|
290
|
-
*end_ptr = RSTRING_PTR(str) + RSTRING_LEN(str);
|
291
|
-
return curr_ptr;
|
258
|
+
char *
|
259
|
+
pg_rb_str_ensure_capa( VALUE str, long expand_len, char *curr_ptr, char **end_ptr )
|
260
|
+
{
|
261
|
+
long curr_len = curr_ptr - RSTRING_PTR(str);
|
262
|
+
long curr_capa = rb_str_capacity( str );
|
263
|
+
if( curr_capa < curr_len + expand_len ){
|
264
|
+
rb_str_set_len( str, curr_len );
|
265
|
+
rb_str_modify_expand( str, (curr_len + expand_len) * 2 - curr_capa );
|
266
|
+
curr_ptr = RSTRING_PTR(str) + curr_len;
|
292
267
|
}
|
293
|
-
|
268
|
+
if( end_ptr )
|
269
|
+
*end_ptr = RSTRING_PTR(str) + rb_str_capacity( str );
|
270
|
+
return curr_ptr;
|
271
|
+
}
|
294
272
|
|
295
273
|
|
296
274
|
/**************************************************************************
|
297
275
|
* Module Methods
|
298
276
|
**************************************************************************/
|
299
277
|
|
300
|
-
#ifdef HAVE_PQLIBVERSION
|
301
278
|
/*
|
302
279
|
* call-seq:
|
303
280
|
* PG.library_version -> Integer
|
@@ -315,7 +292,6 @@ pg_s_library_version(VALUE self)
|
|
315
292
|
UNUSED( self );
|
316
293
|
return INT2NUM(PQlibVersion());
|
317
294
|
}
|
318
|
-
#endif
|
319
295
|
|
320
296
|
|
321
297
|
/*
|
@@ -403,15 +379,20 @@ pg_s_init_ssl(VALUE self, VALUE do_ssl)
|
|
403
379
|
void
|
404
380
|
Init_pg_ext()
|
405
381
|
{
|
382
|
+
if( RTEST(rb_eval_string("ENV['PG_SKIP_DEPRECATION_WARNING']")) ){
|
383
|
+
/* Set all bits to disable all deprecation warnings. */
|
384
|
+
pg_skip_deprecation_warning = 0xFFFF;
|
385
|
+
} else {
|
386
|
+
pg_skip_deprecation_warning = 0;
|
387
|
+
}
|
388
|
+
|
406
389
|
rb_mPG = rb_define_module( "PG" );
|
407
390
|
rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" );
|
408
391
|
|
409
392
|
/*************************
|
410
393
|
* PG module methods
|
411
394
|
*************************/
|
412
|
-
#ifdef HAVE_PQLIBVERSION
|
413
395
|
rb_define_singleton_method( rb_mPG, "library_version", pg_s_library_version, 0 );
|
414
|
-
#endif
|
415
396
|
rb_define_singleton_method( rb_mPG, "isthreadsafe", pg_s_threadsafe_p, 0 );
|
416
397
|
SINGLETON_ALIAS( rb_mPG, "is_threadsafe?", "isthreadsafe" );
|
417
398
|
SINGLETON_ALIAS( rb_mPG, "threadsafe?", "isthreadsafe" );
|
@@ -477,7 +458,6 @@ Init_pg_ext()
|
|
477
458
|
/* Verbose error verbosity level (#set_error_verbosity) */
|
478
459
|
rb_define_const(rb_mPGconstants, "PQERRORS_VERBOSE", INT2FIX(PQERRORS_VERBOSE));
|
479
460
|
|
480
|
-
#ifdef HAVE_PQPING
|
481
461
|
/****** PG::Connection CLASS CONSTANTS: Check Server Status ******/
|
482
462
|
|
483
463
|
/* Server is accepting connections. */
|
@@ -488,7 +468,6 @@ Init_pg_ext()
|
|
488
468
|
rb_define_const(rb_mPGconstants, "PQPING_NO_RESPONSE", INT2FIX(PQPING_NO_RESPONSE));
|
489
469
|
/* Connection not attempted (bad params). */
|
490
470
|
rb_define_const(rb_mPGconstants, "PQPING_NO_ATTEMPT", INT2FIX(PQPING_NO_ATTEMPT));
|
491
|
-
#endif
|
492
471
|
|
493
472
|
/****** PG::Connection CLASS CONSTANTS: Large Objects ******/
|
494
473
|
|
@@ -523,13 +502,9 @@ Init_pg_ext()
|
|
523
502
|
/* #result_status constant: A fatal error occurred. */
|
524
503
|
rb_define_const(rb_mPGconstants, "PGRES_FATAL_ERROR", INT2FIX(PGRES_FATAL_ERROR));
|
525
504
|
/* #result_status constant: Copy In/Out data transfer in progress. */
|
526
|
-
#ifdef HAVE_CONST_PGRES_COPY_BOTH
|
527
505
|
rb_define_const(rb_mPGconstants, "PGRES_COPY_BOTH", INT2FIX(PGRES_COPY_BOTH));
|
528
|
-
#endif
|
529
506
|
/* #result_status constant: Single tuple from larger resultset. */
|
530
|
-
#ifdef HAVE_CONST_PGRES_SINGLE_TUPLE
|
531
507
|
rb_define_const(rb_mPGconstants, "PGRES_SINGLE_TUPLE", INT2FIX(PGRES_SINGLE_TUPLE));
|
532
|
-
#endif
|
533
508
|
|
534
509
|
/****** Result CONSTANTS: result error field codes ******/
|
535
510
|
|
@@ -641,9 +616,7 @@ Init_pg_ext()
|
|
641
616
|
/* Add the constants to the toplevel namespace */
|
642
617
|
rb_include_module( rb_mPG, rb_mPGconstants );
|
643
618
|
|
644
|
-
#ifdef M17N_SUPPORTED
|
645
619
|
enc_pg2ruby = st_init_numtable();
|
646
|
-
#endif
|
647
620
|
|
648
621
|
/* Initialize the main extension classes */
|
649
622
|
init_pg_connection();
|
@@ -662,5 +635,6 @@ Init_pg_ext()
|
|
662
635
|
init_pg_binary_encoder();
|
663
636
|
init_pg_binary_decoder();
|
664
637
|
init_pg_copycoder();
|
638
|
+
init_pg_tuple();
|
665
639
|
}
|
666
640
|
|
data/ext/pg.h
CHANGED
@@ -9,95 +9,27 @@
|
|
9
9
|
#include <stdio.h>
|
10
10
|
#include <stdlib.h>
|
11
11
|
#include <sys/types.h>
|
12
|
+
#if !defined(_WIN32)
|
13
|
+
# include <sys/time.h>
|
14
|
+
#endif
|
12
15
|
#if defined(HAVE_UNISTD_H) && !defined(_WIN32)
|
13
16
|
# include <unistd.h>
|
14
17
|
#endif /* HAVE_UNISTD_H */
|
15
18
|
|
16
19
|
/* Ruby headers */
|
17
20
|
#include "ruby.h"
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#elif HAVE_ST_H
|
21
|
-
# include "st.h"
|
22
|
-
#endif
|
21
|
+
#include "ruby/st.h"
|
22
|
+
#include "ruby/encoding.h"
|
23
23
|
|
24
|
-
#
|
25
|
-
# include "ruby/encoding.h"
|
26
|
-
# define M17N_SUPPORTED
|
27
|
-
# ifdef HAVE_RB_ENCDB_ALIAS
|
28
|
-
extern int rb_encdb_alias(const char *, const char *);
|
29
|
-
# define ENC_ALIAS(name, orig) rb_encdb_alias((name), (orig))
|
30
|
-
# elif HAVE_RB_ENC_ALIAS
|
31
|
-
extern int rb_enc_alias(const char *, const char *);
|
32
|
-
# define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
|
33
|
-
# else
|
34
|
-
extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
|
35
|
-
# define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
|
36
|
-
# endif
|
37
|
-
|
38
|
-
|
39
|
-
# if !defined(ENCODING_SET_INLINED)
|
40
|
-
/* Rubinius doesn't define ENCODING_SET_INLINED, so we fall back to the more
|
41
|
-
* portable version.
|
42
|
-
*/
|
43
|
-
# define PG_ENCODING_SET_NOCHECK(obj,i) \
|
44
|
-
do { \
|
45
|
-
rb_enc_set_index((obj), (i)); \
|
46
|
-
} while(0)
|
47
|
-
# else
|
48
|
-
# define PG_ENCODING_SET_NOCHECK(obj,i) \
|
24
|
+
#define PG_ENCODING_SET_NOCHECK(obj,i) \
|
49
25
|
do { \
|
50
26
|
if ((i) < ENCODING_INLINE_MAX) \
|
51
27
|
ENCODING_SET_INLINED((obj), (i)); \
|
52
28
|
else \
|
53
29
|
rb_enc_set_index((obj), (i)); \
|
54
30
|
} while(0)
|
55
|
-
# endif
|
56
|
-
|
57
|
-
#else
|
58
|
-
# define PG_ENCODING_SET_NOCHECK(obj,i) /* nothing */
|
59
|
-
#endif
|
60
|
-
|
61
|
-
#if RUBY_VM != 1
|
62
|
-
# define RUBY_18_COMPAT
|
63
|
-
#endif
|
64
31
|
|
65
|
-
#
|
66
|
-
# define RARRAY_LEN(x) RARRAY((x))->len
|
67
|
-
#endif /* RARRAY_LEN */
|
68
|
-
|
69
|
-
#ifndef RSTRING_LEN
|
70
|
-
# define RSTRING_LEN(x) RSTRING((x))->len
|
71
|
-
#endif /* RSTRING_LEN */
|
72
|
-
|
73
|
-
#ifndef RSTRING_PTR
|
74
|
-
# define RSTRING_PTR(x) RSTRING((x))->ptr
|
75
|
-
#endif /* RSTRING_PTR */
|
76
|
-
|
77
|
-
#ifndef StringValuePtr
|
78
|
-
# define StringValuePtr(x) STR2CSTR(x)
|
79
|
-
#endif /* StringValuePtr */
|
80
|
-
|
81
|
-
#ifdef RUBY_18_COMPAT
|
82
|
-
# define rb_io_stdio_file GetWriteFile
|
83
|
-
# include "rubyio.h"
|
84
|
-
#else
|
85
|
-
# include "ruby/io.h"
|
86
|
-
#endif
|
87
|
-
|
88
|
-
#ifdef RUBINIUS
|
89
|
-
/* Workaround for wrong FIXNUM_MAX definition */
|
90
|
-
typedef intptr_t native_int;
|
91
|
-
#endif
|
92
|
-
|
93
|
-
#ifndef RETURN_SIZED_ENUMERATOR
|
94
|
-
#define RETURN_SIZED_ENUMERATOR(obj, argc, argv, size_fn) RETURN_ENUMERATOR((obj), (argc), (argv))
|
95
|
-
#endif
|
96
|
-
|
97
|
-
#ifndef HAVE_RB_HASH_DUP
|
98
|
-
/* Rubinius doesn't define rb_hash_dup() */
|
99
|
-
#define rb_hash_dup(tuple) rb_funcall((tuple), rb_intern("dup"), 0)
|
100
|
-
#endif
|
32
|
+
#include "ruby/io.h"
|
101
33
|
|
102
34
|
#ifndef timeradd
|
103
35
|
#define timeradd(a, b, result) \
|
@@ -133,6 +65,19 @@
|
|
133
65
|
typedef long suseconds_t;
|
134
66
|
#endif
|
135
67
|
|
68
|
+
#if defined(HAVE_VARIABLE_LENGTH_ARRAYS)
|
69
|
+
#define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) type name[(len)];
|
70
|
+
#else
|
71
|
+
#define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) \
|
72
|
+
type name[(maxlen)] = {(len)>(maxlen) ? (rb_raise(rb_eArgError, "Number of " #name " (%d) exceeds allowed maximum of " #maxlen, (len) ), (type)1) : (type)0};
|
73
|
+
|
74
|
+
#define PG_MAX_COLUMNS 4000
|
75
|
+
#endif
|
76
|
+
|
77
|
+
#ifndef RARRAY_AREF
|
78
|
+
#define RARRAY_AREF(a, i) (RARRAY_PTR(a)[i])
|
79
|
+
#endif
|
80
|
+
|
136
81
|
/* The data behind each PG::Connection object */
|
137
82
|
typedef struct {
|
138
83
|
PGconn *pgconn;
|
@@ -156,6 +101,13 @@ typedef struct {
|
|
156
101
|
/* Kind of PG::Coder object for casting COPY rows to ruby values */
|
157
102
|
VALUE decoder_for_get_copy_data;
|
158
103
|
|
104
|
+
/* enable/disable guessing size of PGresult's allocated memory */
|
105
|
+
int guess_result_memsize;
|
106
|
+
|
107
|
+
#if defined(_WIN32)
|
108
|
+
/* File descriptor to be used for rb_w32_unwrap_io_handle() */
|
109
|
+
int ruby_sd;
|
110
|
+
#endif
|
159
111
|
} t_pg_connection;
|
160
112
|
|
161
113
|
typedef struct pg_coder t_pg_coder;
|
@@ -186,9 +138,15 @@ typedef struct {
|
|
186
138
|
*/
|
187
139
|
int nfields;
|
188
140
|
|
141
|
+
/* Size of PGresult as published to ruby memory management. */
|
142
|
+
ssize_t result_size;
|
143
|
+
|
189
144
|
/* Prefilled tuple Hash with fnames[] as keys. */
|
190
145
|
VALUE tuple_hash;
|
191
146
|
|
147
|
+
/* Hash with fnames[] to field number mapping. */
|
148
|
+
VALUE field_map;
|
149
|
+
|
192
150
|
/* List of field names as frozen String objects.
|
193
151
|
* Only valid if nfields != -1
|
194
152
|
*/
|
@@ -196,8 +154,8 @@ typedef struct {
|
|
196
154
|
} t_pg_result;
|
197
155
|
|
198
156
|
|
199
|
-
typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE
|
200
|
-
typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, char *, int, int, int, int);
|
157
|
+
typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *, int);
|
158
|
+
typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, const char *, int, int, int, int);
|
201
159
|
typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE);
|
202
160
|
typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE);
|
203
161
|
typedef int (* t_pg_fit_to_copy_get)(VALUE);
|
@@ -205,12 +163,23 @@ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
|
|
205
163
|
typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
|
206
164
|
typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
|
207
165
|
|
166
|
+
#define PG_CODER_TIMESTAMP_DB_UTC 0x0
|
167
|
+
#define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
|
168
|
+
#define PG_CODER_TIMESTAMP_APP_UTC 0x0
|
169
|
+
#define PG_CODER_TIMESTAMP_APP_LOCAL 0x2
|
170
|
+
#define PG_CODER_FORMAT_ERROR_MASK 0xc
|
171
|
+
#define PG_CODER_FORMAT_ERROR_TO_RAISE 0x4
|
172
|
+
#define PG_CODER_FORMAT_ERROR_TO_STRING 0x8
|
173
|
+
#define PG_CODER_FORMAT_ERROR_TO_PARTIAL 0xc
|
174
|
+
|
208
175
|
struct pg_coder {
|
209
176
|
t_pg_coder_enc_func enc_func;
|
210
177
|
t_pg_coder_dec_func dec_func;
|
211
178
|
VALUE coder_obj;
|
212
179
|
Oid oid;
|
213
180
|
int format;
|
181
|
+
/* OR-ed values out of PG_CODER_* */
|
182
|
+
int flags;
|
214
183
|
};
|
215
184
|
|
216
185
|
typedef struct {
|
@@ -247,6 +216,7 @@ typedef struct {
|
|
247
216
|
* Globals
|
248
217
|
**************************************************************************/
|
249
218
|
|
219
|
+
extern int pg_skip_deprecation_warning;
|
250
220
|
extern VALUE rb_mPG;
|
251
221
|
extern VALUE rb_ePGerror;
|
252
222
|
extern VALUE rb_eServerError;
|
@@ -309,10 +279,12 @@ void init_pg_text_encoder _(( void ));
|
|
309
279
|
void init_pg_text_decoder _(( void ));
|
310
280
|
void init_pg_binary_encoder _(( void ));
|
311
281
|
void init_pg_binary_decoder _(( void ));
|
282
|
+
void init_pg_tuple _(( void ));
|
312
283
|
VALUE lookup_error_class _(( const char * ));
|
313
|
-
VALUE pg_bin_dec_bytea _(( t_pg_coder*, char *, int, int, int, int ));
|
314
|
-
VALUE pg_text_dec_string _(( t_pg_coder*, char *, int, int, int, int ));
|
315
|
-
int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE
|
284
|
+
VALUE pg_bin_dec_bytea _(( t_pg_coder*, const char *, int, int, int, int ));
|
285
|
+
VALUE pg_text_dec_string _(( t_pg_coder*, const char *, int, int, int, int ));
|
286
|
+
int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *, int));
|
287
|
+
int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
|
316
288
|
t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
|
317
289
|
t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
|
318
290
|
void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
|
@@ -353,6 +325,7 @@ VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
|
|
353
325
|
PGresult* pgresult_get _(( VALUE ));
|
354
326
|
VALUE pg_result_check _(( VALUE ));
|
355
327
|
VALUE pg_result_clear _(( VALUE ));
|
328
|
+
VALUE pg_tuple_new _(( VALUE, int ));
|
356
329
|
|
357
330
|
/*
|
358
331
|
* Fetch the data pointer for the result object
|
@@ -360,7 +333,7 @@ VALUE pg_result_clear _(( VALUE ));
|
|
360
333
|
static inline t_pg_result *
|
361
334
|
pgresult_get_this( VALUE self )
|
362
335
|
{
|
363
|
-
t_pg_result *this =
|
336
|
+
t_pg_result *this = RTYPEDDATA_DATA(self);
|
364
337
|
|
365
338
|
if( this == NULL )
|
366
339
|
rb_raise(rb_ePGerror, "result has been cleared");
|
@@ -369,14 +342,24 @@ pgresult_get_this( VALUE self )
|
|
369
342
|
}
|
370
343
|
|
371
344
|
|
372
|
-
#ifdef M17N_SUPPORTED
|
373
345
|
rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int ));
|
374
346
|
rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * ));
|
375
347
|
const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * ));
|
376
348
|
rb_encoding *pg_conn_enc_get _(( PGconn * ));
|
377
|
-
#endif /* M17N_SUPPORTED */
|
378
349
|
|
379
350
|
void notice_receiver_proxy(void *arg, const PGresult *result);
|
380
351
|
void notice_processor_proxy(void *arg, const char *message);
|
381
352
|
|
353
|
+
/* reports if `-W' specified and PG_SKIP_DEPRECATION_WARNING environment variable isn't set
|
354
|
+
*
|
355
|
+
* message_id identifies the warning, so that it's reported only once.
|
356
|
+
*/
|
357
|
+
#define pg_deprecated(message_id, format_args) \
|
358
|
+
do { \
|
359
|
+
if( !(pg_skip_deprecation_warning & (1 << message_id)) ){ \
|
360
|
+
pg_skip_deprecation_warning |= 1 << message_id; \
|
361
|
+
rb_warning format_args; \
|
362
|
+
} \
|
363
|
+
} while(0);
|
364
|
+
|
382
365
|
#endif /* end __pg_h */
|
data/ext/pg_binary_decoder.c
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
/*
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
3
|
-
* $Id
|
3
|
+
* $Id$
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
7
|
+
#include "ruby/version.h"
|
7
8
|
#include "pg.h"
|
8
9
|
#include "util.h"
|
10
|
+
#ifdef HAVE_INTTYPES_H
|
9
11
|
#include <inttypes.h>
|
12
|
+
#endif
|
10
13
|
|
11
14
|
VALUE rb_mPG_BinaryDecoder;
|
12
15
|
|
@@ -19,7 +22,7 @@ VALUE rb_mPG_BinaryDecoder;
|
|
19
22
|
*
|
20
23
|
*/
|
21
24
|
static VALUE
|
22
|
-
pg_bin_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
25
|
+
pg_bin_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
23
26
|
{
|
24
27
|
if (len < 1) {
|
25
28
|
rb_raise( rb_eTypeError, "wrong data for binary boolean converter in tuple %d field %d", tuple, field);
|
@@ -35,7 +38,7 @@ pg_bin_dec_boolean(t_pg_coder *conv, char *val, int len, int tuple, int field, i
|
|
35
38
|
*
|
36
39
|
*/
|
37
40
|
static VALUE
|
38
|
-
pg_bin_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
41
|
+
pg_bin_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
39
42
|
{
|
40
43
|
switch( len ){
|
41
44
|
case 2:
|
@@ -57,7 +60,7 @@ pg_bin_dec_integer(t_pg_coder *conv, char *val, int len, int tuple, int field, i
|
|
57
60
|
*
|
58
61
|
*/
|
59
62
|
static VALUE
|
60
|
-
pg_bin_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
63
|
+
pg_bin_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
61
64
|
{
|
62
65
|
union {
|
63
66
|
float f;
|
@@ -89,7 +92,7 @@ pg_bin_dec_float(t_pg_coder *conv, char *val, int len, int tuple, int field, int
|
|
89
92
|
*
|
90
93
|
*/
|
91
94
|
VALUE
|
92
|
-
pg_bin_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
95
|
+
pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
93
96
|
{
|
94
97
|
VALUE ret;
|
95
98
|
ret = rb_tainted_str_new( val, len );
|
@@ -104,7 +107,7 @@ pg_bin_dec_bytea(t_pg_coder *conv, char *val, int len, int tuple, int field, int
|
|
104
107
|
*
|
105
108
|
*/
|
106
109
|
static VALUE
|
107
|
-
pg_bin_dec_to_base64(t_pg_coder *conv, char *val, int len, int tuple, int field, int enc_idx)
|
110
|
+
pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
108
111
|
{
|
109
112
|
t_pg_composite_coder *this = (t_pg_composite_coder *)conv;
|
110
113
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
|
@@ -128,6 +131,70 @@ pg_bin_dec_to_base64(t_pg_coder *conv, char *val, int len, int tuple, int field,
|
|
128
131
|
return out_value;
|
129
132
|
}
|
130
133
|
|
134
|
+
#define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
|
135
|
+
#define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
|
136
|
+
|
137
|
+
/*
|
138
|
+
* Document-class: PG::BinaryDecoder::Timestamp < PG::SimpleDecoder
|
139
|
+
*
|
140
|
+
* This is a decoder class for conversion of PostgreSQL binary timestamps
|
141
|
+
* to Ruby Time objects.
|
142
|
+
*
|
143
|
+
* The following flags can be used to specify timezone interpretation:
|
144
|
+
* * +PG::Coder::TIMESTAMP_DB_UTC+ : Interpret timestamp as UTC time (default)
|
145
|
+
* * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Interpret timestamp as local time
|
146
|
+
* * +PG::Coder::TIMESTAMP_APP_UTC+ : Return timestamp as UTC time (default)
|
147
|
+
* * +PG::Coder::TIMESTAMP_APP_LOCAL+ : Return timestamp as local time
|
148
|
+
*
|
149
|
+
* Example:
|
150
|
+
* deco = PG::BinaryDecoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC | PG::Coder::TIMESTAMP_APP_LOCAL)
|
151
|
+
* deco.decode("\0"*8) # => 2000-01-01 01:00:00 +0100
|
152
|
+
*/
|
153
|
+
static VALUE
|
154
|
+
pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
155
|
+
{
|
156
|
+
int64_t timestamp;
|
157
|
+
int64_t sec;
|
158
|
+
int64_t nsec;
|
159
|
+
VALUE t;
|
160
|
+
|
161
|
+
if( len != sizeof(timestamp) ){
|
162
|
+
rb_raise( rb_eTypeError, "wrong data for timestamp converter in tuple %d field %d length %d", tuple, field, len);
|
163
|
+
}
|
164
|
+
|
165
|
+
timestamp = read_nbo64(val);
|
166
|
+
|
167
|
+
switch(timestamp){
|
168
|
+
case PG_INT64_MAX:
|
169
|
+
return rb_str_new2("infinity");
|
170
|
+
case PG_INT64_MIN:
|
171
|
+
return rb_str_new2("-infinity");
|
172
|
+
default:
|
173
|
+
/* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
|
174
|
+
* Adjust the 30 years difference. */
|
175
|
+
sec = (timestamp / 1000000) + 10957L * 24L * 3600L;
|
176
|
+
nsec = (timestamp % 1000000) * 1000;
|
177
|
+
|
178
|
+
#if (RUBY_API_VERSION_MAJOR > 2 || (RUBY_API_VERSION_MAJOR == 2 && RUBY_API_VERSION_MINOR >= 3)) && defined(NEGATIVE_TIME_T) && defined(SIZEOF_TIME_T) && SIZEOF_TIME_T >= 8
|
179
|
+
/* Fast path for time conversion */
|
180
|
+
{
|
181
|
+
struct timespec ts = {sec, nsec};
|
182
|
+
t = rb_time_timespec_new(&ts, conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL ? INT_MAX : INT_MAX-1);
|
183
|
+
}
|
184
|
+
#else
|
185
|
+
t = rb_funcall(rb_cTime, rb_intern("at"), 2, LL2NUM(sec), LL2NUM(nsec / 1000));
|
186
|
+
if( !(conv->flags & PG_CODER_TIMESTAMP_APP_LOCAL) ) {
|
187
|
+
t = rb_funcall(t, rb_intern("utc"), 0);
|
188
|
+
}
|
189
|
+
#endif
|
190
|
+
if( conv->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
|
191
|
+
/* interpret it as local time */
|
192
|
+
t = rb_funcall(t, rb_intern("-"), 1, rb_funcall(t, rb_intern("utc_offset"), 0));
|
193
|
+
}
|
194
|
+
return t;
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
131
198
|
/*
|
132
199
|
* Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
|
133
200
|
*
|
@@ -154,6 +221,8 @@ init_pg_binary_decoder()
|
|
154
221
|
pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
|
155
222
|
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
|
156
223
|
pg_define_coder( "Bytea", pg_bin_dec_bytea, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
|
224
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
|
225
|
+
pg_define_coder( "Timestamp", pg_bin_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
|
157
226
|
|
158
227
|
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "ToBase64", rb_cPG_CompositeDecoder ); */
|
159
228
|
pg_define_coder( "ToBase64", pg_bin_dec_to_base64, rb_cPG_CompositeDecoder, rb_mPG_BinaryDecoder );
|
data/ext/pg_binary_encoder.c
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
/*
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
3
|
-
* $Id: pg_binary_encoder.c,v
|
3
|
+
* $Id: pg_binary_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
7
7
|
#include "pg.h"
|
8
8
|
#include "util.h"
|
9
|
+
#ifdef HAVE_INTTYPES_H
|
9
10
|
#include <inttypes.h>
|
11
|
+
#endif
|
10
12
|
|
11
13
|
VALUE rb_mPG_BinaryEncoder;
|
12
14
|
|
@@ -20,16 +22,16 @@ VALUE rb_mPG_BinaryEncoder;
|
|
20
22
|
*
|
21
23
|
*/
|
22
24
|
static int
|
23
|
-
pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
25
|
+
pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
24
26
|
{
|
25
|
-
char
|
27
|
+
char mybool;
|
26
28
|
switch(value){
|
27
|
-
case Qtrue :
|
28
|
-
case Qfalse :
|
29
|
+
case Qtrue : mybool = 1; break;
|
30
|
+
case Qfalse : mybool = 0; break;
|
29
31
|
default :
|
30
32
|
rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
|
31
33
|
}
|
32
|
-
if(out) *out =
|
34
|
+
if(out) *out = mybool;
|
33
35
|
return 1;
|
34
36
|
}
|
35
37
|
|
@@ -42,7 +44,7 @@ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
|
|
42
44
|
*
|
43
45
|
*/
|
44
46
|
static int
|
45
|
-
pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
47
|
+
pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
46
48
|
{
|
47
49
|
if(out){
|
48
50
|
write_nbo16(NUM2INT(*intermediate), out);
|
@@ -61,7 +63,7 @@ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
61
63
|
*
|
62
64
|
*/
|
63
65
|
static int
|
64
|
-
pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
66
|
+
pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
65
67
|
{
|
66
68
|
if(out){
|
67
69
|
write_nbo32(NUM2LONG(*intermediate), out);
|
@@ -80,7 +82,7 @@ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
80
82
|
*
|
81
83
|
*/
|
82
84
|
static int
|
83
|
-
pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
85
|
+
pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
84
86
|
{
|
85
87
|
if(out){
|
86
88
|
write_nbo64(NUM2LL(*intermediate), out);
|
@@ -98,7 +100,7 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
98
100
|
*
|
99
101
|
*/
|
100
102
|
static int
|
101
|
-
pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
103
|
+
pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
102
104
|
{
|
103
105
|
int strlen;
|
104
106
|
VALUE subint;
|
@@ -107,13 +109,13 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
|
|
107
109
|
|
108
110
|
if(out){
|
109
111
|
/* Second encoder pass, if required */
|
110
|
-
strlen = enc_func(this->elem, value, out, intermediate);
|
112
|
+
strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
|
111
113
|
strlen = base64_decode( out, out, strlen );
|
112
114
|
|
113
115
|
return strlen;
|
114
116
|
} else {
|
115
117
|
/* First encoder pass */
|
116
|
-
strlen = enc_func(this->elem, value, NULL, &subint);
|
118
|
+
strlen = enc_func(this->elem, value, NULL, &subint, enc_idx);
|
117
119
|
|
118
120
|
if( strlen == -1 ){
|
119
121
|
/* Encoded string is returned in subint */
|