pg 1.2.3 → 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 +0 -1
- data/README.ja.md +276 -0
- data/README.md +286 -0
- data/Rakefile +33 -135
- data/Rakefile.cross +12 -13
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/ext/errorcodes.def +12 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +4 -1
- data/ext/extconf.rb +100 -25
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +72 -57
- data/ext/pg.h +28 -4
- data/ext/pg_binary_decoder.c +80 -1
- data/ext/pg_binary_encoder.c +225 -1
- data/ext/pg_coder.c +96 -33
- data/ext/pg_connection.c +996 -697
- data/ext/pg_copy_coder.c +351 -33
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +50 -19
- data/ext/pg_result.c +177 -64
- data/ext/pg_text_decoder.c +29 -11
- data/ext/pg_text_encoder.c +29 -16
- data/ext/pg_tuple.c +83 -60
- data/ext/pg_type_map.c +44 -10
- data/ext/pg_type_map_all_strings.c +17 -3
- data/ext/pg_type_map_by_class.c +54 -27
- data/ext/pg_type_map_by_column.c +73 -31
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +59 -27
- data/ext/pg_type_map_in_ruby.c +55 -21
- data/ext/pg_util.c +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +67 -0
- data/lib/pg/basic_type_map_for_queries.rb +198 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +299 -0
- data/lib/pg/binary_decoder/date.rb +9 -0
- data/lib/pg/binary_decoder/timestamp.rb +26 -0
- data/lib/pg/binary_encoder/timestamp.rb +20 -0
- data/lib/pg/coder.rb +15 -13
- data/lib/pg/connection.rb +743 -83
- data/lib/pg/exceptions.rb +14 -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/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 +142 -210
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -0
- data/History.rdoc +0 -578
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -213
- data/lib/pg/basic_type_mapping.rb +0 -522
- data/lib/pg/binary_decoder.rb +0 -23
- data/lib/pg/constants.rb +0 -12
- data/lib/pg/text_decoder.rb +0 -46
- data/lib/pg/text_encoder.rb +0 -59
- 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 -630
- data/spec/pg/connection_spec.rb +0 -1949
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -681
- data/spec/pg/tuple_spec.rb +0 -333
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -226
- 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 -1123
- data/spec/pg_spec.rb +0 -50
data/ext/pg_result.c
CHANGED
|
@@ -107,17 +107,34 @@ pgresult_approx_size(const PGresult *result)
|
|
|
107
107
|
* GC Mark function
|
|
108
108
|
*/
|
|
109
109
|
static void
|
|
110
|
-
pgresult_gc_mark(
|
|
110
|
+
pgresult_gc_mark( void *_this )
|
|
111
111
|
{
|
|
112
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
112
113
|
int i;
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
rb_gc_mark_movable( this->connection );
|
|
116
|
+
rb_gc_mark_movable( this->typemap );
|
|
117
|
+
rb_gc_mark_movable( this->tuple_hash );
|
|
118
|
+
rb_gc_mark_movable( this->field_map );
|
|
118
119
|
|
|
119
120
|
for( i=0; i < this->nfields; i++ ){
|
|
120
|
-
|
|
121
|
+
rb_gc_mark_movable( this->fnames[i] );
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static void
|
|
126
|
+
pgresult_gc_compact( void *_this )
|
|
127
|
+
{
|
|
128
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
129
|
+
int i;
|
|
130
|
+
|
|
131
|
+
pg_gc_location( this->connection );
|
|
132
|
+
pg_gc_location( this->typemap );
|
|
133
|
+
pg_gc_location( this->tuple_hash );
|
|
134
|
+
pg_gc_location( this->field_map );
|
|
135
|
+
|
|
136
|
+
for( i=0; i < this->nfields; i++ ){
|
|
137
|
+
pg_gc_location( this->fnames[i] );
|
|
121
138
|
}
|
|
122
139
|
}
|
|
123
140
|
|
|
@@ -125,8 +142,9 @@ pgresult_gc_mark( t_pg_result *this )
|
|
|
125
142
|
* GC Free function
|
|
126
143
|
*/
|
|
127
144
|
static void
|
|
128
|
-
pgresult_clear(
|
|
145
|
+
pgresult_clear( void *_this )
|
|
129
146
|
{
|
|
147
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
130
148
|
if( this->pgresult && !this->autoclear ){
|
|
131
149
|
PQclear(this->pgresult);
|
|
132
150
|
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
|
@@ -139,15 +157,17 @@ pgresult_clear( t_pg_result *this )
|
|
|
139
157
|
}
|
|
140
158
|
|
|
141
159
|
static void
|
|
142
|
-
pgresult_gc_free(
|
|
160
|
+
pgresult_gc_free( void *_this )
|
|
143
161
|
{
|
|
162
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
144
163
|
pgresult_clear( this );
|
|
145
164
|
xfree(this);
|
|
146
165
|
}
|
|
147
166
|
|
|
148
167
|
static size_t
|
|
149
|
-
pgresult_memsize(
|
|
168
|
+
pgresult_memsize( const void *_this )
|
|
150
169
|
{
|
|
170
|
+
const t_pg_result *this = (const t_pg_result *)_this;
|
|
151
171
|
/* Ideally the memory 'this' is pointing to should be taken into account as well.
|
|
152
172
|
* However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
|
|
153
173
|
*/
|
|
@@ -155,16 +175,15 @@ pgresult_memsize( t_pg_result *this )
|
|
|
155
175
|
}
|
|
156
176
|
|
|
157
177
|
static const rb_data_type_t pgresult_type = {
|
|
158
|
-
"
|
|
178
|
+
"PG::Result",
|
|
159
179
|
{
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
180
|
+
pgresult_gc_mark,
|
|
181
|
+
pgresult_gc_free,
|
|
182
|
+
pgresult_memsize,
|
|
183
|
+
pg_compact_callback(pgresult_gc_compact),
|
|
163
184
|
},
|
|
164
185
|
0, 0,
|
|
165
|
-
|
|
166
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
167
|
-
#endif
|
|
186
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
|
168
187
|
};
|
|
169
188
|
|
|
170
189
|
/* Needed by sequel_pg gem, do not delete */
|
|
@@ -189,9 +208,11 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
|
189
208
|
|
|
190
209
|
this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
|
|
191
210
|
this->pgresult = result;
|
|
211
|
+
/* Initialize connection and typemap prior to any object allocations,
|
|
212
|
+
* to make sure valid objects are marked. */
|
|
192
213
|
this->connection = rb_pgconn;
|
|
193
214
|
this->typemap = pg_typemap_all_strings;
|
|
194
|
-
this->p_typemap =
|
|
215
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
|
195
216
|
this->nfields = -1;
|
|
196
217
|
this->tuple_hash = Qnil;
|
|
197
218
|
this->field_map = Qnil;
|
|
@@ -202,11 +223,12 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
|
202
223
|
t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
|
|
203
224
|
VALUE typemap = p_conn->type_map_for_results;
|
|
204
225
|
/* Type check is done when assigned to PG::Connection. */
|
|
205
|
-
t_typemap *p_typemap =
|
|
226
|
+
t_typemap *p_typemap = RTYPEDDATA_DATA(typemap);
|
|
206
227
|
|
|
207
228
|
this->enc_idx = p_conn->enc_idx;
|
|
208
|
-
|
|
209
|
-
|
|
229
|
+
typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
|
230
|
+
RB_OBJ_WRITE(self, &this->typemap, typemap);
|
|
231
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
|
210
232
|
this->flags = p_conn->flags;
|
|
211
233
|
} else {
|
|
212
234
|
this->enc_idx = rb_locale_encindex();
|
|
@@ -270,7 +292,11 @@ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
|
|
|
270
292
|
* call-seq:
|
|
271
293
|
* res.check -> nil
|
|
272
294
|
*
|
|
273
|
-
* Raises appropriate exception if PG::Result is in a bad state
|
|
295
|
+
* Raises appropriate exception if PG::Result is in a bad state, which is:
|
|
296
|
+
* * +PGRES_BAD_RESPONSE+
|
|
297
|
+
* * +PGRES_FATAL_ERROR+
|
|
298
|
+
* * +PGRES_NONFATAL_ERROR+
|
|
299
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
274
300
|
*/
|
|
275
301
|
VALUE
|
|
276
302
|
pg_result_check( VALUE self )
|
|
@@ -295,10 +321,16 @@ pg_result_check( VALUE self )
|
|
|
295
321
|
case PGRES_SINGLE_TUPLE:
|
|
296
322
|
case PGRES_EMPTY_QUERY:
|
|
297
323
|
case PGRES_COMMAND_OK:
|
|
324
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
325
|
+
case PGRES_PIPELINE_SYNC:
|
|
326
|
+
#endif
|
|
298
327
|
return self;
|
|
299
328
|
case PGRES_BAD_RESPONSE:
|
|
300
329
|
case PGRES_FATAL_ERROR:
|
|
301
330
|
case PGRES_NONFATAL_ERROR:
|
|
331
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
332
|
+
case PGRES_PIPELINE_ABORTED:
|
|
333
|
+
#endif
|
|
302
334
|
error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
|
|
303
335
|
break;
|
|
304
336
|
default:
|
|
@@ -345,17 +377,37 @@ VALUE
|
|
|
345
377
|
pg_result_clear(VALUE self)
|
|
346
378
|
{
|
|
347
379
|
t_pg_result *this = pgresult_get_this(self);
|
|
380
|
+
rb_check_frozen(self);
|
|
348
381
|
pgresult_clear( this );
|
|
349
382
|
return Qnil;
|
|
350
383
|
}
|
|
351
384
|
|
|
352
385
|
/*
|
|
353
386
|
* call-seq:
|
|
354
|
-
* res.
|
|
387
|
+
* res.freeze
|
|
388
|
+
*
|
|
389
|
+
* Freeze the PG::Result object and unlink the result from the related PG::Connection.
|
|
390
|
+
*
|
|
391
|
+
* A frozen PG::Result object doesn't allow any streaming and it can't be cleared.
|
|
392
|
+
* It also denies setting a type_map or field_name_type.
|
|
355
393
|
*
|
|
356
|
-
* Returns +true+ if the backend result memory has been free'd.
|
|
357
394
|
*/
|
|
358
395
|
VALUE
|
|
396
|
+
static pg_result_freeze(VALUE self)
|
|
397
|
+
{
|
|
398
|
+
t_pg_result *this = pgresult_get_this(self);
|
|
399
|
+
|
|
400
|
+
RB_OBJ_WRITE(self, &this->connection, Qnil);
|
|
401
|
+
return rb_call_super(0, NULL);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/*
|
|
405
|
+
* call-seq:
|
|
406
|
+
* res.cleared? -> boolean
|
|
407
|
+
*
|
|
408
|
+
* Returns +true+ if the backend result memory has been freed.
|
|
409
|
+
*/
|
|
410
|
+
static VALUE
|
|
359
411
|
pgresult_cleared_p( VALUE self )
|
|
360
412
|
{
|
|
361
413
|
t_pg_result *this = pgresult_get_this(self);
|
|
@@ -367,12 +419,12 @@ pgresult_cleared_p( VALUE self )
|
|
|
367
419
|
* res.autoclear? -> boolean
|
|
368
420
|
*
|
|
369
421
|
* Returns +true+ if the underlying C struct will be cleared at the end of a callback.
|
|
370
|
-
* This applies only to Result objects received by the block to PG::
|
|
422
|
+
* This applies only to Result objects received by the block to PG::Connection#set_notice_receiver .
|
|
371
423
|
*
|
|
372
424
|
* All other Result objects are automatically cleared by the GC when the object is no longer in use or manually by PG::Result#clear .
|
|
373
425
|
*
|
|
374
426
|
*/
|
|
375
|
-
VALUE
|
|
427
|
+
static VALUE
|
|
376
428
|
pgresult_autoclear_p( VALUE self )
|
|
377
429
|
{
|
|
378
430
|
t_pg_result *this = pgresult_get_this(self);
|
|
@@ -448,7 +500,8 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
448
500
|
|
|
449
501
|
for( i=0; i<nfields; i++ ){
|
|
450
502
|
char *cfname = PQfname(this->pgresult, i);
|
|
451
|
-
|
|
503
|
+
VALUE fname = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
|
|
504
|
+
RB_OBJ_WRITE(self, &this->fnames[i], fname);
|
|
452
505
|
this->nfields = i + 1;
|
|
453
506
|
}
|
|
454
507
|
this->nfields = nfields;
|
|
@@ -495,6 +548,11 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
495
548
|
* * +PGRES_NONFATAL_ERROR+
|
|
496
549
|
* * +PGRES_FATAL_ERROR+
|
|
497
550
|
* * +PGRES_COPY_BOTH+
|
|
551
|
+
* * +PGRES_SINGLE_TUPLE+
|
|
552
|
+
* * +PGRES_PIPELINE_SYNC+
|
|
553
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
554
|
+
*
|
|
555
|
+
* Use <tt>res.res_status</tt> to retrieve the string representation.
|
|
498
556
|
*/
|
|
499
557
|
static VALUE
|
|
500
558
|
pgresult_result_status(VALUE self)
|
|
@@ -504,16 +562,38 @@ pgresult_result_status(VALUE self)
|
|
|
504
562
|
|
|
505
563
|
/*
|
|
506
564
|
* call-seq:
|
|
507
|
-
*
|
|
565
|
+
* PG::Result.res_status( status ) -> String
|
|
508
566
|
*
|
|
509
|
-
* Returns the string representation of
|
|
567
|
+
* Returns the string representation of +status+.
|
|
510
568
|
*
|
|
511
569
|
*/
|
|
512
570
|
static VALUE
|
|
513
|
-
|
|
571
|
+
pgresult_s_res_status(VALUE self, VALUE status)
|
|
572
|
+
{
|
|
573
|
+
return rb_utf8_str_new_cstr(PQresStatus(NUM2INT(status)));
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/*
|
|
577
|
+
* call-seq:
|
|
578
|
+
* res.res_status -> String
|
|
579
|
+
* res.res_status( status ) -> String
|
|
580
|
+
*
|
|
581
|
+
* Returns the string representation of the status of the result or of the provided +status+.
|
|
582
|
+
*
|
|
583
|
+
*/
|
|
584
|
+
static VALUE
|
|
585
|
+
pgresult_res_status(int argc, VALUE *argv, VALUE self)
|
|
514
586
|
{
|
|
515
587
|
t_pg_result *this = pgresult_get_this_safe(self);
|
|
516
|
-
VALUE ret
|
|
588
|
+
VALUE ret;
|
|
589
|
+
|
|
590
|
+
if( argc == 0 ){
|
|
591
|
+
ret = rb_str_new2(PQresStatus(PQresultStatus(this->pgresult)));
|
|
592
|
+
}else if( argc == 1 ){
|
|
593
|
+
ret = rb_str_new2(PQresStatus(NUM2INT(argv[0])));
|
|
594
|
+
}else{
|
|
595
|
+
rb_raise(rb_eArgError, "only 0 or 1 arguments expected");
|
|
596
|
+
}
|
|
517
597
|
PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
|
|
518
598
|
return ret;
|
|
519
599
|
}
|
|
@@ -653,6 +733,21 @@ pgresult_nfields(VALUE self)
|
|
|
653
733
|
return INT2NUM(PQnfields(pgresult_get(self)));
|
|
654
734
|
}
|
|
655
735
|
|
|
736
|
+
/*
|
|
737
|
+
* call-seq:
|
|
738
|
+
* res.binary_tuples() -> Integer
|
|
739
|
+
*
|
|
740
|
+
* Returns 1 if the PGresult contains binary data and 0 if it contains text data.
|
|
741
|
+
*
|
|
742
|
+
* This function is deprecated (except for its use in connection with COPY), because it is possible for a single PGresult to contain text data in some columns and binary data in others.
|
|
743
|
+
* Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
|
|
744
|
+
*/
|
|
745
|
+
static VALUE
|
|
746
|
+
pgresult_binary_tuples(VALUE self)
|
|
747
|
+
{
|
|
748
|
+
return INT2NUM(PQbinaryTuples(pgresult_get(self)));
|
|
749
|
+
}
|
|
750
|
+
|
|
656
751
|
/*
|
|
657
752
|
* call-seq:
|
|
658
753
|
* res.fname( index ) -> String or Symbol
|
|
@@ -1003,7 +1098,7 @@ pgresult_cmd_tuples(VALUE self)
|
|
|
1003
1098
|
{
|
|
1004
1099
|
long n;
|
|
1005
1100
|
n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
|
|
1006
|
-
return
|
|
1101
|
+
return LONG2NUM(n);
|
|
1007
1102
|
}
|
|
1008
1103
|
|
|
1009
1104
|
/*
|
|
@@ -1055,7 +1150,7 @@ pgresult_aref(VALUE self, VALUE index)
|
|
|
1055
1150
|
}
|
|
1056
1151
|
/* Store a copy of the filled hash for use at the next row. */
|
|
1057
1152
|
if( num_tuples > 10 )
|
|
1058
|
-
this->tuple_hash
|
|
1153
|
+
RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
|
|
1059
1154
|
|
|
1060
1155
|
return tuple;
|
|
1061
1156
|
}
|
|
@@ -1237,7 +1332,7 @@ static void ensure_init_for_tuple(VALUE self)
|
|
|
1237
1332
|
rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
|
|
1238
1333
|
}
|
|
1239
1334
|
rb_obj_freeze(field_map);
|
|
1240
|
-
this->field_map
|
|
1335
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
|
1241
1336
|
}
|
|
1242
1337
|
}
|
|
1243
1338
|
|
|
@@ -1325,14 +1420,13 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
|
1325
1420
|
t_pg_result *this = pgresult_get_this(self);
|
|
1326
1421
|
t_typemap *p_typemap;
|
|
1327
1422
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
}
|
|
1332
|
-
Data_Get_Struct(typemap, t_typemap, p_typemap);
|
|
1423
|
+
rb_check_frozen(self);
|
|
1424
|
+
/* Check type of method param */
|
|
1425
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, p_typemap);
|
|
1333
1426
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1427
|
+
typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
|
1428
|
+
RB_OBJ_WRITE(self, &this->typemap, typemap);
|
|
1429
|
+
this->p_typemap = RTYPEDDATA_DATA( typemap );
|
|
1336
1430
|
|
|
1337
1431
|
return typemap;
|
|
1338
1432
|
}
|
|
@@ -1353,22 +1447,21 @@ pgresult_type_map_get(VALUE self)
|
|
|
1353
1447
|
}
|
|
1354
1448
|
|
|
1355
1449
|
|
|
1356
|
-
static
|
|
1357
|
-
yield_hash(VALUE self, int ntuples, int nfields)
|
|
1450
|
+
static int
|
|
1451
|
+
yield_hash(VALUE self, int ntuples, int nfields, void *data)
|
|
1358
1452
|
{
|
|
1359
1453
|
int tuple_num;
|
|
1360
|
-
t_pg_result *this = pgresult_get_this(self);
|
|
1361
1454
|
UNUSED(nfields);
|
|
1362
1455
|
|
|
1363
1456
|
for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
|
|
1364
1457
|
rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
|
|
1365
1458
|
}
|
|
1366
1459
|
|
|
1367
|
-
|
|
1460
|
+
return 1; /* clear the result */
|
|
1368
1461
|
}
|
|
1369
1462
|
|
|
1370
|
-
static
|
|
1371
|
-
yield_array(VALUE self, int ntuples, int nfields)
|
|
1463
|
+
static int
|
|
1464
|
+
yield_array(VALUE self, int ntuples, int nfields, void *data)
|
|
1372
1465
|
{
|
|
1373
1466
|
int row;
|
|
1374
1467
|
t_pg_result *this = pgresult_get_this(self);
|
|
@@ -1384,11 +1477,11 @@ yield_array(VALUE self, int ntuples, int nfields)
|
|
|
1384
1477
|
rb_yield( rb_ary_new4( nfields, row_values ));
|
|
1385
1478
|
}
|
|
1386
1479
|
|
|
1387
|
-
|
|
1480
|
+
return 1; /* clear the result */
|
|
1388
1481
|
}
|
|
1389
1482
|
|
|
1390
|
-
static
|
|
1391
|
-
yield_tuple(VALUE self, int ntuples, int nfields)
|
|
1483
|
+
static int
|
|
1484
|
+
yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
|
1392
1485
|
{
|
|
1393
1486
|
int tuple_num;
|
|
1394
1487
|
t_pg_result *this = pgresult_get_this(self);
|
|
@@ -1405,16 +1498,19 @@ yield_tuple(VALUE self, int ntuples, int nfields)
|
|
|
1405
1498
|
VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
|
|
1406
1499
|
rb_yield( tuple );
|
|
1407
1500
|
}
|
|
1501
|
+
return 0; /* don't clear the result */
|
|
1408
1502
|
}
|
|
1409
1503
|
|
|
1410
|
-
static
|
|
1411
|
-
|
|
1504
|
+
/* Non-static, and data pointer for use by sequel_pg */
|
|
1505
|
+
VALUE
|
|
1506
|
+
pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* data)
|
|
1412
1507
|
{
|
|
1413
1508
|
t_pg_result *this;
|
|
1414
|
-
int nfields;
|
|
1509
|
+
int nfields, nfields2;
|
|
1415
1510
|
PGconn *pgconn;
|
|
1416
1511
|
PGresult *pgresult;
|
|
1417
1512
|
|
|
1513
|
+
rb_check_frozen(self);
|
|
1418
1514
|
RETURN_ENUMERATOR(self, 0, NULL);
|
|
1419
1515
|
|
|
1420
1516
|
this = pgresult_get_this_safe(self);
|
|
@@ -1427,6 +1523,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
|
1427
1523
|
|
|
1428
1524
|
switch( PQresultStatus(pgresult) ){
|
|
1429
1525
|
case PGRES_TUPLES_OK:
|
|
1526
|
+
case PGRES_COMMAND_OK:
|
|
1430
1527
|
if( ntuples == 0 )
|
|
1431
1528
|
return self;
|
|
1432
1529
|
rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
|
|
@@ -1436,14 +1533,24 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
|
1436
1533
|
pg_result_check( self );
|
|
1437
1534
|
}
|
|
1438
1535
|
|
|
1439
|
-
|
|
1536
|
+
nfields2 = PQnfields(pgresult);
|
|
1537
|
+
if( nfields != nfields2 ){
|
|
1538
|
+
pgresult_clear( this );
|
|
1539
|
+
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields changed in single row mode from %d to %d - this is a sign for intersection with another query", nfields, nfields2);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
if( yielder( self, ntuples, nfields, data ) ){
|
|
1543
|
+
pgresult_clear( this );
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
if( gvl_PQisBusy(pgconn) ){
|
|
1547
|
+
/* wait for input (without blocking) before reading each result */
|
|
1548
|
+
pgconn_block( 0, NULL, this->connection );
|
|
1549
|
+
}
|
|
1440
1550
|
|
|
1441
1551
|
pgresult = gvl_PQgetResult(pgconn);
|
|
1442
1552
|
if( pgresult == NULL )
|
|
1443
|
-
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another
|
|
1444
|
-
|
|
1445
|
-
if( nfields != PQnfields(pgresult) )
|
|
1446
|
-
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields must not change in single row mode");
|
|
1553
|
+
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
|
|
1447
1554
|
|
|
1448
1555
|
this->pgresult = pgresult;
|
|
1449
1556
|
}
|
|
@@ -1487,7 +1594,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
|
1487
1594
|
static VALUE
|
|
1488
1595
|
pgresult_stream_each(VALUE self)
|
|
1489
1596
|
{
|
|
1490
|
-
return pgresult_stream_any(self, yield_hash);
|
|
1597
|
+
return pgresult_stream_any(self, yield_hash, NULL);
|
|
1491
1598
|
}
|
|
1492
1599
|
|
|
1493
1600
|
/*
|
|
@@ -1503,7 +1610,7 @@ pgresult_stream_each(VALUE self)
|
|
|
1503
1610
|
static VALUE
|
|
1504
1611
|
pgresult_stream_each_row(VALUE self)
|
|
1505
1612
|
{
|
|
1506
|
-
return pgresult_stream_any(self, yield_array);
|
|
1613
|
+
return pgresult_stream_any(self, yield_array, NULL);
|
|
1507
1614
|
}
|
|
1508
1615
|
|
|
1509
1616
|
/*
|
|
@@ -1520,7 +1627,7 @@ pgresult_stream_each_tuple(VALUE self)
|
|
|
1520
1627
|
/* allocate VALUEs that are shared between all streamed tuples */
|
|
1521
1628
|
ensure_init_for_tuple(self);
|
|
1522
1629
|
|
|
1523
|
-
return pgresult_stream_any(self, yield_tuple);
|
|
1630
|
+
return pgresult_stream_any(self, yield_tuple, NULL);
|
|
1524
1631
|
}
|
|
1525
1632
|
|
|
1526
1633
|
/*
|
|
@@ -1531,7 +1638,7 @@ pgresult_stream_each_tuple(VALUE self)
|
|
|
1531
1638
|
* It can be set to one of:
|
|
1532
1639
|
* * +:string+ to use String based field names
|
|
1533
1640
|
* * +:symbol+ to use Symbol based field names
|
|
1534
|
-
* * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future.
|
|
1641
|
+
* * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
|
|
1535
1642
|
*
|
|
1536
1643
|
* The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
|
|
1537
1644
|
*
|
|
@@ -1548,6 +1655,8 @@ static VALUE
|
|
|
1548
1655
|
pgresult_field_name_type_set(VALUE self, VALUE sym)
|
|
1549
1656
|
{
|
|
1550
1657
|
t_pg_result *this = pgresult_get_this(self);
|
|
1658
|
+
|
|
1659
|
+
rb_check_frozen(self);
|
|
1551
1660
|
if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
|
|
1552
1661
|
|
|
1553
1662
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
|
@@ -1581,19 +1690,21 @@ pgresult_field_name_type_get(VALUE self)
|
|
|
1581
1690
|
}
|
|
1582
1691
|
|
|
1583
1692
|
void
|
|
1584
|
-
init_pg_result()
|
|
1693
|
+
init_pg_result(void)
|
|
1585
1694
|
{
|
|
1586
1695
|
sym_string = ID2SYM(rb_intern("string"));
|
|
1587
1696
|
sym_symbol = ID2SYM(rb_intern("symbol"));
|
|
1588
1697
|
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
|
1589
1698
|
|
|
1590
|
-
rb_cPGresult = rb_define_class_under( rb_mPG, "Result",
|
|
1699
|
+
rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
|
|
1700
|
+
rb_undef_alloc_func(rb_cPGresult);
|
|
1591
1701
|
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
|
1592
1702
|
rb_include_module(rb_cPGresult, rb_mPGconstants);
|
|
1593
1703
|
|
|
1594
1704
|
/****** PG::Result INSTANCE METHODS: libpq ******/
|
|
1595
1705
|
rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
|
|
1596
|
-
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
|
|
1706
|
+
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, -1);
|
|
1707
|
+
rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
|
|
1597
1708
|
rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
|
|
1598
1709
|
rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
|
|
1599
1710
|
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
@@ -1603,12 +1714,14 @@ init_pg_result()
|
|
|
1603
1714
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
|
1604
1715
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
|
1605
1716
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
|
1717
|
+
rb_define_method(rb_cPGresult, "freeze", pg_result_freeze, 0 );
|
|
1606
1718
|
rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
|
|
1607
1719
|
rb_define_alias (rb_cPGresult, "check_result", "check");
|
|
1608
1720
|
rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
|
|
1609
1721
|
rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
|
|
1610
1722
|
rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
|
|
1611
1723
|
rb_define_alias(rb_cPGresult, "num_fields", "nfields");
|
|
1724
|
+
rb_define_method(rb_cPGresult, "binary_tuples", pgresult_binary_tuples, 0);
|
|
1612
1725
|
rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
|
|
1613
1726
|
rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
|
|
1614
1727
|
rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
|
data/ext/pg_text_decoder.c
CHANGED
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
#include <string.h>
|
|
44
44
|
|
|
45
45
|
VALUE rb_mPG_TextDecoder;
|
|
46
|
-
static ID s_id_decode;
|
|
47
46
|
static ID s_id_Rational;
|
|
48
47
|
static ID s_id_new;
|
|
49
48
|
static ID s_id_utc;
|
|
@@ -171,6 +170,19 @@ pg_text_dec_numeric(t_pg_coder *conv, const char *val, int len, int tuple, int f
|
|
|
171
170
|
return rb_funcall(rb_cObject, s_id_BigDecimal, 1, rb_str_new(val, len));
|
|
172
171
|
}
|
|
173
172
|
|
|
173
|
+
/* called per autoload when TextDecoder::Numeric is used */
|
|
174
|
+
static VALUE
|
|
175
|
+
init_pg_text_decoder_numeric(VALUE rb_mPG_TextDecoder)
|
|
176
|
+
{
|
|
177
|
+
rb_require("bigdecimal");
|
|
178
|
+
s_id_BigDecimal = rb_intern("BigDecimal");
|
|
179
|
+
|
|
180
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
|
181
|
+
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
182
|
+
|
|
183
|
+
return Qnil;
|
|
184
|
+
}
|
|
185
|
+
|
|
174
186
|
/*
|
|
175
187
|
* Document-class: PG::TextDecoder::Float < PG::SimpleDecoder
|
|
176
188
|
*
|
|
@@ -854,7 +866,7 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
|
854
866
|
|
|
855
867
|
ip_int_native = read_nbo32(dst);
|
|
856
868
|
|
|
857
|
-
/* Work around broken IPAddr behavior of
|
|
869
|
+
/* Work around broken IPAddr behavior of converting portion
|
|
858
870
|
of address after netmask to 0 */
|
|
859
871
|
switch (mask) {
|
|
860
872
|
case 0:
|
|
@@ -922,8 +934,9 @@ pg_text_dec_inet(t_pg_coder *conv, const char *val, int len, int tuple, int fiel
|
|
|
922
934
|
return ip;
|
|
923
935
|
}
|
|
924
936
|
|
|
925
|
-
|
|
926
|
-
|
|
937
|
+
/* called per autoload when TextDecoder::Inet is used */
|
|
938
|
+
static VALUE
|
|
939
|
+
init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
|
|
927
940
|
{
|
|
928
941
|
rb_require("ipaddr");
|
|
929
942
|
s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
|
|
@@ -942,14 +955,21 @@ init_pg_text_decoder()
|
|
|
942
955
|
s_vmasks6 = rb_eval_string("a = [0]*129; a[0] = 0; a[128] = 0xffffffffffffffffffffffffffffffff; 127.downto(1){|i| a[i] = a[i+1] - (1 << (127 - i))}; a.freeze");
|
|
943
956
|
rb_global_variable(&s_vmasks6);
|
|
944
957
|
|
|
945
|
-
|
|
958
|
+
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
|
959
|
+
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
|
960
|
+
|
|
961
|
+
return Qnil;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
void
|
|
966
|
+
init_pg_text_decoder(void)
|
|
967
|
+
{
|
|
946
968
|
s_id_Rational = rb_intern("Rational");
|
|
947
969
|
s_id_new = rb_intern("new");
|
|
948
970
|
s_id_utc = rb_intern("utc");
|
|
949
971
|
s_id_getlocal = rb_intern("getlocal");
|
|
950
972
|
|
|
951
|
-
rb_require("bigdecimal");
|
|
952
|
-
s_id_BigDecimal = rb_intern("BigDecimal");
|
|
953
973
|
s_nan = rb_eval_string("0.0/0.0");
|
|
954
974
|
rb_global_variable(&s_nan);
|
|
955
975
|
s_pos_inf = rb_eval_string("1.0/0.0");
|
|
@@ -959,6 +979,8 @@ init_pg_text_decoder()
|
|
|
959
979
|
|
|
960
980
|
/* This module encapsulates all decoder classes with text input format */
|
|
961
981
|
rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
|
|
982
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_inet", init_pg_text_decoder_inet, 0);
|
|
983
|
+
rb_define_private_method(rb_singleton_class(rb_mPG_TextDecoder), "init_numeric", init_pg_text_decoder_numeric, 0);
|
|
962
984
|
|
|
963
985
|
/* Make RDoc aware of the decoder classes... */
|
|
964
986
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Boolean", rb_cPG_SimpleDecoder ); */
|
|
@@ -967,8 +989,6 @@ init_pg_text_decoder()
|
|
|
967
989
|
pg_define_coder( "Integer", pg_text_dec_integer, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
968
990
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Float", rb_cPG_SimpleDecoder ); */
|
|
969
991
|
pg_define_coder( "Float", pg_text_dec_float, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
970
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Numeric", rb_cPG_SimpleDecoder ); */
|
|
971
|
-
pg_define_coder( "Numeric", pg_text_dec_numeric, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
972
992
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "String", rb_cPG_SimpleDecoder ); */
|
|
973
993
|
pg_define_coder( "String", pg_text_dec_string, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
974
994
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Bytea", rb_cPG_SimpleDecoder ); */
|
|
@@ -977,8 +997,6 @@ init_pg_text_decoder()
|
|
|
977
997
|
pg_define_coder( "Identifier", pg_text_dec_identifier, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder );
|
|
978
998
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Timestamp", rb_cPG_SimpleDecoder ); */
|
|
979
999
|
pg_define_coder( "Timestamp", pg_text_dec_timestamp, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
|
980
|
-
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
|
981
|
-
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
|
982
1000
|
|
|
983
1001
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Array", rb_cPG_CompositeDecoder ); */
|
|
984
1002
|
pg_define_coder( "Array", pg_text_dec_array, rb_cPG_CompositeDecoder, rb_mPG_TextDecoder );
|