pg 1.1.4 → 1.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.appveyor.yml +42 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +117 -0
- data/.github/workflows/source-gem.yml +137 -0
- data/.gitignore +22 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.md +876 -0
- data/Manifest.txt +3 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +37 -137
- data/Rakefile.cross +62 -62
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +76 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +21 -2
- data/ext/extconf.rb +101 -26
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +203 -151
- data/ext/pg.h +48 -21
- data/ext/pg_binary_decoder.c +89 -10
- data/ext/pg_binary_encoder.c +238 -13
- data/ext/pg_coder.c +109 -34
- data/ext/pg_connection.c +1365 -976
- data/ext/pg_copy_coder.c +356 -35
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +522 -0
- data/ext/pg_result.c +436 -171
- data/ext/pg_text_decoder.c +42 -18
- data/ext/pg_text_encoder.c +201 -56
- data/ext/pg_tuple.c +97 -66
- data/ext/pg_type_map.c +45 -11
- data/ext/pg_type_map_all_strings.c +21 -7
- data/ext/pg_type_map_by_class.c +59 -27
- data/ext/pg_type_map_by_column.c +80 -37
- data/ext/pg_type_map_by_mri_type.c +49 -20
- data/ext/pg_type_map_by_oid.c +62 -29
- data/ext/pg_type_map_in_ruby.c +56 -22
- data/ext/{util.c → pg_util.c} +7 -7
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +35 -12
- data/lib/pg/connection.rb +744 -84
- data/lib/pg/exceptions.rb +15 -1
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder/date.rb +18 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +14 -0
- data/lib/pg/text_decoder/numeric.rb +9 -0
- data/lib/pg/text_decoder/timestamp.rb +30 -0
- data/lib/pg/text_encoder/date.rb +12 -0
- data/lib/pg/text_encoder/inet.rb +28 -0
- data/lib/pg/text_encoder/json.rb +14 -0
- data/lib/pg/text_encoder/numeric.rb +9 -0
- data/lib/pg/text_encoder/timestamp.rb +24 -0
- data/lib/pg/type_map_by_column.rb +2 -1
- data/lib/pg/version.rb +4 -0
- data/lib/pg.rb +94 -39
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +34 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data/translation/.po4a-version +7 -0
- data/translation/po/all.pot +910 -0
- data/translation/po/ja.po +1047 -0
- data/translation/po4a.cfg +12 -0
- data.tar.gz.sig +0 -0
- metadata +151 -218
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +0 -492
- data/README.ja.rdoc +0 -14
- data/README.rdoc +0 -178
- data/lib/pg/basic_type_mapping.rb +0 -459
- data/lib/pg/binary_decoder.rb +0 -22
- data/lib/pg/constants.rb +0 -11
- data/lib/pg/text_decoder.rb +0 -47
- data/lib/pg/text_encoder.rb +0 -69
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -380
- data/spec/pg/basic_type_mapping_spec.rb +0 -508
- data/spec/pg/connection_spec.rb +0 -1872
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -491
- data/spec/pg/tuple_spec.rb +0 -280
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -949
- data/spec/pg_spec.rb +0 -50
- /data/ext/{util.h → pg_util.h} +0 -0
data/ext/pg.h
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <sys/types.h>
|
|
12
12
|
#if !defined(_WIN32)
|
|
13
13
|
# include <sys/time.h>
|
|
14
|
+
# include <sys/socket.h>
|
|
14
15
|
#endif
|
|
15
16
|
#if defined(HAVE_UNISTD_H) && !defined(_WIN32)
|
|
16
17
|
# include <unistd.h>
|
|
@@ -56,6 +57,7 @@
|
|
|
56
57
|
#endif
|
|
57
58
|
|
|
58
59
|
/* PostgreSQL headers */
|
|
60
|
+
#include "pg_config.h"
|
|
59
61
|
#include "libpq-fe.h"
|
|
60
62
|
#include "libpq/libpq-fs.h" /* large-object interface */
|
|
61
63
|
#include "pg_config_manual.h"
|
|
@@ -74,9 +76,22 @@ typedef long suseconds_t;
|
|
|
74
76
|
#define PG_MAX_COLUMNS 4000
|
|
75
77
|
#endif
|
|
76
78
|
|
|
77
|
-
#
|
|
78
|
-
#define
|
|
79
|
+
#ifdef HAVE_RB_GC_MARK_MOVABLE
|
|
80
|
+
#define pg_compact_callback(x) (x)
|
|
81
|
+
#define pg_gc_location(x) x = rb_gc_location(x)
|
|
82
|
+
#else
|
|
83
|
+
#define rb_gc_mark_movable(x) rb_gc_mark(x)
|
|
84
|
+
#define pg_compact_callback(x) {(x)}
|
|
85
|
+
#define pg_gc_location(x) UNUSED(x)
|
|
86
|
+
#endif
|
|
87
|
+
|
|
88
|
+
/* For compatibility with ruby < 3.0 */
|
|
89
|
+
#ifndef RUBY_TYPED_FROZEN_SHAREABLE
|
|
90
|
+
#define PG_RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
91
|
+
#else
|
|
92
|
+
#define PG_RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
|
|
79
93
|
#endif
|
|
94
|
+
#define PG_ENC_IDX_BITS 28
|
|
80
95
|
|
|
81
96
|
/* The data behind each PG::Connection object */
|
|
82
97
|
typedef struct {
|
|
@@ -84,6 +99,9 @@ typedef struct {
|
|
|
84
99
|
|
|
85
100
|
/* Cached IO object for the socket descriptor */
|
|
86
101
|
VALUE socket_io;
|
|
102
|
+
/* function pointers of the original libpq notice receivers */
|
|
103
|
+
PQnoticeReceiver default_notice_receiver;
|
|
104
|
+
PQnoticeProcessor default_notice_processor;
|
|
87
105
|
/* Proc object that receives notices as PG::Result objects */
|
|
88
106
|
VALUE notice_receiver;
|
|
89
107
|
/* Proc object that receives notices as String objects */
|
|
@@ -94,15 +112,16 @@ typedef struct {
|
|
|
94
112
|
VALUE type_map_for_results;
|
|
95
113
|
/* IO object internally used for the trace stream */
|
|
96
114
|
VALUE trace_stream;
|
|
97
|
-
/* Cached Encoding object */
|
|
98
|
-
VALUE external_encoding;
|
|
99
115
|
/* Kind of PG::Coder object for casting ruby values to COPY rows */
|
|
100
116
|
VALUE encoder_for_put_copy_data;
|
|
101
117
|
/* Kind of PG::Coder object for casting COPY rows to ruby values */
|
|
102
118
|
VALUE decoder_for_get_copy_data;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
/* Ruby encoding index of the client/internal encoding */
|
|
120
|
+
int enc_idx : PG_ENC_IDX_BITS;
|
|
121
|
+
/* flags controlling Symbol/String field names */
|
|
122
|
+
unsigned int flags : 2;
|
|
123
|
+
/* enable automatic flushing of send data at the end of send_query calls */
|
|
124
|
+
unsigned int flush_data : 1;
|
|
106
125
|
|
|
107
126
|
#if defined(_WIN32)
|
|
108
127
|
/* File descriptor to be used for rb_w32_unwrap_io_handle() */
|
|
@@ -128,10 +147,16 @@ typedef struct {
|
|
|
128
147
|
*/
|
|
129
148
|
t_typemap *p_typemap;
|
|
130
149
|
|
|
150
|
+
/* Ruby encoding index of the client/internal encoding */
|
|
151
|
+
int enc_idx : PG_ENC_IDX_BITS;
|
|
152
|
+
|
|
131
153
|
/* 0 = PGresult is cleared by PG::Result#clear or by the GC
|
|
132
154
|
* 1 = PGresult is cleared internally by libpq
|
|
133
155
|
*/
|
|
134
|
-
int autoclear;
|
|
156
|
+
unsigned int autoclear : 1;
|
|
157
|
+
|
|
158
|
+
/* flags controlling Symbol/String field names */
|
|
159
|
+
unsigned int flags : 2;
|
|
135
160
|
|
|
136
161
|
/* Number of fields in fnames[] .
|
|
137
162
|
* Set to -1 if fnames[] is not yet initialized.
|
|
@@ -147,7 +172,7 @@ typedef struct {
|
|
|
147
172
|
/* Hash with fnames[] to field number mapping. */
|
|
148
173
|
VALUE field_map;
|
|
149
174
|
|
|
150
|
-
/* List of field names as frozen String objects.
|
|
175
|
+
/* List of field names as frozen String or Symbol objects.
|
|
151
176
|
* Only valid if nfields != -1
|
|
152
177
|
*/
|
|
153
178
|
VALUE fnames[0];
|
|
@@ -163,6 +188,10 @@ typedef VALUE (* t_pg_typecast_result)(t_typemap *, VALUE, int, int);
|
|
|
163
188
|
typedef t_pg_coder *(* t_pg_typecast_query_param)(t_typemap *, VALUE, int);
|
|
164
189
|
typedef VALUE (* t_pg_typecast_copy_get)( t_typemap *, VALUE, int, int, int );
|
|
165
190
|
|
|
191
|
+
#define PG_RESULT_FIELD_NAMES_MASK 0x03
|
|
192
|
+
#define PG_RESULT_FIELD_NAMES_SYMBOL 0x01
|
|
193
|
+
#define PG_RESULT_FIELD_NAMES_STATIC_SYMBOL 0x02
|
|
194
|
+
|
|
166
195
|
#define PG_CODER_TIMESTAMP_DB_UTC 0x0
|
|
167
196
|
#define PG_CODER_TIMESTAMP_DB_LOCAL 0x1
|
|
168
197
|
#define PG_CODER_TIMESTAMP_APP_UTC 0x0
|
|
@@ -209,6 +238,8 @@ typedef struct {
|
|
|
209
238
|
} convs[0];
|
|
210
239
|
} t_tmbc;
|
|
211
240
|
|
|
241
|
+
extern const rb_data_type_t pg_typemap_type;
|
|
242
|
+
extern const rb_data_type_t pg_coder_type;
|
|
212
243
|
|
|
213
244
|
#include "gvl_wrappers.h"
|
|
214
245
|
|
|
@@ -275,6 +306,7 @@ void init_pg_type_map_by_oid _(( void ));
|
|
|
275
306
|
void init_pg_type_map_in_ruby _(( void ));
|
|
276
307
|
void init_pg_coder _(( void ));
|
|
277
308
|
void init_pg_copycoder _(( void ));
|
|
309
|
+
void init_pg_recordcoder _(( void ));
|
|
278
310
|
void init_pg_text_encoder _(( void ));
|
|
279
311
|
void init_pg_text_decoder _(( void ));
|
|
280
312
|
void init_pg_binary_encoder _(( void ));
|
|
@@ -287,11 +319,12 @@ int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, c
|
|
|
287
319
|
int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
|
|
288
320
|
t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
|
|
289
321
|
t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
|
|
290
|
-
|
|
322
|
+
VALUE pg_define_coder _(( const char *, void *, VALUE, VALUE ));
|
|
291
323
|
VALUE pg_obj_to_i _(( VALUE ));
|
|
292
324
|
VALUE pg_tmbc_allocate _(( void ));
|
|
293
325
|
void pg_coder_init_encoder _(( VALUE ));
|
|
294
326
|
void pg_coder_init_decoder _(( VALUE ));
|
|
327
|
+
void pg_coder_compact _(( void * ));
|
|
295
328
|
char *pg_rb_str_ensure_capa _(( VALUE, long, char *, char ** ));
|
|
296
329
|
|
|
297
330
|
#define PG_RB_STR_ENSURE_CAPA( str, expand_len, curr_ptr, end_ptr ) \
|
|
@@ -305,20 +338,19 @@ char *pg_rb_str_ensure_capa _(( VALUE, long, char *,
|
|
|
305
338
|
(curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
|
|
306
339
|
)
|
|
307
340
|
|
|
308
|
-
#define PG_RB_TAINTED_STR_NEW( str, curr_ptr, end_ptr ) ( \
|
|
309
|
-
(str) = rb_tainted_str_new( NULL, 0 ), \
|
|
310
|
-
(curr_ptr) = (end_ptr) = RSTRING_PTR(str) \
|
|
311
|
-
)
|
|
312
|
-
|
|
313
341
|
VALUE pg_typemap_fit_to_result _(( VALUE, VALUE ));
|
|
314
342
|
VALUE pg_typemap_fit_to_query _(( VALUE, VALUE ));
|
|
315
343
|
int pg_typemap_fit_to_copy_get _(( VALUE ));
|
|
316
344
|
VALUE pg_typemap_result_value _(( t_typemap *, VALUE, int, int ));
|
|
317
345
|
t_pg_coder *pg_typemap_typecast_query_param _(( t_typemap *, VALUE, int ));
|
|
318
346
|
VALUE pg_typemap_typecast_copy_get _(( t_typemap *, VALUE, int, int, int ));
|
|
347
|
+
void pg_typemap_mark _(( void * ));
|
|
348
|
+
size_t pg_typemap_memsize _(( const void * ));
|
|
349
|
+
void pg_typemap_compact _(( void * ));
|
|
319
350
|
|
|
320
351
|
PGconn *pg_get_pgconn _(( VALUE ));
|
|
321
352
|
t_pg_connection *pg_get_connection _(( VALUE ));
|
|
353
|
+
VALUE pgconn_block _(( int, VALUE *, VALUE ));
|
|
322
354
|
|
|
323
355
|
VALUE pg_new_result _(( PGresult *, VALUE ));
|
|
324
356
|
VALUE pg_new_result_autoclear _(( PGresult *, VALUE ));
|
|
@@ -333,12 +365,7 @@ VALUE pg_tuple_new _(( VALUE, int ));
|
|
|
333
365
|
static inline t_pg_result *
|
|
334
366
|
pgresult_get_this( VALUE self )
|
|
335
367
|
{
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if( this == NULL )
|
|
339
|
-
rb_raise(rb_ePGerror, "result has been cleared");
|
|
340
|
-
|
|
341
|
-
return this;
|
|
368
|
+
return RTYPEDDATA_DATA(self);
|
|
342
369
|
}
|
|
343
370
|
|
|
344
371
|
|
data/ext/pg_binary_decoder.c
CHANGED
|
@@ -6,19 +6,21 @@
|
|
|
6
6
|
|
|
7
7
|
#include "ruby/version.h"
|
|
8
8
|
#include "pg.h"
|
|
9
|
-
#include "
|
|
9
|
+
#include "pg_util.h"
|
|
10
10
|
#ifdef HAVE_INTTYPES_H
|
|
11
11
|
#include <inttypes.h>
|
|
12
12
|
#endif
|
|
13
13
|
|
|
14
14
|
VALUE rb_mPG_BinaryDecoder;
|
|
15
|
+
static VALUE s_Date;
|
|
16
|
+
static ID s_id_new;
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
/*
|
|
18
20
|
* Document-class: PG::BinaryDecoder::Boolean < PG::SimpleDecoder
|
|
19
21
|
*
|
|
20
|
-
* This is a decoder class for conversion of PostgreSQL binary bool type
|
|
21
|
-
* to Ruby true or false objects.
|
|
22
|
+
* This is a decoder class for conversion of PostgreSQL binary +bool+ type
|
|
23
|
+
* to Ruby +true+ or +false+ objects.
|
|
22
24
|
*
|
|
23
25
|
*/
|
|
24
26
|
static VALUE
|
|
@@ -33,7 +35,7 @@ pg_bin_dec_boolean(t_pg_coder *conv, const char *val, int len, int tuple, int fi
|
|
|
33
35
|
/*
|
|
34
36
|
* Document-class: PG::BinaryDecoder::Integer < PG::SimpleDecoder
|
|
35
37
|
*
|
|
36
|
-
* This is a decoder class for conversion of PostgreSQL binary int2
|
|
38
|
+
* This is a decoder class for conversion of PostgreSQL binary +int2+, +int4+ and +int8+ types
|
|
37
39
|
* to Ruby Integer objects.
|
|
38
40
|
*
|
|
39
41
|
*/
|
|
@@ -55,7 +57,7 @@ pg_bin_dec_integer(t_pg_coder *conv, const char *val, int len, int tuple, int fi
|
|
|
55
57
|
/*
|
|
56
58
|
* Document-class: PG::BinaryDecoder::Float < PG::SimpleDecoder
|
|
57
59
|
*
|
|
58
|
-
* This is a decoder class for conversion of PostgreSQL binary float4 and float8 types
|
|
60
|
+
* This is a decoder class for conversion of PostgreSQL binary +float4+ and +float8+ types
|
|
59
61
|
* to Ruby Float objects.
|
|
60
62
|
*
|
|
61
63
|
*/
|
|
@@ -87,7 +89,7 @@ pg_bin_dec_float(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
|
87
89
|
* Document-class: PG::BinaryDecoder::Bytea < PG::SimpleDecoder
|
|
88
90
|
*
|
|
89
91
|
* This decoder class delivers the data received from the server as binary String object.
|
|
90
|
-
* It is therefore suitable for conversion of PostgreSQL bytea data as well as any other
|
|
92
|
+
* It is therefore suitable for conversion of PostgreSQL +bytea+ data as well as any other
|
|
91
93
|
* data in binary format.
|
|
92
94
|
*
|
|
93
95
|
*/
|
|
@@ -95,7 +97,7 @@ VALUE
|
|
|
95
97
|
pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
96
98
|
{
|
|
97
99
|
VALUE ret;
|
|
98
|
-
ret =
|
|
100
|
+
ret = rb_str_new( val, len );
|
|
99
101
|
PG_ENCODING_SET_NOCHECK( ret, rb_ascii8bit_encindex() );
|
|
100
102
|
return ret;
|
|
101
103
|
}
|
|
@@ -103,7 +105,7 @@ pg_bin_dec_bytea(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
|
103
105
|
/*
|
|
104
106
|
* Document-class: PG::BinaryDecoder::ToBase64 < PG::CompositeDecoder
|
|
105
107
|
*
|
|
106
|
-
* This is a decoder class for conversion of binary
|
|
108
|
+
* This is a decoder class for conversion of binary +bytea+ to base64 data.
|
|
107
109
|
*
|
|
108
110
|
*/
|
|
109
111
|
static VALUE
|
|
@@ -113,7 +115,7 @@ pg_bin_dec_to_base64(t_pg_coder *conv, const char *val, int len, int tuple, int
|
|
|
113
115
|
t_pg_coder_dec_func dec_func = pg_coder_dec_func(this->elem, this->comp.format);
|
|
114
116
|
int encoded_len = BASE64_ENCODED_SIZE(len);
|
|
115
117
|
/* create a buffer of the encoded length */
|
|
116
|
-
VALUE out_value =
|
|
118
|
+
VALUE out_value = rb_str_new(NULL, encoded_len);
|
|
117
119
|
|
|
118
120
|
base64_encode( RSTRING_PTR(out_value), val, len );
|
|
119
121
|
|
|
@@ -195,6 +197,82 @@ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int
|
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
199
|
|
|
200
|
+
#define PG_INT32_MIN (-0x7FFFFFFF-1)
|
|
201
|
+
#define PG_INT32_MAX (0x7FFFFFFF)
|
|
202
|
+
#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
|
|
203
|
+
#define MONTHS_PER_YEAR 12
|
|
204
|
+
|
|
205
|
+
/* taken from PostgreSQL sources at src/backend/utils/adt/datetime.c */
|
|
206
|
+
void
|
|
207
|
+
j2date(int jd, int *year, int *month, int *day)
|
|
208
|
+
{
|
|
209
|
+
unsigned int julian;
|
|
210
|
+
unsigned int quad;
|
|
211
|
+
unsigned int extra;
|
|
212
|
+
int y;
|
|
213
|
+
|
|
214
|
+
julian = jd;
|
|
215
|
+
julian += 32044;
|
|
216
|
+
quad = julian / 146097;
|
|
217
|
+
extra = (julian - quad * 146097) * 4 + 3;
|
|
218
|
+
julian += 60 + quad * 3 + extra / 146097;
|
|
219
|
+
quad = julian / 1461;
|
|
220
|
+
julian -= quad * 1461;
|
|
221
|
+
y = julian * 4 / 1461;
|
|
222
|
+
julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
|
|
223
|
+
+ 123;
|
|
224
|
+
y += quad * 4;
|
|
225
|
+
*year = y - 4800;
|
|
226
|
+
quad = julian * 2141 / 65536;
|
|
227
|
+
*day = julian - 7834 * quad / 256;
|
|
228
|
+
*month = (quad + 10) % MONTHS_PER_YEAR + 1;
|
|
229
|
+
} /* j2date() */
|
|
230
|
+
|
|
231
|
+
/*
|
|
232
|
+
* Document-class: PG::BinaryDecoder::Date < PG::SimpleDecoder
|
|
233
|
+
*
|
|
234
|
+
* This is a decoder class for conversion of PostgreSQL binary date
|
|
235
|
+
* to Ruby Date objects.
|
|
236
|
+
*/
|
|
237
|
+
static VALUE
|
|
238
|
+
pg_bin_dec_date(t_pg_coder *conv, const char *val, int len, int tuple, int field, int enc_idx)
|
|
239
|
+
{
|
|
240
|
+
int year, month, day;
|
|
241
|
+
int date;
|
|
242
|
+
|
|
243
|
+
if (len != 4) {
|
|
244
|
+
rb_raise(rb_eTypeError, "unexpected date format != 4 bytes");
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
date = read_nbo32(val);
|
|
248
|
+
switch(date){
|
|
249
|
+
case PG_INT32_MAX:
|
|
250
|
+
return rb_str_new2("infinity");
|
|
251
|
+
case PG_INT32_MIN:
|
|
252
|
+
return rb_str_new2("-infinity");
|
|
253
|
+
default:
|
|
254
|
+
j2date(date + POSTGRES_EPOCH_JDATE, &year, &month, &day);
|
|
255
|
+
|
|
256
|
+
return rb_funcall(s_Date, s_id_new, 3, INT2NUM(year), INT2NUM(month), INT2NUM(day));
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* called per autoload when BinaryDecoder::Date is used */
|
|
261
|
+
static VALUE
|
|
262
|
+
init_pg_bin_decoder_date(VALUE rb_mPG_BinaryDecoder)
|
|
263
|
+
{
|
|
264
|
+
rb_require("date");
|
|
265
|
+
s_Date = rb_const_get(rb_cObject, rb_intern("Date"));
|
|
266
|
+
rb_gc_register_mark_object(s_Date);
|
|
267
|
+
s_id_new = rb_intern("new");
|
|
268
|
+
|
|
269
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Date", rb_cPG_SimpleDecoder ); */
|
|
270
|
+
pg_define_coder( "Date", pg_bin_dec_date, rb_cPG_SimpleDecoder, rb_mPG_BinaryDecoder );
|
|
271
|
+
|
|
272
|
+
return Qnil;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
198
276
|
/*
|
|
199
277
|
* Document-class: PG::BinaryDecoder::String < PG::SimpleDecoder
|
|
200
278
|
*
|
|
@@ -205,10 +283,11 @@ pg_bin_dec_timestamp(t_pg_coder *conv, const char *val, int len, int tuple, int
|
|
|
205
283
|
*/
|
|
206
284
|
|
|
207
285
|
void
|
|
208
|
-
init_pg_binary_decoder()
|
|
286
|
+
init_pg_binary_decoder(void)
|
|
209
287
|
{
|
|
210
288
|
/* This module encapsulates all decoder classes with binary input format */
|
|
211
289
|
rb_mPG_BinaryDecoder = rb_define_module_under( rb_mPG, "BinaryDecoder" );
|
|
290
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_BinaryDecoder), "init_date", init_pg_bin_decoder_date, 0);
|
|
212
291
|
|
|
213
292
|
/* Make RDoc aware of the decoder classes... */
|
|
214
293
|
/* dummy = rb_define_class_under( rb_mPG_BinaryDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
|
data/ext/pg_binary_encoder.c
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
#include "pg.h"
|
|
8
|
-
#include "
|
|
8
|
+
#include "pg_util.h"
|
|
9
9
|
#ifdef HAVE_INTTYPES_H
|
|
10
10
|
#include <inttypes.h>
|
|
11
11
|
#endif
|
|
12
12
|
|
|
13
13
|
VALUE rb_mPG_BinaryEncoder;
|
|
14
|
+
static ID s_id_year;
|
|
15
|
+
static ID s_id_month;
|
|
16
|
+
static ID s_id_day;
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
/*
|
|
@@ -25,11 +28,12 @@ static int
|
|
|
25
28
|
pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
|
26
29
|
{
|
|
27
30
|
char mybool;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
if (value == Qtrue) {
|
|
32
|
+
mybool = 1;
|
|
33
|
+
} else if (value == Qfalse) {
|
|
34
|
+
mybool = 0;
|
|
35
|
+
} else {
|
|
36
|
+
rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
|
|
33
37
|
}
|
|
34
38
|
if(out) *out = mybool;
|
|
35
39
|
return 1;
|
|
@@ -38,7 +42,7 @@ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
|
|
|
38
42
|
/*
|
|
39
43
|
* Document-class: PG::BinaryEncoder::Int2 < PG::SimpleEncoder
|
|
40
44
|
*
|
|
41
|
-
* This is the encoder class for the PostgreSQL int2 type.
|
|
45
|
+
* This is the encoder class for the PostgreSQL +int2+ (alias +smallint+) type.
|
|
42
46
|
*
|
|
43
47
|
* Non-Number values are expected to have method +to_i+ defined.
|
|
44
48
|
*
|
|
@@ -55,9 +59,9 @@ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
|
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
/*
|
|
58
|
-
* Document-class: PG::BinaryEncoder::
|
|
62
|
+
* Document-class: PG::BinaryEncoder::Int4 < PG::SimpleEncoder
|
|
59
63
|
*
|
|
60
|
-
* This is the encoder class for the PostgreSQL int4 type.
|
|
64
|
+
* This is the encoder class for the PostgreSQL +int4+ (alias +integer+) type.
|
|
61
65
|
*
|
|
62
66
|
* Non-Number values are expected to have method +to_i+ defined.
|
|
63
67
|
*
|
|
@@ -74,9 +78,9 @@ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
|
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
/*
|
|
77
|
-
* Document-class: PG::BinaryEncoder::
|
|
81
|
+
* Document-class: PG::BinaryEncoder::Int8 < PG::SimpleEncoder
|
|
78
82
|
*
|
|
79
|
-
* This is the encoder class for the PostgreSQL int8 type.
|
|
83
|
+
* This is the encoder class for the PostgreSQL +int8+ (alias +bigint+) type.
|
|
80
84
|
*
|
|
81
85
|
* Non-Number values are expected to have method +to_i+ defined.
|
|
82
86
|
*
|
|
@@ -92,6 +96,215 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, i
|
|
|
92
96
|
return 8;
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
/*
|
|
100
|
+
* Document-class: PG::BinaryEncoder::Float4 < PG::SimpleEncoder
|
|
101
|
+
*
|
|
102
|
+
* This is the binary encoder class for the PostgreSQL +float4+ type.
|
|
103
|
+
*
|
|
104
|
+
*/
|
|
105
|
+
static int
|
|
106
|
+
pg_bin_enc_float4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
|
107
|
+
{
|
|
108
|
+
union {
|
|
109
|
+
float f;
|
|
110
|
+
int32_t i;
|
|
111
|
+
} swap4;
|
|
112
|
+
|
|
113
|
+
if(out){
|
|
114
|
+
swap4.f = NUM2DBL(*intermediate);
|
|
115
|
+
write_nbo32(swap4.i, out);
|
|
116
|
+
}else{
|
|
117
|
+
*intermediate = value;
|
|
118
|
+
}
|
|
119
|
+
return 4;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/*
|
|
123
|
+
* Document-class: PG::BinaryEncoder::Float8 < PG::SimpleEncoder
|
|
124
|
+
*
|
|
125
|
+
* This is the binary encoder class for the PostgreSQL +float8+ type.
|
|
126
|
+
*
|
|
127
|
+
*/
|
|
128
|
+
static int
|
|
129
|
+
pg_bin_enc_float8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
|
130
|
+
{
|
|
131
|
+
union {
|
|
132
|
+
double f;
|
|
133
|
+
int64_t i;
|
|
134
|
+
} swap8;
|
|
135
|
+
|
|
136
|
+
if(out){
|
|
137
|
+
swap8.f = NUM2DBL(*intermediate);
|
|
138
|
+
write_nbo64(swap8.i, out);
|
|
139
|
+
}else{
|
|
140
|
+
*intermediate = value;
|
|
141
|
+
}
|
|
142
|
+
return 8;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
#define PG_INT32_MIN (-0x7FFFFFFF-1)
|
|
146
|
+
#define PG_INT32_MAX (0x7FFFFFFF)
|
|
147
|
+
#define PG_INT64_MIN (-0x7FFFFFFFFFFFFFFFL - 1)
|
|
148
|
+
#define PG_INT64_MAX 0x7FFFFFFFFFFFFFFFL
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* Document-class: PG::BinaryEncoder::Timestamp < PG::SimpleEncoder
|
|
152
|
+
*
|
|
153
|
+
* This is a encoder class for conversion of Ruby Time objects to PostgreSQL binary timestamps.
|
|
154
|
+
*
|
|
155
|
+
* The following flags can be used to specify timezone interpretation:
|
|
156
|
+
* * +PG::Coder::TIMESTAMP_DB_UTC+ : Send timestamp as UTC time (default)
|
|
157
|
+
* * +PG::Coder::TIMESTAMP_DB_LOCAL+ : Send timestamp as local time (slower)
|
|
158
|
+
*
|
|
159
|
+
* Example:
|
|
160
|
+
* enco = PG::BinaryEncoder::Timestamp.new(flags: PG::Coder::TIMESTAMP_DB_UTC)
|
|
161
|
+
* enco.encode(Time.utc(2000, 1, 1)) # => "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
162
|
+
*
|
|
163
|
+
* String values are expected to contain a binary data with a length of 8 byte.
|
|
164
|
+
*
|
|
165
|
+
*/
|
|
166
|
+
static int
|
|
167
|
+
pg_bin_enc_timestamp(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
|
168
|
+
{
|
|
169
|
+
if(out){
|
|
170
|
+
int64_t timestamp;
|
|
171
|
+
struct timespec ts;
|
|
172
|
+
|
|
173
|
+
/* second call -> write data to *out */
|
|
174
|
+
switch(TYPE(*intermediate)){
|
|
175
|
+
case T_STRING:
|
|
176
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
|
177
|
+
case T_TRUE:
|
|
178
|
+
write_nbo64(PG_INT64_MAX, out);
|
|
179
|
+
return 8;
|
|
180
|
+
case T_FALSE:
|
|
181
|
+
write_nbo64(PG_INT64_MIN, out);
|
|
182
|
+
return 8;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
ts = rb_time_timespec(*intermediate);
|
|
186
|
+
/* PostgreSQL's timestamp is based on year 2000 and Ruby's time is based on 1970.
|
|
187
|
+
* Adjust the 30 years difference. */
|
|
188
|
+
timestamp = (ts.tv_sec - 10957L * 24L * 3600L) * 1000000 + (ts.tv_nsec / 1000);
|
|
189
|
+
|
|
190
|
+
if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
|
|
191
|
+
/* send as local time */
|
|
192
|
+
timestamp += NUM2LL(rb_funcall(*intermediate, rb_intern("utc_offset"), 0)) * 1000000;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
write_nbo64(timestamp, out);
|
|
196
|
+
}else{
|
|
197
|
+
/* first call -> determine the required length */
|
|
198
|
+
if(TYPE(value) == T_STRING){
|
|
199
|
+
char *pstr = RSTRING_PTR(value);
|
|
200
|
+
if(RSTRING_LEN(value) >= 1){
|
|
201
|
+
switch(pstr[0]) {
|
|
202
|
+
case 'I':
|
|
203
|
+
case 'i':
|
|
204
|
+
*intermediate = Qtrue;
|
|
205
|
+
return 8;
|
|
206
|
+
case '-':
|
|
207
|
+
if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
|
|
208
|
+
*intermediate = Qfalse;
|
|
209
|
+
return 8;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if( this->flags & PG_CODER_TIMESTAMP_DB_LOCAL ) {
|
|
218
|
+
/* make a local time, so that utc_offset is set */
|
|
219
|
+
value = rb_funcall(value, rb_intern("getlocal"), 0);
|
|
220
|
+
}
|
|
221
|
+
*intermediate = value;
|
|
222
|
+
}
|
|
223
|
+
return 8;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#define POSTGRES_EPOCH_JDATE 2451545 /* == date2j(2000, 1, 1) */
|
|
227
|
+
int
|
|
228
|
+
date2j(int year, int month, int day)
|
|
229
|
+
{
|
|
230
|
+
int julian;
|
|
231
|
+
int century;
|
|
232
|
+
|
|
233
|
+
if (month > 2)
|
|
234
|
+
{
|
|
235
|
+
month += 1;
|
|
236
|
+
year += 4800;
|
|
237
|
+
}
|
|
238
|
+
else
|
|
239
|
+
{
|
|
240
|
+
month += 13;
|
|
241
|
+
year += 4799;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
century = year / 100;
|
|
245
|
+
julian = year * 365 - 32167;
|
|
246
|
+
julian += year / 4 - century + century / 4;
|
|
247
|
+
julian += 7834 * month / 256 + day;
|
|
248
|
+
|
|
249
|
+
return julian;
|
|
250
|
+
} /* date2j() */
|
|
251
|
+
|
|
252
|
+
/*
|
|
253
|
+
* Document-class: PG::BinaryEncoder::Date < PG::SimpleEncoder
|
|
254
|
+
*
|
|
255
|
+
* This is a encoder class for conversion of Ruby Date objects to PostgreSQL binary date.
|
|
256
|
+
*
|
|
257
|
+
* String values are expected to contain a binary data with a length of 4 byte.
|
|
258
|
+
*
|
|
259
|
+
*/
|
|
260
|
+
static int
|
|
261
|
+
pg_bin_enc_date(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
|
262
|
+
{
|
|
263
|
+
if(out){
|
|
264
|
+
/* second call -> write data to *out */
|
|
265
|
+
switch(TYPE(*intermediate)){
|
|
266
|
+
case T_STRING:
|
|
267
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
|
268
|
+
case T_TRUE:
|
|
269
|
+
write_nbo32(PG_INT32_MAX, out);
|
|
270
|
+
return 4;
|
|
271
|
+
case T_FALSE:
|
|
272
|
+
write_nbo32(PG_INT32_MIN, out);
|
|
273
|
+
return 4;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
VALUE year = rb_funcall(value, s_id_year, 0);
|
|
277
|
+
VALUE month = rb_funcall(value, s_id_month, 0);
|
|
278
|
+
VALUE day = rb_funcall(value, s_id_day, 0);
|
|
279
|
+
int jday = date2j(NUM2INT(year), NUM2INT(month), NUM2INT(day)) - POSTGRES_EPOCH_JDATE;
|
|
280
|
+
write_nbo32(jday, out);
|
|
281
|
+
|
|
282
|
+
}else{
|
|
283
|
+
/* first call -> determine the required length */
|
|
284
|
+
if(TYPE(value) == T_STRING){
|
|
285
|
+
char *pstr = RSTRING_PTR(value);
|
|
286
|
+
if(RSTRING_LEN(value) >= 1){
|
|
287
|
+
switch(pstr[0]) {
|
|
288
|
+
case 'I':
|
|
289
|
+
case 'i':
|
|
290
|
+
*intermediate = Qtrue;
|
|
291
|
+
return 4;
|
|
292
|
+
case '-':
|
|
293
|
+
if (RSTRING_LEN(value) >= 2 && (pstr[1] == 'I' || pstr[1] == 'i')) {
|
|
294
|
+
*intermediate = Qfalse;
|
|
295
|
+
return 4;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return pg_coder_enc_to_s(this, value, out, intermediate, enc_idx);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
*intermediate = value;
|
|
304
|
+
}
|
|
305
|
+
return 4;
|
|
306
|
+
}
|
|
307
|
+
|
|
95
308
|
/*
|
|
96
309
|
* Document-class: PG::BinaryEncoder::FromBase64 < PG::CompositeEncoder
|
|
97
310
|
*
|
|
@@ -138,8 +351,12 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
|
|
|
138
351
|
}
|
|
139
352
|
|
|
140
353
|
void
|
|
141
|
-
init_pg_binary_encoder()
|
|
354
|
+
init_pg_binary_encoder(void)
|
|
142
355
|
{
|
|
356
|
+
s_id_year = rb_intern("year");
|
|
357
|
+
s_id_month = rb_intern("month");
|
|
358
|
+
s_id_day = rb_intern("day");
|
|
359
|
+
|
|
143
360
|
/* This module encapsulates all encoder classes with binary output format */
|
|
144
361
|
rb_mPG_BinaryEncoder = rb_define_module_under( rb_mPG, "BinaryEncoder" );
|
|
145
362
|
|
|
@@ -152,10 +369,18 @@ init_pg_binary_encoder()
|
|
|
152
369
|
pg_define_coder( "Int4", pg_bin_enc_int4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
153
370
|
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Int8", rb_cPG_SimpleEncoder ); */
|
|
154
371
|
pg_define_coder( "Int8", pg_bin_enc_int8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
372
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float4", rb_cPG_SimpleEncoder ); */
|
|
373
|
+
pg_define_coder( "Float4", pg_bin_enc_float4, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
374
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Float8", rb_cPG_SimpleEncoder ); */
|
|
375
|
+
pg_define_coder( "Float8", pg_bin_enc_float8, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
155
376
|
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "String", rb_cPG_SimpleEncoder ); */
|
|
156
377
|
pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
157
378
|
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
|
|
158
379
|
pg_define_coder( "Bytea", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
380
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Timestamp", rb_cPG_SimpleEncoder ); */
|
|
381
|
+
pg_define_coder( "Timestamp", pg_bin_enc_timestamp, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
382
|
+
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "Date", rb_cPG_SimpleEncoder ); */
|
|
383
|
+
pg_define_coder( "Date", pg_bin_enc_date, rb_cPG_SimpleEncoder, rb_mPG_BinaryEncoder );
|
|
159
384
|
|
|
160
385
|
/* dummy = rb_define_class_under( rb_mPG_BinaryEncoder, "FromBase64", rb_cPG_CompositeEncoder ); */
|
|
161
386
|
pg_define_coder( "FromBase64", pg_bin_enc_from_base64, rb_cPG_CompositeEncoder, rb_mPG_BinaryEncoder );
|