pg 0.17.1-x64-mingw32 → 0.18.0.pre20141017160319-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +1885 -169
  5. data/History.rdoc +6 -0
  6. data/Manifest.txt +25 -1
  7. data/README.rdoc +47 -0
  8. data/Rakefile +21 -12
  9. data/Rakefile.cross +39 -33
  10. data/ext/extconf.rb +27 -26
  11. data/ext/pg.c +73 -19
  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 +473 -0
  16. data/ext/pg_connection.c +872 -534
  17. data/ext/pg_copy_coder.c +557 -0
  18. data/ext/pg_result.c +266 -111
  19. data/ext/pg_text_decoder.c +424 -0
  20. data/ext/pg_text_encoder.c +631 -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 +149 -0
  27. data/ext/util.h +65 -0
  28. data/lib/2.0/pg_ext.so +0 -0
  29. data/lib/2.1/pg_ext.so +0 -0
  30. data/lib/pg.rb +11 -1
  31. data/lib/pg/basic_type_mapping.rb +377 -0
  32. data/lib/pg/coder.rb +74 -0
  33. data/lib/pg/connection.rb +43 -1
  34. data/lib/pg/result.rb +13 -3
  35. data/lib/pg/text_decoder.rb +42 -0
  36. data/lib/pg/text_encoder.rb +27 -0
  37. data/lib/pg/type_map_by_column.rb +15 -0
  38. data/lib/x64-mingw32/libpq.dll +0 -0
  39. data/spec/{lib/helpers.rb → helpers.rb} +95 -35
  40. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  41. data/spec/pg/connection_spec.rb +416 -214
  42. data/spec/pg/result_spec.rb +146 -116
  43. data/spec/pg/type_map_by_column_spec.rb +135 -0
  44. data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
  45. data/spec/pg/type_map_by_oid_spec.rb +133 -0
  46. data/spec/pg/type_map_spec.rb +39 -0
  47. data/spec/pg/type_spec.rb +649 -0
  48. data/spec/pg_spec.rb +10 -18
  49. metadata +129 -50
  50. metadata.gz.sig +0 -0
@@ -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;
@@ -299,7 +397,7 @@ pgresult_ntuples(VALUE self)
299
397
 
300
398
  /*
301
399
  * call-seq:
302
- * res.nfields() -> Fixnum
400
+ * res.nfields() -> Integer
303
401
  *
304
402
  * Returns the number of columns in the query result.
305
403
  */
@@ -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,16 +459,16 @@ 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
  }
370
468
 
371
469
  /*
372
470
  * call-seq:
373
- * res.ftable( column_number ) -> Fixnum
471
+ * res.ftable( column_number ) -> Integer
374
472
  *
375
473
  * Returns the Oid of the table from which the column _column_number_
376
474
  * was fetched.
@@ -389,7 +487,7 @@ pgresult_ftable(VALUE self, VALUE column_number)
389
487
  rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
390
488
 
391
489
  n = PQftable(pgresult, col_number);
392
- return INT2FIX(n);
490
+ return UINT2NUM(n);
393
491
  }
394
492
 
395
493
  /*
@@ -440,7 +538,7 @@ pgresult_fformat(VALUE self, VALUE column_number)
440
538
 
441
539
  /*
442
540
  * call-seq:
443
- * res.ftype( column_number )
541
+ * res.ftype( column_number ) -> Integer
444
542
  *
445
543
  * Returns the data type associated with _column_number_.
446
544
  *
@@ -464,7 +562,7 @@ pgresult_ftype(VALUE self, VALUE index)
464
562
  if (i < 0 || i >= PQnfields(result)) {
465
563
  rb_raise(rb_eArgError, "invalid field number %d", i);
466
564
  }
467
- return INT2NUM(PQftype(result, i));
565
+ return UINT2NUM(PQftype(result, i));
468
566
  }
469
567
 
470
568
  /*
@@ -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
  /*
@@ -640,7 +713,7 @@ pgresult_paramtype(VALUE self, VALUE param_number)
640
713
  PGresult *result;
641
714
 
642
715
  result = pgresult_get(self);
643
- return INT2FIX(PQparamtype(result,NUM2INT(param_number)));
716
+ return UINT2NUM(PQparamtype(result,NUM2INT(param_number)));
644
717
  }
645
718
 
646
719
  /*
@@ -653,13 +726,13 @@ 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
 
660
733
  /*
661
734
  * call-seq:
662
- * res.cmd_tuples() -> Fixnum
735
+ * res.cmd_tuples() -> Integer
663
736
  *
664
737
  * Returns the number of tuples (rows) affected by the SQL command.
665
738
  *
@@ -681,7 +754,7 @@ pgresult_cmd_tuples(VALUE self)
681
754
 
682
755
  /*
683
756
  * call-seq:
684
- * res.oid_value() -> Fixnum
757
+ * res.oid_value() -> Integer
685
758
  *
686
759
  * Returns the +oid+ of the inserted row if applicable,
687
760
  * otherwise +nil+.
@@ -693,7 +766,7 @@ pgresult_oid_value(VALUE self)
693
766
  if (n == InvalidOid)
694
767
  return Qnil;
695
768
  else
696
- return INT2FIX(n);
769
+ return UINT2NUM(n);
697
770
  }
698
771
 
699
772
  /* Utility methods not in libpq */
@@ -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