pg 1.5.9 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/{History.md → CHANGELOG.md} +126 -0
- data/Gemfile +11 -7
- data/README-Windows.rdoc +1 -1
- data/README.ja.md +83 -32
- data/README.md +79 -29
- data/Rakefile +84 -19
- data/certs/larskanis-2026.pem +24 -0
- data/ext/errorcodes.def +9 -0
- data/ext/errorcodes.rb +1 -1
- data/ext/errorcodes.txt +8 -1
- data/ext/extconf.rb +194 -30
- data/ext/gvl_wrappers.c +13 -2
- data/ext/gvl_wrappers.h +47 -134
- data/ext/pg.c +23 -16
- data/ext/pg.h +23 -24
- data/ext/pg_binary_decoder.c +157 -3
- data/ext/pg_binary_encoder.c +219 -9
- data/ext/pg_cancel_connection.c +360 -0
- data/ext/pg_coder.c +58 -9
- data/ext/pg_connection.c +558 -291
- data/ext/pg_copy_coder.c +36 -23
- data/ext/pg_record_coder.c +11 -7
- data/ext/pg_result.c +144 -76
- data/ext/pg_text_decoder.c +7 -7
- data/ext/pg_text_encoder.c +29 -11
- data/ext/pg_tuple.c +9 -9
- data/ext/pg_type_map.c +45 -3
- data/ext/pg_type_map_all_strings.c +3 -3
- data/ext/pg_type_map_by_class.c +2 -2
- data/ext/pg_type_map_by_column.c +4 -3
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +4 -2
- data/ext/pg_type_map_in_ruby.c +2 -2
- data/ext/pg_util.c +2 -2
- data/ext/pg_util.h +2 -2
- data/lib/pg/basic_type_map_based_on_result.rb +5 -0
- data/lib/pg/basic_type_map_for_queries.rb +16 -5
- data/lib/pg/basic_type_map_for_results.rb +5 -0
- data/lib/pg/basic_type_registry.rb +2 -2
- data/lib/pg/cancel_connection.rb +53 -0
- data/lib/pg/coder.rb +4 -2
- data/lib/pg/connection.rb +393 -180
- data/lib/pg/text_decoder/date.rb +1 -1
- data/lib/pg/text_decoder/json.rb +1 -1
- data/lib/pg/text_encoder/date.rb +7 -1
- data/lib/pg/text_encoder/json.rb +1 -1
- data/lib/pg/version.rb +2 -1
- data/lib/pg.rb +156 -130
- data/misc/glibc/Dockerfile +20 -0
- data/misc/glibc/docker-compose.yml +9 -0
- data/misc/glibc/glibc_spec.rb +5 -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 +5 -3
- data/ports/patches/krb5/1.22.2/0001-Allow-static-linking-krb5-library.patch +30 -0
- data/ports/patches/krb5/1.22.2/0002-unknown-command-line-option-on-clang.patch +12 -0
- data/ports/patches/postgresql/18.6/0001-Use-workaround-of-__builtin_setjmp-only-on-MINGW-on-.patch +42 -0
- data/rakelib/pg_gem_helper.rb +64 -0
- data/sample/async_mixed.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +36 -22
- metadata.gz.sig +0 -0
- data/Manifest.txt +0 -72
- data/Rakefile.cross +0 -303
data/ext/pg_result.c
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
#include "pg.h"
|
|
8
8
|
|
|
9
9
|
VALUE rb_cPGresult;
|
|
10
|
-
static VALUE sym_symbol, sym_string
|
|
10
|
+
static VALUE sym_symbol, sym_string;
|
|
11
11
|
|
|
12
12
|
static VALUE pgresult_type_map_set( VALUE, VALUE );
|
|
13
13
|
static t_pg_result *pgresult_get_this( VALUE );
|
|
14
14
|
static t_pg_result *pgresult_get_this_safe( VALUE );
|
|
15
|
+
static void ensure_init_for_tuple(VALUE self);
|
|
15
16
|
|
|
16
17
|
#if defined(HAVE_PQRESULTMEMORYSIZE)
|
|
17
18
|
|
|
@@ -114,7 +115,6 @@ pgresult_gc_mark( void *_this )
|
|
|
114
115
|
|
|
115
116
|
rb_gc_mark_movable( this->connection );
|
|
116
117
|
rb_gc_mark_movable( this->typemap );
|
|
117
|
-
rb_gc_mark_movable( this->tuple_hash );
|
|
118
118
|
rb_gc_mark_movable( this->field_map );
|
|
119
119
|
|
|
120
120
|
for( i=0; i < this->nfields; i++ ){
|
|
@@ -130,7 +130,6 @@ pgresult_gc_compact( void *_this )
|
|
|
130
130
|
|
|
131
131
|
pg_gc_location( this->connection );
|
|
132
132
|
pg_gc_location( this->typemap );
|
|
133
|
-
pg_gc_location( this->tuple_hash );
|
|
134
133
|
pg_gc_location( this->field_map );
|
|
135
134
|
|
|
136
135
|
for( i=0; i < this->nfields; i++ ){
|
|
@@ -147,9 +146,7 @@ pgresult_clear( void *_this )
|
|
|
147
146
|
t_pg_result *this = (t_pg_result *)_this;
|
|
148
147
|
if( this->pgresult && !this->autoclear ){
|
|
149
148
|
PQclear(this->pgresult);
|
|
150
|
-
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
|
151
149
|
rb_gc_adjust_memory_usage(-this->result_size);
|
|
152
|
-
#endif
|
|
153
150
|
}
|
|
154
151
|
this->result_size = 0;
|
|
155
152
|
this->nfields = -1;
|
|
@@ -180,10 +177,10 @@ static const rb_data_type_t pgresult_type = {
|
|
|
180
177
|
pgresult_gc_mark,
|
|
181
178
|
pgresult_gc_free,
|
|
182
179
|
pgresult_memsize,
|
|
183
|
-
|
|
180
|
+
pgresult_gc_compact,
|
|
184
181
|
},
|
|
185
182
|
0, 0,
|
|
186
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED |
|
|
183
|
+
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
187
184
|
};
|
|
188
185
|
|
|
189
186
|
/* Needed by sequel_pg gem, do not delete */
|
|
@@ -214,7 +211,6 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
|
214
211
|
this->typemap = pg_typemap_all_strings;
|
|
215
212
|
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
|
216
213
|
this->nfields = -1;
|
|
217
|
-
this->tuple_hash = Qnil;
|
|
218
214
|
this->field_map = Qnil;
|
|
219
215
|
this->flags = 0;
|
|
220
216
|
self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
|
|
@@ -253,9 +249,7 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
|
|
|
253
249
|
*/
|
|
254
250
|
this->result_size = pgresult_approx_size(result);
|
|
255
251
|
|
|
256
|
-
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
|
257
252
|
rb_gc_adjust_memory_usage(this->result_size);
|
|
258
|
-
#endif
|
|
259
253
|
|
|
260
254
|
return self;
|
|
261
255
|
}
|
|
@@ -321,14 +315,17 @@ pg_result_check( VALUE self )
|
|
|
321
315
|
case PGRES_SINGLE_TUPLE:
|
|
322
316
|
case PGRES_EMPTY_QUERY:
|
|
323
317
|
case PGRES_COMMAND_OK:
|
|
324
|
-
#ifdef
|
|
318
|
+
#ifdef LIBPQ_HAS_PIPELINING
|
|
325
319
|
case PGRES_PIPELINE_SYNC:
|
|
320
|
+
#endif
|
|
321
|
+
#ifdef LIBPQ_HAS_CHUNK_MODE
|
|
322
|
+
case PGRES_TUPLES_CHUNK:
|
|
326
323
|
#endif
|
|
327
324
|
return self;
|
|
328
325
|
case PGRES_BAD_RESPONSE:
|
|
329
326
|
case PGRES_FATAL_ERROR:
|
|
330
327
|
case PGRES_NONFATAL_ERROR:
|
|
331
|
-
#ifdef
|
|
328
|
+
#ifdef LIBPQ_HAS_PIPELINING
|
|
332
329
|
case PGRES_PIPELINE_ABORTED:
|
|
333
330
|
#endif
|
|
334
331
|
error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
|
|
@@ -397,6 +394,7 @@ pg_result_freeze(VALUE self)
|
|
|
397
394
|
{
|
|
398
395
|
t_pg_result *this = pgresult_get_this(self);
|
|
399
396
|
|
|
397
|
+
ensure_init_for_tuple(self);
|
|
400
398
|
RB_OBJ_WRITE(self, &this->connection, Qnil);
|
|
401
399
|
return rb_call_super(0, NULL);
|
|
402
400
|
}
|
|
@@ -467,9 +465,6 @@ pgresult_get(VALUE self)
|
|
|
467
465
|
static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
|
|
468
466
|
{
|
|
469
467
|
VALUE fname;
|
|
470
|
-
#ifdef TRUFFLERUBY
|
|
471
|
-
if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
|
|
472
|
-
#else
|
|
473
468
|
if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
|
474
469
|
rb_encoding *enc = rb_enc_from_index(enc_idx);
|
|
475
470
|
fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
|
|
@@ -478,14 +473,9 @@ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
|
|
|
478
473
|
PG_ENCODING_SET_NOCHECK(fname, enc_idx);
|
|
479
474
|
fname = rb_str_intern(fname);
|
|
480
475
|
}
|
|
481
|
-
} else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
|
482
|
-
#endif
|
|
483
|
-
rb_encoding *enc = rb_enc_from_index(enc_idx);
|
|
484
|
-
fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
|
|
485
476
|
} else {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
fname = rb_obj_freeze(fname);
|
|
477
|
+
rb_encoding *enc = rb_enc_from_index(enc_idx);
|
|
478
|
+
fname = rb_enc_interned_str(cstr, strlen(cstr), enc);
|
|
489
479
|
}
|
|
490
480
|
return fname;
|
|
491
481
|
}
|
|
@@ -514,20 +504,48 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
514
504
|
*
|
|
515
505
|
* The class to represent the query result tuples (rows).
|
|
516
506
|
* An instance of this class is created as the result of every query.
|
|
517
|
-
* All result rows and columns are stored in
|
|
518
|
-
* Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
|
|
519
|
-
*
|
|
520
|
-
* Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
|
|
521
|
-
* You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
|
|
507
|
+
* All result rows and columns are stored in an immutable memory block attached to the PG::Result object unless streaming is used.
|
|
522
508
|
*
|
|
523
|
-
*
|
|
509
|
+
* A PG::Result has various ways to retrieve the result data:
|
|
524
510
|
* require 'pg'
|
|
525
|
-
* conn = PG.connect(:
|
|
526
|
-
* res
|
|
527
|
-
* res.
|
|
528
|
-
* res
|
|
529
|
-
* res
|
|
511
|
+
* conn = PG.connect(dbname: 'test')
|
|
512
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
513
|
+
* res.num_fields # 3
|
|
514
|
+
* res.num_tuples # 1
|
|
515
|
+
* res.fname(2) # "c"
|
|
516
|
+
* res.fields # ["a", "b", "c"]
|
|
517
|
+
* res.getvalue(0,0) # '1'
|
|
518
|
+
* res[0] # {"a" => "1", "b" => "2", "c" => "3"}
|
|
519
|
+
* res.tuple_values(0) # ["1", "2", nil]
|
|
520
|
+
* res.tuple(0) # #<PG::Tuple a: "1", b: "2", c: nil>
|
|
521
|
+
* res.values # [["1", "2", nil]]
|
|
522
|
+
* res.field_values(:a) # ["1"]
|
|
523
|
+
* res.column_values(1) # ["2"]
|
|
524
|
+
* res.each.first # {"a" => "1", "b" => "2", "c" => nil}
|
|
525
|
+
* res.each_row.first # ["1", "2", nil]
|
|
526
|
+
* res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
|
|
527
|
+
*
|
|
528
|
+
* Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map which is PG::TypeMapAllStrings by default.
|
|
529
|
+
* Similarly field names can be retrieved either as strings (default) or as symbols which can be switched per #field_name_type= .
|
|
530
|
+
*
|
|
531
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
532
|
+
* res.type_map = PG::TypeMapByColumn.new([PG::TextDecoder::Integer.new]*3)
|
|
533
|
+
* res.field_name_type = :symbol
|
|
534
|
+
* res.fname(2) # :c
|
|
535
|
+
* res.fields # [:a, :b, :c]
|
|
536
|
+
* res.getvalue(0,0) # 1
|
|
537
|
+
* res[0] # {a: 1, b: 2, c: nil}
|
|
538
|
+
* res.tuple_values(0) # [1, 2, nil]
|
|
539
|
+
* res.tuple(0) # #<PG::Tuple a: 1, b: 2, c: nil>
|
|
540
|
+
* res.values # [[1, 2, nil]]
|
|
541
|
+
* res.field_values(:a) # [1]
|
|
542
|
+
* res.column_values(1) # [2]
|
|
543
|
+
* res.each.first # {a: 1, b: 2, c: nil}
|
|
544
|
+
* res.each_row.first # [1, 2, nil]
|
|
545
|
+
* res.each_tuple.first # #<PG::Tuple a: 1, b: 2, c: nil>
|
|
530
546
|
*
|
|
547
|
+
* Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
|
|
548
|
+
* You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
|
|
531
549
|
*/
|
|
532
550
|
|
|
533
551
|
/**************************************************************************
|
|
@@ -549,10 +567,11 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
549
567
|
* * +PGRES_FATAL_ERROR+
|
|
550
568
|
* * +PGRES_COPY_BOTH+
|
|
551
569
|
* * +PGRES_SINGLE_TUPLE+
|
|
570
|
+
* * +PGRES_TUPLES_CHUNK+
|
|
552
571
|
* * +PGRES_PIPELINE_SYNC+
|
|
553
572
|
* * +PGRES_PIPELINE_ABORTED+
|
|
554
573
|
*
|
|
555
|
-
* Use
|
|
574
|
+
* Use #res_status or Result.res_status to retrieve the string representation.
|
|
556
575
|
*/
|
|
557
576
|
static VALUE
|
|
558
577
|
pgresult_result_status(VALUE self)
|
|
@@ -564,7 +583,7 @@ pgresult_result_status(VALUE self)
|
|
|
564
583
|
* call-seq:
|
|
565
584
|
* PG::Result.res_status( status ) -> String
|
|
566
585
|
*
|
|
567
|
-
* Returns the string representation of
|
|
586
|
+
* Returns the string representation of #result_status.
|
|
568
587
|
*
|
|
569
588
|
*/
|
|
570
589
|
static VALUE
|
|
@@ -578,7 +597,7 @@ pgresult_s_res_status(VALUE self, VALUE status)
|
|
|
578
597
|
* res.res_status -> String
|
|
579
598
|
* res.res_status( status ) -> String
|
|
580
599
|
*
|
|
581
|
-
* Returns the string representation of the status of the result or of the provided
|
|
600
|
+
* Returns the string representation of the status of the result or of the provided #result_status.
|
|
582
601
|
*
|
|
583
602
|
*/
|
|
584
603
|
static VALUE
|
|
@@ -613,14 +632,12 @@ pgresult_error_message(VALUE self)
|
|
|
613
632
|
return ret;
|
|
614
633
|
}
|
|
615
634
|
|
|
616
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
617
635
|
/*
|
|
618
636
|
* call-seq:
|
|
619
637
|
* res.verbose_error_message( verbosity, show_context ) -> String
|
|
620
638
|
*
|
|
621
|
-
* Returns a reformatted version of the error message associated with
|
|
639
|
+
* Returns a reformatted version of the error message associated with the PG::Result object.
|
|
622
640
|
*
|
|
623
|
-
* Available since PostgreSQL-9.6
|
|
624
641
|
*/
|
|
625
642
|
static VALUE
|
|
626
643
|
pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
@@ -639,7 +656,6 @@ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
|
639
656
|
|
|
640
657
|
return ret;
|
|
641
658
|
}
|
|
642
|
-
#endif
|
|
643
659
|
|
|
644
660
|
/*
|
|
645
661
|
* call-seq:
|
|
@@ -708,6 +724,10 @@ pgresult_error_field(VALUE self, VALUE field)
|
|
|
708
724
|
* res.ntuples() -> Integer
|
|
709
725
|
*
|
|
710
726
|
* Returns the number of tuples in the query result.
|
|
727
|
+
*
|
|
728
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
729
|
+
* res.ntuples # 1
|
|
730
|
+
* res.num_tuples # 1
|
|
711
731
|
*/
|
|
712
732
|
static VALUE
|
|
713
733
|
pgresult_ntuples(VALUE self)
|
|
@@ -726,6 +746,9 @@ pgresult_ntuples_for_enum(VALUE self, VALUE args, VALUE eobj)
|
|
|
726
746
|
* res.nfields() -> Integer
|
|
727
747
|
*
|
|
728
748
|
* Returns the number of columns in the query result.
|
|
749
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
750
|
+
* res.nfields # 3
|
|
751
|
+
* res.num_fields # 3
|
|
729
752
|
*/
|
|
730
753
|
static VALUE
|
|
731
754
|
pgresult_nfields(VALUE self)
|
|
@@ -737,9 +760,9 @@ pgresult_nfields(VALUE self)
|
|
|
737
760
|
* call-seq:
|
|
738
761
|
* res.binary_tuples() -> Integer
|
|
739
762
|
*
|
|
740
|
-
* Returns 1 if the
|
|
763
|
+
* Returns 1 if the PG::Result contains binary data and 0 if it contains text data.
|
|
741
764
|
*
|
|
742
|
-
* This function is deprecated (except for its use in connection with COPY), because it is possible for a single
|
|
765
|
+
* This function is deprecated (except for its use in connection with COPY), because it is possible for a single PG::Result to contain text data in some columns and binary data in others.
|
|
743
766
|
* Result#fformat is preferred. binary_tuples returns 1 only if all columns of the result are binary (format 1).
|
|
744
767
|
*/
|
|
745
768
|
static VALUE
|
|
@@ -755,6 +778,8 @@ pgresult_binary_tuples(VALUE self)
|
|
|
755
778
|
* Returns the name of the column corresponding to _index_.
|
|
756
779
|
* Depending on #field_name_type= it's a String or Symbol.
|
|
757
780
|
*
|
|
781
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
782
|
+
* res.fname(2) # "c"
|
|
758
783
|
*/
|
|
759
784
|
static VALUE
|
|
760
785
|
pgresult_fname(VALUE self, VALUE index)
|
|
@@ -1125,6 +1150,9 @@ pgresult_oid_value(VALUE self)
|
|
|
1125
1150
|
* res[ n ] -> Hash
|
|
1126
1151
|
*
|
|
1127
1152
|
* Returns tuple _n_ as a hash.
|
|
1153
|
+
*
|
|
1154
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1155
|
+
* res[0] # {"a" => "1", "b" => "2", "c" => "3"}
|
|
1128
1156
|
*/
|
|
1129
1157
|
static VALUE
|
|
1130
1158
|
pgresult_aref(VALUE self, VALUE index)
|
|
@@ -1141,16 +1169,11 @@ pgresult_aref(VALUE self, VALUE index)
|
|
|
1141
1169
|
if ( tuple_num < 0 || tuple_num >= num_tuples )
|
|
1142
1170
|
rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
|
|
1143
1171
|
|
|
1144
|
-
|
|
1145
|
-
* This is somewhat faster than populating an empty Hash object. */
|
|
1146
|
-
tuple = NIL_P(this->tuple_hash) ? rb_hash_new() : this->tuple_hash;
|
|
1172
|
+
tuple = rb_hash_new_capa(this->nfields);
|
|
1147
1173
|
for ( field_num = 0; field_num < this->nfields; field_num++ ) {
|
|
1148
1174
|
VALUE val = this->p_typemap->funcs.typecast_result_value(this->p_typemap, self, tuple_num, field_num);
|
|
1149
1175
|
rb_hash_aset( tuple, this->fnames[field_num], val );
|
|
1150
1176
|
}
|
|
1151
|
-
/* Store a copy of the filled hash for use at the next row. */
|
|
1152
|
-
if( num_tuples > 10 )
|
|
1153
|
-
RB_OBJ_WRITE(self, &this->tuple_hash, rb_hash_dup(tuple));
|
|
1154
1177
|
|
|
1155
1178
|
return tuple;
|
|
1156
1179
|
}
|
|
@@ -1159,7 +1182,10 @@ pgresult_aref(VALUE self, VALUE index)
|
|
|
1159
1182
|
* call-seq:
|
|
1160
1183
|
* res.each_row { |row| ... }
|
|
1161
1184
|
*
|
|
1162
|
-
* Yields
|
|
1185
|
+
* Yields an Array object for each row in the result.
|
|
1186
|
+
*
|
|
1187
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1188
|
+
* res.each_row.first # ["1", "2", nil]
|
|
1163
1189
|
*/
|
|
1164
1190
|
static VALUE
|
|
1165
1191
|
pgresult_each_row(VALUE self)
|
|
@@ -1194,6 +1220,9 @@ pgresult_each_row(VALUE self)
|
|
|
1194
1220
|
* res.values -> Array
|
|
1195
1221
|
*
|
|
1196
1222
|
* Returns all tuples as an array of arrays.
|
|
1223
|
+
*
|
|
1224
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1225
|
+
* res.values # [["1", "2", nil]]
|
|
1197
1226
|
*/
|
|
1198
1227
|
static VALUE
|
|
1199
1228
|
pgresult_values(VALUE self)
|
|
@@ -1243,12 +1272,13 @@ make_column_result_array( VALUE self, int col )
|
|
|
1243
1272
|
|
|
1244
1273
|
|
|
1245
1274
|
/*
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1275
|
+
* call-seq:
|
|
1276
|
+
* res.column_values( n ) -> array
|
|
1248
1277
|
*
|
|
1249
|
-
*
|
|
1250
|
-
* tuple in the result.
|
|
1278
|
+
* Returns an Array of the values from the nth column of each tuple in the result.
|
|
1251
1279
|
*
|
|
1280
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1281
|
+
* res.column_values(1) # ["2"]
|
|
1252
1282
|
*/
|
|
1253
1283
|
static VALUE
|
|
1254
1284
|
pgresult_column_values(VALUE self, VALUE index)
|
|
@@ -1259,11 +1289,13 @@ pgresult_column_values(VALUE self, VALUE index)
|
|
|
1259
1289
|
|
|
1260
1290
|
|
|
1261
1291
|
/*
|
|
1262
|
-
*
|
|
1292
|
+
* call-seq:
|
|
1263
1293
|
* res.field_values( field ) -> array
|
|
1264
1294
|
*
|
|
1265
|
-
*
|
|
1295
|
+
* Returns an Array of the values from the given _field_ of each tuple in the result.
|
|
1266
1296
|
*
|
|
1297
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1298
|
+
* res.field_values(:a) # ["1"]
|
|
1267
1299
|
*/
|
|
1268
1300
|
static VALUE
|
|
1269
1301
|
pgresult_field_values( VALUE self, VALUE field )
|
|
@@ -1284,11 +1316,13 @@ pgresult_field_values( VALUE self, VALUE field )
|
|
|
1284
1316
|
|
|
1285
1317
|
|
|
1286
1318
|
/*
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1319
|
+
* call-seq:
|
|
1320
|
+
* res.tuple_values( n ) -> array
|
|
1289
1321
|
*
|
|
1290
|
-
*
|
|
1322
|
+
* Returns an Array of the field values from the nth row of the result.
|
|
1291
1323
|
*
|
|
1324
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1325
|
+
* res.tuple_values(0) # ["1", "2", nil]
|
|
1292
1326
|
*/
|
|
1293
1327
|
static VALUE
|
|
1294
1328
|
pgresult_tuple_values(VALUE self, VALUE index)
|
|
@@ -1323,11 +1357,12 @@ static void ensure_init_for_tuple(VALUE self)
|
|
|
1323
1357
|
|
|
1324
1358
|
if( this->field_map == Qnil ){
|
|
1325
1359
|
int i;
|
|
1326
|
-
VALUE field_map
|
|
1360
|
+
VALUE field_map;
|
|
1327
1361
|
|
|
1328
1362
|
if( this->nfields == -1 )
|
|
1329
1363
|
pgresult_init_fnames( self );
|
|
1330
1364
|
|
|
1365
|
+
field_map = rb_hash_new_capa(this->nfields);
|
|
1331
1366
|
for( i = 0; i < this->nfields; i++ ){
|
|
1332
1367
|
rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
|
|
1333
1368
|
}
|
|
@@ -1337,11 +1372,13 @@ static void ensure_init_for_tuple(VALUE self)
|
|
|
1337
1372
|
}
|
|
1338
1373
|
|
|
1339
1374
|
/*
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1375
|
+
* call-seq:
|
|
1376
|
+
* res.tuple( n ) -> PG::Tuple
|
|
1342
1377
|
*
|
|
1343
|
-
*
|
|
1378
|
+
* Returns a PG::Tuple from the nth row of the result.
|
|
1344
1379
|
*
|
|
1380
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1381
|
+
* res.tuple(0) # #<PG::Tuple a: "1", b: "2", c: nil>
|
|
1345
1382
|
*/
|
|
1346
1383
|
static VALUE
|
|
1347
1384
|
pgresult_tuple(VALUE self, VALUE index)
|
|
@@ -1366,7 +1403,10 @@ pgresult_tuple(VALUE self, VALUE index)
|
|
|
1366
1403
|
* call-seq:
|
|
1367
1404
|
* res.each{ |tuple| ... }
|
|
1368
1405
|
*
|
|
1369
|
-
*
|
|
1406
|
+
* Yields a Hash object for each row in the result.
|
|
1407
|
+
*
|
|
1408
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1409
|
+
* res.each.first # {"a" => "1", "b" => "2", "c" => nil}
|
|
1370
1410
|
*/
|
|
1371
1411
|
static VALUE
|
|
1372
1412
|
pgresult_each(VALUE self)
|
|
@@ -1384,11 +1424,40 @@ pgresult_each(VALUE self)
|
|
|
1384
1424
|
return self;
|
|
1385
1425
|
}
|
|
1386
1426
|
|
|
1427
|
+
/*
|
|
1428
|
+
* call-seq:
|
|
1429
|
+
* res.each_tuple{ |tuple| ... }
|
|
1430
|
+
*
|
|
1431
|
+
* Yields a PG::Tuple object for each row in the result.
|
|
1432
|
+
*
|
|
1433
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1434
|
+
* res.each_tuple.first # #<PG::Tuple a: "1", b: "2", c: nil>
|
|
1435
|
+
*/
|
|
1436
|
+
static VALUE
|
|
1437
|
+
pgresult_each_tuple(VALUE self)
|
|
1438
|
+
{
|
|
1439
|
+
PGresult *result;
|
|
1440
|
+
int tuple_num;
|
|
1441
|
+
|
|
1442
|
+
RETURN_SIZED_ENUMERATOR(self, 0, NULL, pgresult_ntuples_for_enum);
|
|
1443
|
+
|
|
1444
|
+
result = pgresult_get(self);
|
|
1445
|
+
|
|
1446
|
+
for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
|
|
1447
|
+
VALUE tuple = pgresult_tuple(self, INT2FIX(tuple_num));
|
|
1448
|
+
rb_yield( tuple );
|
|
1449
|
+
}
|
|
1450
|
+
return self;
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1387
1453
|
/*
|
|
1388
1454
|
* call-seq:
|
|
1389
1455
|
* res.fields() -> Array
|
|
1390
1456
|
*
|
|
1391
1457
|
* Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
|
|
1458
|
+
*
|
|
1459
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
|
1460
|
+
* res.fields # ["a", "b", "c"]
|
|
1392
1461
|
*/
|
|
1393
1462
|
static VALUE
|
|
1394
1463
|
pgresult_fields(VALUE self)
|
|
@@ -1405,7 +1474,7 @@ pgresult_fields(VALUE self)
|
|
|
1405
1474
|
* call-seq:
|
|
1406
1475
|
* res.type_map = typemap
|
|
1407
1476
|
*
|
|
1408
|
-
* Set the TypeMap that is used for type casts of result values to ruby objects.
|
|
1477
|
+
* Set the PG::TypeMap that is used for type casts of result values to ruby objects.
|
|
1409
1478
|
*
|
|
1410
1479
|
* All value retrieval methods will respect the type map and will do the
|
|
1411
1480
|
* type casts from PostgreSQL's wire format to Ruby objects on the fly,
|
|
@@ -1413,6 +1482,7 @@ pgresult_fields(VALUE self)
|
|
|
1413
1482
|
*
|
|
1414
1483
|
* +typemap+ must be a kind of PG::TypeMap .
|
|
1415
1484
|
*
|
|
1485
|
+
* See also #map_types! and PG::BasicTypeMapForResults
|
|
1416
1486
|
*/
|
|
1417
1487
|
static VALUE
|
|
1418
1488
|
pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
@@ -1435,7 +1505,8 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
|
1435
1505
|
* call-seq:
|
|
1436
1506
|
* res.type_map -> value
|
|
1437
1507
|
*
|
|
1438
|
-
* Returns the TypeMap that is currently set for type casts of result values to ruby objects.
|
|
1508
|
+
* Returns the PG::TypeMap that is currently set for type casts of result values to ruby objects.
|
|
1509
|
+
* The default is retrieved from PG::Connection#type_map_for_results , which defaults to PG::TypeMapAllStrings .
|
|
1439
1510
|
*
|
|
1440
1511
|
*/
|
|
1441
1512
|
static VALUE
|
|
@@ -1528,6 +1599,9 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
|
|
|
1528
1599
|
return self;
|
|
1529
1600
|
rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
|
|
1530
1601
|
case PGRES_SINGLE_TUPLE:
|
|
1602
|
+
#ifdef LIBPQ_HAS_CHUNK_MODE
|
|
1603
|
+
case PGRES_TUPLES_CHUNK:
|
|
1604
|
+
#endif
|
|
1531
1605
|
break;
|
|
1532
1606
|
default:
|
|
1533
1607
|
pg_result_check( self );
|
|
@@ -1543,12 +1617,12 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
|
|
|
1543
1617
|
pgresult_clear( this );
|
|
1544
1618
|
}
|
|
1545
1619
|
|
|
1546
|
-
if(
|
|
1620
|
+
if( PQisBusy(pgconn) ){
|
|
1547
1621
|
/* wait for input (without blocking) before reading each result */
|
|
1548
1622
|
pgconn_block( 0, NULL, this->connection );
|
|
1549
1623
|
}
|
|
1550
1624
|
|
|
1551
|
-
pgresult =
|
|
1625
|
+
pgresult = PQgetResult(pgconn);
|
|
1552
1626
|
if( pgresult == NULL )
|
|
1553
1627
|
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
|
|
1554
1628
|
|
|
@@ -1572,8 +1646,8 @@ pgresult_stream_any(VALUE self, int (*yielder)(VALUE, int, int, void*), void* da
|
|
|
1572
1646
|
* wrapping each row into a dedicated result object, it delivers data in nearly
|
|
1573
1647
|
* the same speed as with ordinary results.
|
|
1574
1648
|
*
|
|
1575
|
-
* The base result must be in status PGRES_SINGLE_TUPLE
|
|
1576
|
-
* It iterates over all tuples until the status changes to PGRES_TUPLES_OK
|
|
1649
|
+
* The base result must be in status +PGRES_SINGLE_TUPLE+ or +PGRES_TUPLES_CHUNK+.
|
|
1650
|
+
* It iterates over all tuples until the status changes to +PGRES_TUPLES_OK+.
|
|
1577
1651
|
* A PG::Error is raised for any errors from the server.
|
|
1578
1652
|
*
|
|
1579
1653
|
* Row description data does not change while the iteration. All value retrieval
|
|
@@ -1638,7 +1712,6 @@ pgresult_stream_each_tuple(VALUE self)
|
|
|
1638
1712
|
* It can be set to one of:
|
|
1639
1713
|
* * +:string+ to use String based field names
|
|
1640
1714
|
* * +:symbol+ to use Symbol based field names
|
|
1641
|
-
* * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
|
|
1642
1715
|
*
|
|
1643
1716
|
* The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
|
|
1644
1717
|
*
|
|
@@ -1661,7 +1734,6 @@ pgresult_field_name_type_set(VALUE self, VALUE sym)
|
|
|
1661
1734
|
|
|
1662
1735
|
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
|
1663
1736
|
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
|
1664
|
-
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
|
1665
1737
|
else if ( sym == sym_string );
|
|
1666
1738
|
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
|
1667
1739
|
|
|
@@ -1682,8 +1754,6 @@ pgresult_field_name_type_get(VALUE self)
|
|
|
1682
1754
|
t_pg_result *this = pgresult_get_this(self);
|
|
1683
1755
|
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
|
1684
1756
|
return sym_symbol;
|
|
1685
|
-
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
|
1686
|
-
return sym_static_symbol;
|
|
1687
1757
|
} else {
|
|
1688
1758
|
return sym_string;
|
|
1689
1759
|
}
|
|
@@ -1694,7 +1764,6 @@ init_pg_result(void)
|
|
|
1694
1764
|
{
|
|
1695
1765
|
sym_string = ID2SYM(rb_intern("string"));
|
|
1696
1766
|
sym_symbol = ID2SYM(rb_intern("symbol"));
|
|
1697
|
-
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
|
1698
1767
|
|
|
1699
1768
|
rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
|
|
1700
1769
|
rb_undef_alloc_func(rb_cPGresult);
|
|
@@ -1707,10 +1776,8 @@ init_pg_result(void)
|
|
|
1707
1776
|
rb_define_singleton_method(rb_cPGresult, "res_status", pgresult_s_res_status, 1);
|
|
1708
1777
|
rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
|
|
1709
1778
|
rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
|
|
1710
|
-
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
1711
1779
|
rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
|
|
1712
1780
|
rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
|
|
1713
|
-
#endif
|
|
1714
1781
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
|
1715
1782
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
|
1716
1783
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
|
@@ -1745,6 +1812,7 @@ init_pg_result(void)
|
|
|
1745
1812
|
rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
|
|
1746
1813
|
rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
|
|
1747
1814
|
rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
|
|
1815
|
+
rb_define_method(rb_cPGresult, "each_tuple", pgresult_each_tuple, 0);
|
|
1748
1816
|
rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
|
|
1749
1817
|
rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
|
|
1750
1818
|
rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
|
data/ext/pg_text_decoder.c
CHANGED
|
@@ -579,7 +579,7 @@ pg_text_dec_from_base64(t_pg_coder *conv, const char *val, int len, int tuple, i
|
|
|
579
579
|
/* create a buffer of the expected decoded length */
|
|
580
580
|
VALUE out_value = rb_str_new(NULL, BASE64_DECODED_SIZE(len));
|
|
581
581
|
|
|
582
|
-
decoded_len =
|
|
582
|
+
decoded_len = rbpg_base64_decode( RSTRING_PTR(out_value), val, len );
|
|
583
583
|
rb_str_set_len(out_value, decoded_len);
|
|
584
584
|
|
|
585
585
|
/* Is it a pure String conversion? Then we can directly send out_value to the user. */
|
|
@@ -942,8 +942,8 @@ static VALUE
|
|
|
942
942
|
init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
|
|
943
943
|
{
|
|
944
944
|
rb_require("ipaddr");
|
|
945
|
+
rb_gc_register_address(&s_IPAddr);
|
|
945
946
|
s_IPAddr = rb_funcall(rb_cObject, rb_intern("const_get"), 1, rb_str_new2("IPAddr"));
|
|
946
|
-
rb_global_variable(&s_IPAddr);
|
|
947
947
|
s_ivar_family = rb_intern("@family");
|
|
948
948
|
s_ivar_addr = rb_intern("@addr");
|
|
949
949
|
s_ivar_mask_addr = rb_intern("@mask_addr");
|
|
@@ -953,10 +953,10 @@ init_pg_text_decoder_inet(VALUE rb_mPG_TextDecoder)
|
|
|
953
953
|
|
|
954
954
|
use_ipaddr_alloc = RTEST(rb_eval_string("IPAddr.new.instance_variables.sort == [:@addr, :@family, :@mask_addr]"));
|
|
955
955
|
|
|
956
|
+
rb_gc_register_address(&s_vmasks4);
|
|
957
|
+
rb_gc_register_address(&s_vmasks6);
|
|
956
958
|
s_vmasks4 = rb_eval_string("a = [0]*33; a[0] = 0; a[32] = 0xffffffff; 31.downto(1){|i| a[i] = a[i+1] - (1 << (31 - i))}; a.freeze");
|
|
957
|
-
rb_global_variable(&s_vmasks4);
|
|
958
959
|
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");
|
|
959
|
-
rb_global_variable(&s_vmasks6);
|
|
960
960
|
|
|
961
961
|
/* dummy = rb_define_class_under( rb_mPG_TextDecoder, "Inet", rb_cPG_SimpleDecoder ); */
|
|
962
962
|
pg_define_coder( "Inet", pg_text_dec_inet, rb_cPG_SimpleDecoder, rb_mPG_TextDecoder);
|
|
@@ -973,12 +973,12 @@ init_pg_text_decoder(void)
|
|
|
973
973
|
s_id_utc = rb_intern("utc");
|
|
974
974
|
s_id_getlocal = rb_intern("getlocal");
|
|
975
975
|
|
|
976
|
+
rb_gc_register_address(&s_nan);
|
|
977
|
+
rb_gc_register_address(&s_pos_inf);
|
|
978
|
+
rb_gc_register_address(&s_neg_inf);
|
|
976
979
|
s_nan = rb_eval_string("0.0/0.0");
|
|
977
|
-
rb_global_variable(&s_nan);
|
|
978
980
|
s_pos_inf = rb_eval_string("1.0/0.0");
|
|
979
|
-
rb_global_variable(&s_pos_inf);
|
|
980
981
|
s_neg_inf = rb_eval_string("-1.0/0.0");
|
|
981
|
-
rb_global_variable(&s_neg_inf);
|
|
982
982
|
|
|
983
983
|
/* This module encapsulates all decoder classes with text input format */
|
|
984
984
|
rb_mPG_TextDecoder = rb_define_module_under( rb_mPG, "TextDecoder" );
|