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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +1573 -2
  5. data/History.rdoc +3 -11
  6. data/Manifest.txt +24 -0
  7. data/README.rdoc +51 -4
  8. data/Rakefile +20 -14
  9. data/Rakefile.cross +39 -32
  10. data/ext/extconf.rb +27 -26
  11. data/ext/pg.c +75 -21
  12. data/ext/pg.h +194 -6
  13. data/ext/pg_binary_decoder.c +160 -0
  14. data/ext/pg_binary_encoder.c +160 -0
  15. data/ext/pg_coder.c +454 -0
  16. data/ext/pg_connection.c +815 -518
  17. data/ext/pg_copy_coder.c +557 -0
  18. data/ext/pg_result.c +258 -103
  19. data/ext/pg_text_decoder.c +424 -0
  20. data/ext/pg_text_encoder.c +608 -0
  21. data/ext/pg_type_map.c +113 -0
  22. data/ext/pg_type_map_all_strings.c +113 -0
  23. data/ext/pg_type_map_by_column.c +254 -0
  24. data/ext/pg_type_map_by_mri_type.c +266 -0
  25. data/ext/pg_type_map_by_oid.c +341 -0
  26. data/ext/util.c +121 -0
  27. data/ext/util.h +63 -0
  28. data/lib/pg.rb +11 -1
  29. data/lib/pg/basic_type_mapping.rb +377 -0
  30. data/lib/pg/coder.rb +74 -0
  31. data/lib/pg/connection.rb +38 -5
  32. data/lib/pg/result.rb +13 -3
  33. data/lib/pg/text_decoder.rb +42 -0
  34. data/lib/pg/text_encoder.rb +27 -0
  35. data/lib/pg/type_map_by_column.rb +15 -0
  36. data/spec/helpers.rb +9 -1
  37. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  38. data/spec/pg/connection_spec.rb +232 -13
  39. data/spec/pg/result_spec.rb +52 -0
  40. data/spec/pg/type_map_by_column_spec.rb +135 -0
  41. data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
  42. data/spec/pg/type_map_by_oid_spec.rb +133 -0
  43. data/spec/pg/type_map_spec.rb +39 -0
  44. data/spec/pg/type_spec.rb +620 -0
  45. metadata +40 -4
  46. 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 738d4c4125a1 2014/07/23 18:10:52 mina $
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( PGresult * );
13
- static PGresult* pgresult_get( VALUE );
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
- PGconn *conn = pg_get_pgconn( rb_pgconn );
27
- VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, pgresult_gc_free, result);
28
- #ifdef M17N_SUPPORTED
29
- rb_encoding *enc = pg_conn_enc_get( conn );
30
- ENCODING_SET( val, rb_enc_to_index(enc) );
31
- #endif
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
- rb_iv_set( val, "@connection", rb_pgconn );
51
+ this->typemap = typemap;
52
+ }
53
+
54
+ return self;
55
+ }
34
56
 
35
- return val;
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
- VALUE rb_pgconn = rb_iv_get( self, "@connection" );
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
- Data_Get_Struct(self, PGresult, result);
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(result))
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(result) );
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
- #ifdef M17N_SUPPORTED
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( result, PG_DIAG_SQLSTATE );
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", rb_pgconn );
96
- rb_iv_set( exception, "@result", result ? self : Qnil );
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
- PQclear(pgresult_get(self));
120
- DATA_PTR(self) = NULL;
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( PGresult *result )
196
+ pgresult_gc_free( t_pg_result *this )
135
197
  {
136
- if(result != NULL)
137
- PQclear(result);
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 for the result object
205
+ * Fetch the PG::Result object data pointer and check it's
206
+ * PGresult data pointer for sanity.
142
207
  */
143
- static PGresult*
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
- PGresult *result;
147
- Data_Get_Struct(self, PGresult, result);
148
- if (result == NULL) rb_raise(rb_ePGerror, "result has been cleared");
149
- return result;
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
- ASSOCIATE_INDEX(ret, self);
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
- ASSOCIATE_INDEX(ret, self);
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
- ASSOCIATE_INDEX( ret, self );
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
- ASSOCIATE_INDEX(fname, self);
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), StringValuePtr(name));
462
+ n = PQfnumber(pgresult_get(self), StringValueCStr(name));
365
463
  if (n == -1) {
366
- rb_raise(rb_eArgError,"Unknown field: %s", StringValuePtr(name));
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
- PGresult *result;
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
- result = pgresult_get(self);
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(result)) {
633
+ if(j < 0 || j >= PQnfields(this->pgresult)) {
561
634
  rb_raise(rb_eArgError,"invalid field number %d", j);
562
635
  }
563
- return pgresult_value(self, result, i, j);
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
- ASSOCIATE_INDEX(ret, self);
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
- PGresult *result = pgresult_get(self);
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(result) )
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(result); field_num++ ) {
721
- fname = rb_tainted_str_new2( PQfname(result,field_num) );
722
- ASSOCIATE_INDEX(fname, self);
723
- rb_hash_aset( tuple, fname, pgresult_value(self, result, tuple_num, field_num) );
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
- PGresult* result = (PGresult*) pgresult_get(self);
810
+ t_pg_result *this = pgresult_get_this_safe(self);
738
811
  int row;
739
812
  int field;
740
- int num_rows = PQntuples(result);
741
- int num_fields = PQnfields(result);
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
- rb_ary_store( new_row, field, pgresult_value(self, result, row, field) );
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
- PGresult *result = pgresult_get( self );
765
- int rows = PQntuples( result );
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(result) )
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 = rb_tainted_str_new( PQgetvalue(result, i, col),
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 = StringValuePtr( field );
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
- ASSOCIATE_INDEX(val, self);
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