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

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 (52) 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/1.9/pg_ext.so +0 -0
  29. data/lib/2.0/pg_ext.so +0 -0
  30. data/lib/2.1/pg_ext.so +0 -0
  31. data/lib/i386-mingw32/libpq.dll +0 -0
  32. data/lib/pg.rb +11 -1
  33. data/lib/pg/basic_type_mapping.rb +377 -0
  34. data/lib/pg/coder.rb +74 -0
  35. data/lib/pg/connection.rb +43 -1
  36. data/lib/pg/result.rb +13 -3
  37. data/lib/pg/text_decoder.rb +42 -0
  38. data/lib/pg/text_encoder.rb +27 -0
  39. data/lib/pg/type_map_by_column.rb +15 -0
  40. data/spec/{lib/helpers.rb → helpers.rb} +95 -35
  41. data/spec/pg/basic_type_mapping_spec.rb +251 -0
  42. data/spec/pg/connection_spec.rb +416 -214
  43. data/spec/pg/result_spec.rb +146 -116
  44. data/spec/pg/type_map_by_column_spec.rb +135 -0
  45. data/spec/pg/type_map_by_mri_type_spec.rb +122 -0
  46. data/spec/pg/type_map_by_oid_spec.rb +133 -0
  47. data/spec/pg/type_map_spec.rb +39 -0
  48. data/spec/pg/type_spec.rb +649 -0
  49. data/spec/pg_spec.rb +10 -18
  50. metadata +130 -52
  51. metadata.gz.sig +0 -0
  52. data/lib/1.8/pg_ext.so +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