pg 1.2.3 → 1.6.1
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/CHANGELOG.md +986 -0
- data/Gemfile +23 -0
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +300 -0
- data/README.md +327 -0
- data/Rakefile +123 -144
- data/certs/ged.pem +24 -0
- data/certs/kanis@comcard.de.pem +20 -0
- data/certs/larskanis-2022.pem +26 -0
- data/certs/larskanis-2023.pem +24 -0
- data/certs/larskanis-2024.pem +24 -0
- data/ext/errorcodes.def +16 -5
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +5 -5
- data/ext/extconf.rb +259 -33
- data/ext/gvl_wrappers.c +17 -2
- data/ext/gvl_wrappers.h +56 -0
- data/ext/pg.c +89 -63
- data/ext/pg.h +31 -8
- data/ext/pg_binary_decoder.c +232 -1
- data/ext/pg_binary_encoder.c +428 -1
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +148 -36
- data/ext/pg_connection.c +1365 -817
- data/ext/pg_copy_coder.c +360 -38
- data/ext/pg_errors.c +1 -1
- data/ext/pg_record_coder.c +56 -25
- data/ext/pg_result.c +187 -76
- data/ext/pg_text_decoder.c +32 -11
- data/ext/pg_text_encoder.c +65 -33
- data/ext/pg_tuple.c +84 -61
- 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 +74 -31
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +61 -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 +206 -0
- data/lib/pg/basic_type_map_for_results.rb +104 -0
- data/lib/pg/basic_type_registry.rb +311 -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/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +18 -14
- data/lib/pg/connection.rb +894 -91
- data/lib/pg/exceptions.rb +20 -1
- data/lib/pg/text_decoder/date.rb +21 -0
- data/lib/pg/text_decoder/inet.rb +9 -0
- data/lib/pg/text_decoder/json.rb +17 -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 +13 -0
- data/lib/pg/text_encoder/inet.rb +31 -0
- data/lib/pg/text_encoder/json.rb +17 -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 +109 -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/misc/yugabyte/Dockerfile +9 -0
- data/misc/yugabyte/docker-compose.yml +28 -0
- data/misc/yugabyte/pg-test.rb +45 -0
- data/pg.gemspec +38 -0
- data/ports/patches/krb5/1.21.3/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/openssl/3.5.1/0001-aarch64-mingw.patch +21 -0
- data/ports/patches/postgresql/17.5/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/ports/patches/postgresql/17.5/0001-libpq-Process-buffered-SSL-read-bytes-to-support-rec.patch +52 -0
- data/rakelib/pg_gem_helper.rb +64 -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.tar.gz.sig +0 -0
- metadata +139 -213
- metadata.gz.sig +0 -0
- data/.gemtest +0 -0
- data/ChangeLog +0 -0
- data/History.rdoc +0 -578
- data/Manifest.txt +0 -73
- data/README.ja.rdoc +0 -13
- data/README.rdoc +0 -213
- data/Rakefile.cross +0 -299
- 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,13 +142,12 @@ 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
|
-
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
133
150
|
rb_gc_adjust_memory_usage(-this->result_size);
|
134
|
-
#endif
|
135
151
|
}
|
136
152
|
this->result_size = 0;
|
137
153
|
this->nfields = -1;
|
@@ -139,15 +155,17 @@ pgresult_clear( t_pg_result *this )
|
|
139
155
|
}
|
140
156
|
|
141
157
|
static void
|
142
|
-
pgresult_gc_free(
|
158
|
+
pgresult_gc_free( void *_this )
|
143
159
|
{
|
160
|
+
t_pg_result *this = (t_pg_result *)_this;
|
144
161
|
pgresult_clear( this );
|
145
162
|
xfree(this);
|
146
163
|
}
|
147
164
|
|
148
165
|
static size_t
|
149
|
-
pgresult_memsize(
|
166
|
+
pgresult_memsize( const void *_this )
|
150
167
|
{
|
168
|
+
const t_pg_result *this = (const t_pg_result *)_this;
|
151
169
|
/* Ideally the memory 'this' is pointing to should be taken into account as well.
|
152
170
|
* However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
|
153
171
|
*/
|
@@ -155,16 +173,15 @@ pgresult_memsize( t_pg_result *this )
|
|
155
173
|
}
|
156
174
|
|
157
175
|
static const rb_data_type_t pgresult_type = {
|
158
|
-
"
|
176
|
+
"PG::Result",
|
159
177
|
{
|
160
|
-
|
161
|
-
|
162
|
-
|
178
|
+
pgresult_gc_mark,
|
179
|
+
pgresult_gc_free,
|
180
|
+
pgresult_memsize,
|
181
|
+
pgresult_gc_compact,
|
163
182
|
},
|
164
183
|
0, 0,
|
165
|
-
|
166
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
167
|
-
#endif
|
184
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | PG_RUBY_TYPED_FROZEN_SHAREABLE,
|
168
185
|
};
|
169
186
|
|
170
187
|
/* Needed by sequel_pg gem, do not delete */
|
@@ -189,9 +206,11 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
189
206
|
|
190
207
|
this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
|
191
208
|
this->pgresult = result;
|
209
|
+
/* Initialize connection and typemap prior to any object allocations,
|
210
|
+
* to make sure valid objects are marked. */
|
192
211
|
this->connection = rb_pgconn;
|
193
212
|
this->typemap = pg_typemap_all_strings;
|
194
|
-
this->p_typemap =
|
213
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
195
214
|
this->nfields = -1;
|
196
215
|
this->tuple_hash = Qnil;
|
197
216
|
this->field_map = Qnil;
|
@@ -202,11 +221,12 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
202
221
|
t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
|
203
222
|
VALUE typemap = p_conn->type_map_for_results;
|
204
223
|
/* Type check is done when assigned to PG::Connection. */
|
205
|
-
t_typemap *p_typemap =
|
224
|
+
t_typemap *p_typemap = RTYPEDDATA_DATA(typemap);
|
206
225
|
|
207
226
|
this->enc_idx = p_conn->enc_idx;
|
208
|
-
|
209
|
-
|
227
|
+
typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
228
|
+
RB_OBJ_WRITE(self, &this->typemap, typemap);
|
229
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
210
230
|
this->flags = p_conn->flags;
|
211
231
|
} else {
|
212
232
|
this->enc_idx = rb_locale_encindex();
|
@@ -231,9 +251,7 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
|
|
231
251
|
*/
|
232
252
|
this->result_size = pgresult_approx_size(result);
|
233
253
|
|
234
|
-
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
235
254
|
rb_gc_adjust_memory_usage(this->result_size);
|
236
|
-
#endif
|
237
255
|
|
238
256
|
return self;
|
239
257
|
}
|
@@ -270,7 +288,11 @@ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
|
|
270
288
|
* call-seq:
|
271
289
|
* res.check -> nil
|
272
290
|
*
|
273
|
-
* Raises appropriate exception if PG::Result is in a bad state
|
291
|
+
* Raises appropriate exception if PG::Result is in a bad state, which is:
|
292
|
+
* * +PGRES_BAD_RESPONSE+
|
293
|
+
* * +PGRES_FATAL_ERROR+
|
294
|
+
* * +PGRES_NONFATAL_ERROR+
|
295
|
+
* * +PGRES_PIPELINE_ABORTED+
|
274
296
|
*/
|
275
297
|
VALUE
|
276
298
|
pg_result_check( VALUE self )
|
@@ -295,10 +317,19 @@ pg_result_check( VALUE self )
|
|
295
317
|
case PGRES_SINGLE_TUPLE:
|
296
318
|
case PGRES_EMPTY_QUERY:
|
297
319
|
case PGRES_COMMAND_OK:
|
320
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
321
|
+
case PGRES_PIPELINE_SYNC:
|
322
|
+
#endif
|
323
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
324
|
+
case PGRES_TUPLES_CHUNK:
|
325
|
+
#endif
|
298
326
|
return self;
|
299
327
|
case PGRES_BAD_RESPONSE:
|
300
328
|
case PGRES_FATAL_ERROR:
|
301
329
|
case PGRES_NONFATAL_ERROR:
|
330
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
331
|
+
case PGRES_PIPELINE_ABORTED:
|
332
|
+
#endif
|
302
333
|
error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
|
303
334
|
break;
|
304
335
|
default:
|
@@ -345,17 +376,37 @@ VALUE
|
|
345
376
|
pg_result_clear(VALUE self)
|
346
377
|
{
|
347
378
|
t_pg_result *this = pgresult_get_this(self);
|
379
|
+
rb_check_frozen(self);
|
348
380
|
pgresult_clear( this );
|
349
381
|
return Qnil;
|
350
382
|
}
|
351
383
|
|
384
|
+
/*
|
385
|
+
* call-seq:
|
386
|
+
* res.freeze
|
387
|
+
*
|
388
|
+
* Freeze the PG::Result object and unlink the result from the related PG::Connection.
|
389
|
+
*
|
390
|
+
* A frozen PG::Result object doesn't allow any streaming and it can't be cleared.
|
391
|
+
* It also denies setting a type_map or field_name_type.
|
392
|
+
*
|
393
|
+
*/
|
394
|
+
static VALUE
|
395
|
+
pg_result_freeze(VALUE self)
|
396
|
+
{
|
397
|
+
t_pg_result *this = pgresult_get_this(self);
|
398
|
+
|
399
|
+
RB_OBJ_WRITE(self, &this->connection, Qnil);
|
400
|
+
return rb_call_super(0, NULL);
|
401
|
+
}
|
402
|
+
|
352
403
|
/*
|
353
404
|
* call-seq:
|
354
405
|
* res.cleared? -> boolean
|
355
406
|
*
|
356
|
-
* Returns +true+ if the backend result memory has been
|
407
|
+
* Returns +true+ if the backend result memory has been freed.
|
357
408
|
*/
|
358
|
-
VALUE
|
409
|
+
static VALUE
|
359
410
|
pgresult_cleared_p( VALUE self )
|
360
411
|
{
|
361
412
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -367,12 +418,12 @@ pgresult_cleared_p( VALUE self )
|
|
367
418
|
* res.autoclear? -> boolean
|
368
419
|
*
|
369
420
|
* 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::
|
421
|
+
* This applies only to Result objects received by the block to PG::Connection#set_notice_receiver .
|
371
422
|
*
|
372
423
|
* 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
424
|
*
|
374
425
|
*/
|
375
|
-
VALUE
|
426
|
+
static VALUE
|
376
427
|
pgresult_autoclear_p( VALUE self )
|
377
428
|
{
|
378
429
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -448,7 +499,8 @@ static void pgresult_init_fnames(VALUE self)
|
|
448
499
|
|
449
500
|
for( i=0; i<nfields; i++ ){
|
450
501
|
char *cfname = PQfname(this->pgresult, i);
|
451
|
-
|
502
|
+
VALUE fname = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
|
503
|
+
RB_OBJ_WRITE(self, &this->fnames[i], fname);
|
452
504
|
this->nfields = i + 1;
|
453
505
|
}
|
454
506
|
this->nfields = nfields;
|
@@ -495,6 +547,12 @@ static void pgresult_init_fnames(VALUE self)
|
|
495
547
|
* * +PGRES_NONFATAL_ERROR+
|
496
548
|
* * +PGRES_FATAL_ERROR+
|
497
549
|
* * +PGRES_COPY_BOTH+
|
550
|
+
* * +PGRES_SINGLE_TUPLE+
|
551
|
+
* * +PGRES_TUPLES_CHUNK+
|
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
|
}
|
@@ -533,14 +613,12 @@ pgresult_error_message(VALUE self)
|
|
533
613
|
return ret;
|
534
614
|
}
|
535
615
|
|
536
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
537
616
|
/*
|
538
617
|
* call-seq:
|
539
618
|
* res.verbose_error_message( verbosity, show_context ) -> String
|
540
619
|
*
|
541
620
|
* Returns a reformatted version of the error message associated with a PGresult object.
|
542
621
|
*
|
543
|
-
* Available since PostgreSQL-9.6
|
544
622
|
*/
|
545
623
|
static VALUE
|
546
624
|
pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
@@ -559,7 +637,6 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
559
637
|
|
560
638
|
return ret;
|
561
639
|
}
|
562
|
-
#endif
|
563
640
|
|
564
641
|
/*
|
565
642
|
* call-seq:
|
@@ -584,7 +661,7 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
584
661
|
* An example:
|
585
662
|
*
|
586
663
|
* begin
|
587
|
-
* conn.exec( "SELECT * FROM
|
664
|
+
* conn.exec( "SELECT * FROM nonexistent_table" )
|
588
665
|
* rescue PG::Error => err
|
589
666
|
* p [
|
590
667
|
* err.result.error_field( PG::Result::PG_DIAG_SEVERITY ),
|
@@ -604,7 +681,7 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
604
681
|
*
|
605
682
|
* Outputs:
|
606
683
|
*
|
607
|
-
* ["ERROR", "42P01", "relation \"
|
684
|
+
* ["ERROR", "42P01", "relation \"nonexistent_table\" does not exist", nil, nil,
|
608
685
|
* "15", nil, nil, nil, "path/to/parse_relation.c", "857", "parserOpenTable"]
|
609
686
|
*/
|
610
687
|
static VALUE
|
@@ -653,6 +730,21 @@ pgresult_nfields(VALUE self)
|
|
653
730
|
return INT2NUM(PQnfields(pgresult_get(self)));
|
654
731
|
}
|
655
732
|
|
733
|
+
/*
|
734
|
+
* call-seq:
|
735
|
+
* res.binary_tuples() -> Integer
|
736
|
+
*
|
737
|
+
* Returns 1 if the PGresult contains binary data and 0 if it contains text data.
|
738
|
+
*
|
739
|
+
* 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.
|
740
|
+
* Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
|
741
|
+
*/
|
742
|
+
static VALUE
|
743
|
+
pgresult_binary_tuples(VALUE self)
|
744
|
+
{
|
745
|
+
return INT2NUM(PQbinaryTuples(pgresult_get(self)));
|
746
|
+
}
|
747
|
+
|
656
748
|
/*
|
657
749
|
* call-seq:
|
658
750
|
* res.fname( index ) -> String or Symbol
|
@@ -1003,7 +1095,7 @@ pgresult_cmd_tuples(VALUE self)
|
|
1003
1095
|
{
|
1004
1096
|
long n;
|
1005
1097
|
n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
|
1006
|
-
return
|
1098
|
+
return LONG2NUM(n);
|
1007
1099
|
}
|
1008
1100
|
|
1009
1101
|
/*
|
@@ -1055,7 +1147,7 @@ pgresult_aref(VALUE self, VALUE index)
|
|
1055
1147
|
}
|
1056
1148
|
/* Store a copy of the filled hash for use at the next row. */
|
1057
1149
|
if( num_tuples > 10 )
|
1058
|
-
this->tuple_hash
|
1150
|
+
RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
|
1059
1151
|
|
1060
1152
|
return tuple;
|
1061
1153
|
}
|
@@ -1237,7 +1329,7 @@ static void ensure_init_for_tuple(VALUE self)
|
|
1237
1329
|
rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
|
1238
1330
|
}
|
1239
1331
|
rb_obj_freeze(field_map);
|
1240
|
-
this->field_map
|
1332
|
+
RB_OBJ_WRITE(self, &this->field_map, field_map);
|
1241
1333
|
}
|
1242
1334
|
}
|
1243
1335
|
|
@@ -1325,14 +1417,13 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
1325
1417
|
t_pg_result *this = pgresult_get_this(self);
|
1326
1418
|
t_typemap *p_typemap;
|
1327
1419
|
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
}
|
1332
|
-
Data_Get_Struct(typemap, t_typemap, p_typemap);
|
1420
|
+
rb_check_frozen(self);
|
1421
|
+
/* Check type of method param */
|
1422
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, p_typemap);
|
1333
1423
|
|
1334
|
-
|
1335
|
-
|
1424
|
+
typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
1425
|
+
RB_OBJ_WRITE(self, &this->typemap, typemap);
|
1426
|
+
this->p_typemap = RTYPEDDATA_DATA( typemap );
|
1336
1427
|
|
1337
1428
|
return typemap;
|
1338
1429
|
}
|
@@ -1353,22 +1444,21 @@ pgresult_type_map_get(VALUE self)
|
|
1353
1444
|
}
|
1354
1445
|
|
1355
1446
|
|
1356
|
-
static
|
1357
|
-
yield_hash(VALUE self, int ntuples, int nfields)
|
1447
|
+
static int
|
1448
|
+
yield_hash(VALUE self, int ntuples, int nfields, void *data)
|
1358
1449
|
{
|
1359
1450
|
int tuple_num;
|
1360
|
-
t_pg_result *this = pgresult_get_this(self);
|
1361
1451
|
UNUSED(nfields);
|
1362
1452
|
|
1363
1453
|
for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
|
1364
1454
|
rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
|
1365
1455
|
}
|
1366
1456
|
|
1367
|
-
|
1457
|
+
return 1; /* clear the result */
|
1368
1458
|
}
|
1369
1459
|
|
1370
|
-
static
|
1371
|
-
yield_array(VALUE self, int ntuples, int nfields)
|
1460
|
+
static int
|
1461
|
+
yield_array(VALUE self, int ntuples, int nfields, void *data)
|
1372
1462
|
{
|
1373
1463
|
int row;
|
1374
1464
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1384,11 +1474,11 @@ yield_array(VALUE self, int ntuples, int nfields)
|
|
1384
1474
|
rb_yield( rb_ary_new4( nfields, row_values ));
|
1385
1475
|
}
|
1386
1476
|
|
1387
|
-
|
1477
|
+
return 1; /* clear the result */
|
1388
1478
|
}
|
1389
1479
|
|
1390
|
-
static
|
1391
|
-
yield_tuple(VALUE self, int ntuples, int nfields)
|
1480
|
+
static int
|
1481
|
+
yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
1392
1482
|
{
|
1393
1483
|
int tuple_num;
|
1394
1484
|
t_pg_result *this = pgresult_get_this(self);
|
@@ -1405,16 +1495,19 @@ yield_tuple(VALUE self, int ntuples, int nfields)
|
|
1405
1495
|
VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
|
1406
1496
|
rb_yield( tuple );
|
1407
1497
|
}
|
1498
|
+
return 0; /* don't clear the result */
|
1408
1499
|
}
|
1409
1500
|
|
1410
|
-
static
|
1411
|
-
|
1501
|
+
/* Non-static, and data pointer for use by sequel_pg */
|
1502
|
+
VALUE
|
1503
|
+
pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* data)
|
1412
1504
|
{
|
1413
1505
|
t_pg_result *this;
|
1414
|
-
int nfields;
|
1506
|
+
int nfields, nfields2;
|
1415
1507
|
PGconn *pgconn;
|
1416
1508
|
PGresult *pgresult;
|
1417
1509
|
|
1510
|
+
rb_check_frozen(self);
|
1418
1511
|
RETURN_ENUMERATOR(self, 0, NULL);
|
1419
1512
|
|
1420
1513
|
this = pgresult_get_this_safe(self);
|
@@ -1427,23 +1520,37 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
1427
1520
|
|
1428
1521
|
switch( PQresultStatus(pgresult) ){
|
1429
1522
|
case PGRES_TUPLES_OK:
|
1523
|
+
case PGRES_COMMAND_OK:
|
1430
1524
|
if( ntuples == 0 )
|
1431
1525
|
return self;
|
1432
1526
|
rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
|
1433
1527
|
case PGRES_SINGLE_TUPLE:
|
1528
|
+
#ifdef HAVE_PQSETCHUNKEDROWSMODE
|
1529
|
+
case PGRES_TUPLES_CHUNK:
|
1530
|
+
#endif
|
1434
1531
|
break;
|
1435
1532
|
default:
|
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
|
}
|
@@ -1465,7 +1572,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
1465
1572
|
* wrapping each row into a dedicated result object, it delivers data in nearly
|
1466
1573
|
* the same speed as with ordinary results.
|
1467
1574
|
*
|
1468
|
-
* The base result must be in status PGRES_SINGLE_TUPLE.
|
1575
|
+
* The base result must be in status PGRES_SINGLE_TUPLE or PGRES_TUPLES_CHUNK.
|
1469
1576
|
* It iterates over all tuples until the status changes to PGRES_TUPLES_OK.
|
1470
1577
|
* A PG::Error is raised for any errors from the server.
|
1471
1578
|
*
|
@@ -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,34 +1690,36 @@ 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
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
1600
1710
|
rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
|
1601
1711
|
rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
|
1602
|
-
#endif
|
1603
1712
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
1604
1713
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
1605
1714
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
1715
|
+
rb_define_method(rb_cPGresult, "freeze", pg_result_freeze, 0 );
|
1606
1716
|
rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
|
1607
1717
|
rb_define_alias (rb_cPGresult, "check_result", "check");
|
1608
1718
|
rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
|
1609
1719
|
rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
|
1610
1720
|
rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
|
1611
1721
|
rb_define_alias(rb_cPGresult, "num_fields", "nfields");
|
1722
|
+
rb_define_method(rb_cPGresult, "binary_tuples", pgresult_binary_tuples, 0);
|
1612
1723
|
rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
|
1613
1724
|
rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
|
1614
1725
|
rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
|