pg 0.18.0.pre20140820094244 → 0.18.0.pre20141017155815
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.tar.gz.sig +0 -0
- data/ChangeLog +1573 -2
- data/History.rdoc +3 -11
- data/Manifest.txt +24 -0
- data/README.rdoc +51 -4
- data/Rakefile +20 -14
- data/Rakefile.cross +39 -32
- data/ext/extconf.rb +27 -26
- data/ext/pg.c +75 -21
- data/ext/pg.h +194 -6
- data/ext/pg_binary_decoder.c +160 -0
- data/ext/pg_binary_encoder.c +160 -0
- data/ext/pg_coder.c +454 -0
- data/ext/pg_connection.c +815 -518
- data/ext/pg_copy_coder.c +557 -0
- data/ext/pg_result.c +258 -103
- data/ext/pg_text_decoder.c +424 -0
- data/ext/pg_text_encoder.c +608 -0
- data/ext/pg_type_map.c +113 -0
- data/ext/pg_type_map_all_strings.c +113 -0
- data/ext/pg_type_map_by_column.c +254 -0
- data/ext/pg_type_map_by_mri_type.c +266 -0
- data/ext/pg_type_map_by_oid.c +341 -0
- data/ext/util.c +121 -0
- data/ext/util.h +63 -0
- data/lib/pg.rb +11 -1
- data/lib/pg/basic_type_mapping.rb +377 -0
- data/lib/pg/coder.rb +74 -0
- data/lib/pg/connection.rb +38 -5
- data/lib/pg/result.rb +13 -3
- data/lib/pg/text_decoder.rb +42 -0
- data/lib/pg/text_encoder.rb +27 -0
- data/lib/pg/type_map_by_column.rb +15 -0
- data/spec/helpers.rb +9 -1
- data/spec/pg/basic_type_mapping_spec.rb +251 -0
- data/spec/pg/connection_spec.rb +232 -13
- data/spec/pg/result_spec.rb +52 -0
- data/spec/pg/type_map_by_column_spec.rb +135 -0
- data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
- data/spec/pg/type_map_by_oid_spec.rb +133 -0
- data/spec/pg/type_map_spec.rb +39 -0
- data/spec/pg/type_spec.rb +620 -0
- metadata +40 -4
- metadata.gz.sig +0 -0
data/ext/pg_result.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_result.c - PG::Result class extension
|
3
|
-
* $Id: pg_result.c,v
|
3
|
+
* $Id: pg_result.c,v f0b7f99b1dd5 2014/10/06 08:31:02 kanis $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -9,8 +9,12 @@
|
|
9
9
|
|
10
10
|
VALUE rb_cPGresult;
|
11
11
|
|
12
|
-
static void pgresult_gc_free(
|
13
|
-
static
|
12
|
+
static void pgresult_gc_free( t_pg_result * );
|
13
|
+
static VALUE pgresult_type_map_set( VALUE, VALUE );
|
14
|
+
static VALUE pgresult_s_allocate( VALUE );
|
15
|
+
static t_pg_result *pgresult_get_this( VALUE );
|
16
|
+
static t_pg_result *pgresult_get_this_safe( VALUE );
|
17
|
+
|
14
18
|
|
15
19
|
|
16
20
|
/*
|
@@ -23,16 +27,40 @@ static PGresult* pgresult_get( VALUE );
|
|
23
27
|
VALUE
|
24
28
|
pg_new_result(PGresult *result, VALUE rb_pgconn)
|
25
29
|
{
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
30
|
+
VALUE self = pgresult_s_allocate( rb_cPGresult );
|
31
|
+
t_pg_result *this = pgresult_get_this(self);
|
32
|
+
t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
|
33
|
+
|
34
|
+
PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
|
35
|
+
|
36
|
+
this->pgresult = result;
|
37
|
+
this->connection = rb_pgconn;
|
38
|
+
if( result ){
|
39
|
+
VALUE typemap = p_conn->type_map_for_results;
|
40
|
+
|
41
|
+
if( !NIL_P(typemap) ){
|
42
|
+
t_typemap *p_typemap;
|
43
|
+
|
44
|
+
/* Type check is done when assigned to PG::Connection. */
|
45
|
+
p_typemap = DATA_PTR(typemap);
|
46
|
+
|
47
|
+
typemap = p_typemap->fit_to_result( typemap, self );
|
48
|
+
this->p_typemap = DATA_PTR( typemap );
|
49
|
+
}
|
32
50
|
|
33
|
-
|
51
|
+
this->typemap = typemap;
|
52
|
+
}
|
53
|
+
|
54
|
+
return self;
|
55
|
+
}
|
34
56
|
|
35
|
-
|
57
|
+
VALUE
|
58
|
+
pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
|
59
|
+
{
|
60
|
+
VALUE self = pg_new_result(result, rb_pgconn);
|
61
|
+
t_pg_result *this = pgresult_get_this(self);
|
62
|
+
this->autoclear = 1;
|
63
|
+
return self;
|
36
64
|
}
|
37
65
|
|
38
66
|
/*
|
@@ -44,24 +72,18 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
|
|
44
72
|
VALUE
|
45
73
|
pg_result_check( VALUE self )
|
46
74
|
{
|
75
|
+
t_pg_result *this = pgresult_get_this(self);
|
47
76
|
VALUE error, exception, klass;
|
48
|
-
|
49
|
-
PGconn *conn = pg_get_pgconn(rb_pgconn);
|
50
|
-
PGresult *result;
|
51
|
-
#ifdef M17N_SUPPORTED
|
52
|
-
rb_encoding *enc = pg_conn_enc_get( conn );
|
53
|
-
#endif
|
77
|
+
PGconn *conn = pg_get_pgconn(this->connection);
|
54
78
|
char * sqlstate;
|
55
79
|
|
56
|
-
|
57
|
-
|
58
|
-
if(result == NULL)
|
80
|
+
if(this->pgresult == NULL)
|
59
81
|
{
|
60
82
|
error = rb_str_new2( PQerrorMessage(conn) );
|
61
83
|
}
|
62
84
|
else
|
63
85
|
{
|
64
|
-
switch (PQresultStatus(
|
86
|
+
switch (PQresultStatus(this->pgresult))
|
65
87
|
{
|
66
88
|
case PGRES_TUPLES_OK:
|
67
89
|
case PGRES_COPY_OUT:
|
@@ -78,22 +100,20 @@ pg_result_check( VALUE self )
|
|
78
100
|
case PGRES_BAD_RESPONSE:
|
79
101
|
case PGRES_FATAL_ERROR:
|
80
102
|
case PGRES_NONFATAL_ERROR:
|
81
|
-
error = rb_str_new2( PQresultErrorMessage(
|
103
|
+
error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
|
82
104
|
break;
|
83
105
|
default:
|
84
106
|
error = rb_str_new2( "internal error : unknown result status." );
|
85
107
|
}
|
86
108
|
}
|
87
109
|
|
88
|
-
|
89
|
-
rb_enc_set_index( error, rb_enc_to_index(enc) );
|
90
|
-
#endif
|
110
|
+
PG_ENCODING_SET_NOCHECK( error, ENCODING_GET(self) );
|
91
111
|
|
92
|
-
sqlstate = PQresultErrorField(
|
112
|
+
sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
|
93
113
|
klass = lookup_error_class( sqlstate );
|
94
114
|
exception = rb_exc_new3( klass, error );
|
95
|
-
rb_iv_set( exception, "@connection",
|
96
|
-
rb_iv_set( exception, "@result",
|
115
|
+
rb_iv_set( exception, "@connection", this->connection );
|
116
|
+
rb_iv_set( exception, "@result", this->pgresult ? self : Qnil );
|
97
117
|
rb_exc_raise( exception );
|
98
118
|
|
99
119
|
/* Not reached */
|
@@ -112,41 +132,119 @@ pg_result_check( VALUE self )
|
|
112
132
|
* res.clear() -> nil
|
113
133
|
*
|
114
134
|
* Clears the PG::Result object as the result of the query.
|
135
|
+
*
|
136
|
+
* If PG::Result#autoclear? is true then the result is marked as cleared
|
137
|
+
* and the underlying C struct will be cleared automatically by libpq.
|
138
|
+
*
|
115
139
|
*/
|
116
140
|
VALUE
|
117
141
|
pg_result_clear(VALUE self)
|
118
142
|
{
|
119
|
-
|
120
|
-
|
143
|
+
t_pg_result *this = pgresult_get_this(self);
|
144
|
+
if( !this->autoclear )
|
145
|
+
PQclear(pgresult_get(self));
|
146
|
+
this->pgresult = NULL;
|
121
147
|
return Qnil;
|
122
148
|
}
|
123
149
|
|
150
|
+
/*
|
151
|
+
* call-seq:
|
152
|
+
* res.cleared? -> boolean
|
153
|
+
*
|
154
|
+
* Returns +true+ if the backend result memory has been free'd.
|
155
|
+
*/
|
156
|
+
VALUE
|
157
|
+
pgresult_cleared_p( VALUE self )
|
158
|
+
{
|
159
|
+
t_pg_result *this = pgresult_get_this(self);
|
160
|
+
return this->pgresult ? Qfalse : Qtrue;
|
161
|
+
}
|
124
162
|
|
163
|
+
/*
|
164
|
+
* call-seq:
|
165
|
+
* res.autoclose? -> boolean
|
166
|
+
*
|
167
|
+
* Returns +true+ if the underlying C struct will be cleared automatically by libpq.
|
168
|
+
* Elsewise the result is cleared by PG::Result#clear or by the GC when it's no longer in use.
|
169
|
+
*
|
170
|
+
*/
|
171
|
+
VALUE
|
172
|
+
pgresult_autoclear_p( VALUE self )
|
173
|
+
{
|
174
|
+
t_pg_result *this = pgresult_get_this(self);
|
175
|
+
return this->autoclear ? Qtrue : Qfalse;
|
176
|
+
}
|
125
177
|
|
126
178
|
/*
|
127
179
|
* DATA pointer functions
|
128
180
|
*/
|
129
181
|
|
182
|
+
/*
|
183
|
+
* GC Mark function
|
184
|
+
*/
|
185
|
+
static void
|
186
|
+
pgresult_gc_mark( t_pg_result *this )
|
187
|
+
{
|
188
|
+
rb_gc_mark( this->connection );
|
189
|
+
rb_gc_mark( this->typemap );
|
190
|
+
}
|
191
|
+
|
130
192
|
/*
|
131
193
|
* GC Free function
|
132
194
|
*/
|
133
195
|
static void
|
134
|
-
pgresult_gc_free(
|
196
|
+
pgresult_gc_free( t_pg_result *this )
|
135
197
|
{
|
136
|
-
if(
|
137
|
-
PQclear(
|
198
|
+
if(this->pgresult != NULL && !this->autoclear)
|
199
|
+
PQclear(this->pgresult);
|
200
|
+
|
201
|
+
xfree(this);
|
138
202
|
}
|
139
203
|
|
140
204
|
/*
|
141
|
-
* Fetch the data pointer
|
205
|
+
* Fetch the PG::Result object data pointer and check it's
|
206
|
+
* PGresult data pointer for sanity.
|
142
207
|
*/
|
143
|
-
static
|
208
|
+
static t_pg_result *
|
209
|
+
pgresult_get_this_safe( VALUE self )
|
210
|
+
{
|
211
|
+
t_pg_result *this = pgresult_get_this(self);
|
212
|
+
|
213
|
+
if (this->pgresult == NULL) rb_raise(rb_ePGerror, "result has been cleared");
|
214
|
+
return this;
|
215
|
+
}
|
216
|
+
|
217
|
+
/*
|
218
|
+
* Fetch the PGresult pointer for the result object and check validity
|
219
|
+
*/
|
220
|
+
PGresult*
|
144
221
|
pgresult_get(VALUE self)
|
145
222
|
{
|
146
|
-
|
147
|
-
|
148
|
-
if (
|
149
|
-
return
|
223
|
+
t_pg_result *this = pgresult_get_this(self);
|
224
|
+
|
225
|
+
if (this->pgresult == NULL) rb_raise(rb_ePGerror, "result has been cleared");
|
226
|
+
return this->pgresult;
|
227
|
+
}
|
228
|
+
|
229
|
+
/*
|
230
|
+
* Document-method: allocate
|
231
|
+
*
|
232
|
+
* call-seq:
|
233
|
+
* PG::Result.allocate -> result
|
234
|
+
*/
|
235
|
+
static VALUE
|
236
|
+
pgresult_s_allocate( VALUE klass )
|
237
|
+
{
|
238
|
+
t_pg_result *this;
|
239
|
+
VALUE self = Data_Make_Struct( klass, t_pg_result, pgresult_gc_mark, pgresult_gc_free, this );
|
240
|
+
|
241
|
+
this->pgresult = NULL;
|
242
|
+
this->connection = Qnil;
|
243
|
+
this->typemap = Qnil;
|
244
|
+
this->p_typemap = DATA_PTR( pg_default_typemap );
|
245
|
+
this->autoclear = 0;
|
246
|
+
|
247
|
+
return self;
|
150
248
|
}
|
151
249
|
|
152
250
|
|
@@ -205,7 +303,7 @@ static VALUE
|
|
205
303
|
pgresult_res_status(VALUE self, VALUE status)
|
206
304
|
{
|
207
305
|
VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
|
208
|
-
|
306
|
+
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
|
209
307
|
return ret;
|
210
308
|
}
|
211
309
|
|
@@ -219,7 +317,7 @@ static VALUE
|
|
219
317
|
pgresult_error_message(VALUE self)
|
220
318
|
{
|
221
319
|
VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
|
222
|
-
|
320
|
+
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
|
223
321
|
return ret;
|
224
322
|
}
|
225
323
|
|
@@ -279,7 +377,7 @@ pgresult_error_field(VALUE self, VALUE field)
|
|
279
377
|
|
280
378
|
if ( fieldstr ) {
|
281
379
|
ret = rb_tainted_str_new2( fieldstr );
|
282
|
-
|
380
|
+
PG_ENCODING_SET_NOCHECK( ret, ENCODING_GET(self ));
|
283
381
|
}
|
284
382
|
|
285
383
|
return ret;
|
@@ -327,7 +425,7 @@ pgresult_fname(VALUE self, VALUE index)
|
|
327
425
|
rb_raise(rb_eArgError,"invalid field number %d", i);
|
328
426
|
}
|
329
427
|
fname = rb_tainted_str_new2(PQfname(result, i));
|
330
|
-
|
428
|
+
PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
|
331
429
|
return fname;
|
332
430
|
}
|
333
431
|
|
@@ -361,9 +459,9 @@ pgresult_fnumber(VALUE self, VALUE name)
|
|
361
459
|
|
362
460
|
Check_Type(name, T_STRING);
|
363
461
|
|
364
|
-
n = PQfnumber(pgresult_get(self),
|
462
|
+
n = PQfnumber(pgresult_get(self), StringValueCStr(name));
|
365
463
|
if (n == -1) {
|
366
|
-
rb_raise(rb_eArgError,"Unknown field: %s",
|
464
|
+
rb_raise(rb_eArgError,"Unknown field: %s", StringValueCStr(name));
|
367
465
|
}
|
368
466
|
return INT2FIX(n);
|
369
467
|
}
|
@@ -515,30 +613,6 @@ pgresult_fsize(VALUE self, VALUE index)
|
|
515
613
|
}
|
516
614
|
|
517
615
|
|
518
|
-
static VALUE
|
519
|
-
pgresult_value(VALUE self, PGresult *result, int tuple_num, int field_num)
|
520
|
-
{
|
521
|
-
VALUE val;
|
522
|
-
if ( PQgetisnull(result, tuple_num, field_num) ) {
|
523
|
-
return Qnil;
|
524
|
-
}
|
525
|
-
else {
|
526
|
-
val = rb_tainted_str_new( PQgetvalue(result, tuple_num, field_num ),
|
527
|
-
PQgetlength(result, tuple_num, field_num) );
|
528
|
-
|
529
|
-
#ifdef M17N_SUPPORTED
|
530
|
-
/* associate client encoding for text format only */
|
531
|
-
if ( 0 == PQfformat(result, field_num) ) {
|
532
|
-
ASSOCIATE_INDEX( val, self );
|
533
|
-
} else {
|
534
|
-
rb_enc_associate( val, rb_ascii8bit_encoding() );
|
535
|
-
}
|
536
|
-
#endif
|
537
|
-
|
538
|
-
return val;
|
539
|
-
}
|
540
|
-
}
|
541
|
-
|
542
616
|
/*
|
543
617
|
* call-seq:
|
544
618
|
* res.getvalue( tup_num, field_num )
|
@@ -549,18 +623,17 @@ pgresult_value(VALUE self, PGresult *result, int tuple_num, int field_num)
|
|
549
623
|
static VALUE
|
550
624
|
pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
|
551
625
|
{
|
552
|
-
|
626
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
553
627
|
int i = NUM2INT(tup_num);
|
554
628
|
int j = NUM2INT(field_num);
|
555
629
|
|
556
|
-
|
557
|
-
if(i < 0 || i >= PQntuples(result)) {
|
630
|
+
if(i < 0 || i >= PQntuples(this->pgresult)) {
|
558
631
|
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
559
632
|
}
|
560
|
-
if(j < 0 || j >= PQnfields(
|
633
|
+
if(j < 0 || j >= PQnfields(this->pgresult)) {
|
561
634
|
rb_raise(rb_eArgError,"invalid field number %d", j);
|
562
635
|
}
|
563
|
-
return
|
636
|
+
return this->p_typemap->typecast_result_value(self, i, j);
|
564
637
|
}
|
565
638
|
|
566
639
|
/*
|
@@ -653,7 +726,7 @@ static VALUE
|
|
653
726
|
pgresult_cmd_status(VALUE self)
|
654
727
|
{
|
655
728
|
VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
|
656
|
-
|
729
|
+
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
|
657
730
|
return ret;
|
658
731
|
}
|
659
732
|
|
@@ -707,20 +780,20 @@ pgresult_oid_value(VALUE self)
|
|
707
780
|
static VALUE
|
708
781
|
pgresult_aref(VALUE self, VALUE index)
|
709
782
|
{
|
710
|
-
|
783
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
711
784
|
int tuple_num = NUM2INT(index);
|
712
785
|
int field_num;
|
713
786
|
VALUE fname;
|
714
787
|
VALUE tuple;
|
715
788
|
|
716
|
-
if ( tuple_num < 0 || tuple_num >= PQntuples(
|
789
|
+
if ( tuple_num < 0 || tuple_num >= PQntuples(this->pgresult) )
|
717
790
|
rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
|
718
791
|
|
719
792
|
tuple = rb_hash_new();
|
720
|
-
for ( field_num = 0; field_num < PQnfields(
|
721
|
-
fname = rb_tainted_str_new2( PQfname(
|
722
|
-
|
723
|
-
rb_hash_aset( tuple, fname,
|
793
|
+
for ( field_num = 0; field_num < PQnfields(this->pgresult); field_num++ ) {
|
794
|
+
fname = rb_tainted_str_new2( PQfname(this->pgresult,field_num) );
|
795
|
+
PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
|
796
|
+
rb_hash_aset( tuple, fname, this->p_typemap->typecast_result_value(self, tuple_num, field_num) );
|
724
797
|
}
|
725
798
|
return tuple;
|
726
799
|
}
|
@@ -734,18 +807,18 @@ pgresult_aref(VALUE self, VALUE index)
|
|
734
807
|
static VALUE
|
735
808
|
pgresult_each_row(VALUE self)
|
736
809
|
{
|
737
|
-
|
810
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
738
811
|
int row;
|
739
812
|
int field;
|
740
|
-
int num_rows = PQntuples(
|
741
|
-
int num_fields = PQnfields(
|
813
|
+
int num_rows = PQntuples(this->pgresult);
|
814
|
+
int num_fields = PQnfields(this->pgresult);
|
742
815
|
|
743
816
|
for ( row = 0; row < num_rows; row++ ) {
|
744
817
|
VALUE new_row = rb_ary_new2(num_fields);
|
745
818
|
|
746
819
|
/* populate the row */
|
747
820
|
for ( field = 0; field < num_fields; field++ ) {
|
748
|
-
|
821
|
+
rb_ary_store( new_row, field, this->p_typemap->typecast_result_value(self, row, field) );
|
749
822
|
}
|
750
823
|
rb_yield( new_row );
|
751
824
|
}
|
@@ -753,6 +826,34 @@ pgresult_each_row(VALUE self)
|
|
753
826
|
return Qnil;
|
754
827
|
}
|
755
828
|
|
829
|
+
/*
|
830
|
+
* call-seq:
|
831
|
+
* res.values -> Array
|
832
|
+
*
|
833
|
+
* Returns all tuples as an array of arrays.
|
834
|
+
*/
|
835
|
+
static VALUE
|
836
|
+
pgresult_values(VALUE self)
|
837
|
+
{
|
838
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
839
|
+
int row;
|
840
|
+
int field;
|
841
|
+
int num_rows = PQntuples(this->pgresult);
|
842
|
+
int num_fields = PQnfields(this->pgresult);
|
843
|
+
VALUE results = rb_ary_new2( num_rows );
|
844
|
+
|
845
|
+
for ( row = 0; row < num_rows; row++ ) {
|
846
|
+
VALUE new_row = rb_ary_new2(num_fields);
|
847
|
+
|
848
|
+
/* populate the row */
|
849
|
+
for ( field = 0; field < num_fields; field++ ) {
|
850
|
+
rb_ary_store( new_row, field, this->p_typemap->typecast_result_value(self, row, field) );
|
851
|
+
}
|
852
|
+
rb_ary_store( results, row, new_row );
|
853
|
+
}
|
854
|
+
|
855
|
+
return results;
|
856
|
+
}
|
756
857
|
|
757
858
|
/*
|
758
859
|
* Make a Ruby array out of the encoded values from the specified
|
@@ -761,28 +862,16 @@ pgresult_each_row(VALUE self)
|
|
761
862
|
static VALUE
|
762
863
|
make_column_result_array( VALUE self, int col )
|
763
864
|
{
|
764
|
-
|
765
|
-
int rows = PQntuples(
|
865
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
866
|
+
int rows = PQntuples( this->pgresult );
|
766
867
|
int i;
|
767
|
-
VALUE val = Qnil;
|
768
868
|
VALUE results = rb_ary_new2( rows );
|
769
869
|
|
770
|
-
if ( col >= PQnfields(
|
870
|
+
if ( col >= PQnfields(this->pgresult) )
|
771
871
|
rb_raise( rb_eIndexError, "no column %d in result", col );
|
772
872
|
|
773
873
|
for ( i=0; i < rows; i++ ) {
|
774
|
-
val =
|
775
|
-
PQgetlength(result, i, col) );
|
776
|
-
|
777
|
-
#ifdef M17N_SUPPORTED
|
778
|
-
/* associate client encoding for text format only */
|
779
|
-
if ( 0 == PQfformat(result, col) ) {
|
780
|
-
ASSOCIATE_INDEX( val, self );
|
781
|
-
} else {
|
782
|
-
rb_enc_associate( val, rb_ascii8bit_encoding() );
|
783
|
-
}
|
784
|
-
#endif
|
785
|
-
|
874
|
+
VALUE val = this->p_typemap->typecast_result_value(self, i, col);
|
786
875
|
rb_ary_store( results, i, val );
|
787
876
|
}
|
788
877
|
|
@@ -817,7 +906,7 @@ static VALUE
|
|
817
906
|
pgresult_field_values( VALUE self, VALUE field )
|
818
907
|
{
|
819
908
|
PGresult *result = pgresult_get( self );
|
820
|
-
const char *fieldname =
|
909
|
+
const char *fieldname = StringValueCStr( field );
|
821
910
|
int fnum = PQfnumber( result, fieldname );
|
822
911
|
|
823
912
|
if ( fnum < 0 )
|
@@ -861,18 +950,78 @@ pgresult_fields(VALUE self)
|
|
861
950
|
|
862
951
|
for ( i = 0; i < n; i++ ) {
|
863
952
|
VALUE val = rb_tainted_str_new2(PQfname(result, i));
|
864
|
-
|
953
|
+
PG_ENCODING_SET_NOCHECK(val, ENCODING_GET(self));
|
865
954
|
rb_ary_store( fields, i, val );
|
866
955
|
}
|
867
956
|
|
868
957
|
return fields;
|
869
958
|
}
|
870
959
|
|
960
|
+
/*
|
961
|
+
* call-seq:
|
962
|
+
* res.type_map = typemap
|
963
|
+
*
|
964
|
+
* Set the TypeMap that is used for type casts of result values to ruby objects.
|
965
|
+
*
|
966
|
+
* All value retrieval methods will respect the type map and will do the
|
967
|
+
* type casts from PostgreSQL's wire format to Ruby objects on the fly,
|
968
|
+
* according to the rules and decoders defined in the given typemap.
|
969
|
+
*
|
970
|
+
* +typemap+ can be:
|
971
|
+
* * a kind of PG::TypeMap
|
972
|
+
* * +nil+ - to type cast all result values to String.
|
973
|
+
*
|
974
|
+
*/
|
975
|
+
static VALUE
|
976
|
+
pgresult_type_map_set(VALUE self, VALUE typemap)
|
977
|
+
{
|
978
|
+
t_pg_result *this = pgresult_get_this(self);
|
979
|
+
|
980
|
+
if( NIL_P(typemap) ){
|
981
|
+
this->p_typemap = DATA_PTR( pg_default_typemap );
|
982
|
+
} else {
|
983
|
+
t_typemap *p_typemap;
|
984
|
+
|
985
|
+
if ( !rb_obj_is_kind_of(typemap, rb_cTypeMap) ) {
|
986
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected kind of PG::TypeMap)",
|
987
|
+
rb_obj_classname( typemap ) );
|
988
|
+
}
|
989
|
+
Data_Get_Struct(typemap, t_typemap, p_typemap);
|
990
|
+
|
991
|
+
typemap = p_typemap->fit_to_result( typemap, self );
|
992
|
+
this->p_typemap = DATA_PTR( typemap );
|
993
|
+
}
|
994
|
+
|
995
|
+
this->typemap = typemap;
|
996
|
+
|
997
|
+
return typemap;
|
998
|
+
}
|
999
|
+
|
1000
|
+
/*
|
1001
|
+
* call-seq:
|
1002
|
+
* res.type_map -> value
|
1003
|
+
*
|
1004
|
+
* Returns the TypeMap that is currently set for type casts of result values to ruby objects.
|
1005
|
+
*
|
1006
|
+
* Returns either:
|
1007
|
+
* * a kind of PG::TypeMap or
|
1008
|
+
* * +nil+ - when no type map is set.
|
1009
|
+
*
|
1010
|
+
*/
|
1011
|
+
static VALUE
|
1012
|
+
pgresult_type_map_get(VALUE self)
|
1013
|
+
{
|
1014
|
+
t_pg_result *this = pgresult_get_this(self);
|
1015
|
+
|
1016
|
+
return this->typemap;
|
1017
|
+
}
|
1018
|
+
|
871
1019
|
|
872
1020
|
void
|
873
1021
|
init_pg_result()
|
874
1022
|
{
|
875
1023
|
rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
|
1024
|
+
rb_define_alloc_func( rb_cPGresult, pgresult_s_allocate );
|
876
1025
|
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
877
1026
|
rb_include_module(rb_cPGresult, rb_mPGconstants);
|
878
1027
|
|
@@ -913,8 +1062,14 @@ init_pg_result()
|
|
913
1062
|
rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
|
914
1063
|
rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
|
915
1064
|
rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
|
1065
|
+
rb_define_method(rb_cPGresult, "values", pgresult_values, 0);
|
916
1066
|
rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
|
917
1067
|
rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
|
1068
|
+
rb_define_method(rb_cPGresult, "cleared?", pgresult_cleared_p, 0);
|
1069
|
+
rb_define_method(rb_cPGresult, "autoclear?", pgresult_autoclear_p, 0);
|
1070
|
+
|
1071
|
+
rb_define_method(rb_cPGresult, "type_map=", pgresult_type_map_set, 1);
|
1072
|
+
rb_define_method(rb_cPGresult, "type_map", pgresult_type_map_get, 0);
|
918
1073
|
}
|
919
1074
|
|
920
1075
|
|