pg 1.1.4-x86-mingw32 → 1.2.0-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 (61) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +0 -6595
  5. data/History.rdoc +63 -0
  6. data/Manifest.txt +3 -2
  7. data/README-Windows.rdoc +4 -4
  8. data/README.ja.rdoc +1 -2
  9. data/README.rdoc +43 -8
  10. data/Rakefile +3 -3
  11. data/Rakefile.cross +6 -3
  12. data/ext/errorcodes.def +64 -0
  13. data/ext/errorcodes.txt +18 -2
  14. data/ext/extconf.rb +6 -6
  15. data/ext/pg.c +132 -95
  16. data/ext/pg.h +20 -18
  17. data/ext/pg_binary_decoder.c +9 -9
  18. data/ext/pg_binary_encoder.c +13 -12
  19. data/ext/pg_coder.c +5 -5
  20. data/ext/pg_connection.c +388 -298
  21. data/ext/pg_copy_coder.c +5 -3
  22. data/ext/pg_record_coder.c +490 -0
  23. data/ext/pg_result.c +269 -123
  24. data/ext/pg_text_decoder.c +14 -8
  25. data/ext/pg_text_encoder.c +180 -48
  26. data/ext/pg_tuple.c +14 -6
  27. data/ext/pg_type_map.c +1 -1
  28. data/ext/pg_type_map_all_strings.c +4 -4
  29. data/ext/pg_type_map_by_class.c +4 -3
  30. data/ext/pg_type_map_by_column.c +7 -6
  31. data/ext/pg_type_map_by_mri_type.c +1 -1
  32. data/ext/pg_type_map_by_oid.c +3 -2
  33. data/ext/pg_type_map_in_ruby.c +1 -1
  34. data/ext/{util.c → pg_util.c} +5 -5
  35. data/ext/{util.h → pg_util.h} +0 -0
  36. data/lib/2.2/pg_ext.so +0 -0
  37. data/lib/2.3/pg_ext.so +0 -0
  38. data/lib/2.4/pg_ext.so +0 -0
  39. data/lib/2.5/pg_ext.so +0 -0
  40. data/lib/2.6/pg_ext.so +0 -0
  41. data/lib/libpq.dll +0 -0
  42. data/lib/pg.rb +2 -3
  43. data/lib/pg/basic_type_mapping.rb +79 -16
  44. data/lib/pg/binary_decoder.rb +1 -0
  45. data/lib/pg/coder.rb +22 -1
  46. data/lib/pg/connection.rb +2 -2
  47. data/lib/pg/constants.rb +1 -0
  48. data/lib/pg/exceptions.rb +1 -0
  49. data/lib/pg/result.rb +13 -1
  50. data/lib/pg/text_decoder.rb +2 -3
  51. data/lib/pg/text_encoder.rb +8 -18
  52. data/lib/pg/type_map_by_column.rb +2 -1
  53. data/spec/helpers.rb +10 -8
  54. data/spec/pg/basic_type_mapping_spec.rb +150 -13
  55. data/spec/pg/connection_spec.rb +89 -50
  56. data/spec/pg/result_spec.rb +193 -3
  57. data/spec/pg/tuple_spec.rb +55 -2
  58. data/spec/pg/type_map_by_column_spec.rb +5 -1
  59. data/spec/pg/type_spec.rb +180 -6
  60. metadata +27 -25
  61. metadata.gz.sig +0 -0
@@ -6,15 +6,22 @@
6
6
 
7
7
  #include "pg.h"
8
8
 
9
-
10
9
  VALUE rb_cPGresult;
10
+ static VALUE sym_symbol, sym_string, sym_static_symbol;
11
11
 
12
- static void pgresult_gc_free( t_pg_result * );
13
12
  static VALUE pgresult_type_map_set( VALUE, VALUE );
14
- static VALUE pgresult_s_allocate( VALUE );
15
13
  static t_pg_result *pgresult_get_this( VALUE );
16
14
  static t_pg_result *pgresult_get_this_safe( VALUE );
17
15
 
16
+ #if defined(HAVE_PQRESULTMEMORYSIZE)
17
+
18
+ static ssize_t
19
+ pgresult_approx_size(const PGresult *result)
20
+ {
21
+ return PQresultMemorySize(result);
22
+ }
23
+
24
+ #else
18
25
 
19
26
  #define PGRESULT_DATA_BLOCKSIZE 2048
20
27
  typedef struct pgresAttValue
@@ -44,7 +51,7 @@ count_leading_zero_bits(unsigned int x)
44
51
  }
45
52
 
46
53
  static ssize_t
47
- pgresult_approx_size(PGresult *result)
54
+ pgresult_approx_size(const PGresult *result)
48
55
  {
49
56
  int num_fields = PQnfields(result);
50
57
  ssize_t size = 0;
@@ -94,7 +101,29 @@ pgresult_approx_size(PGresult *result)
94
101
 
95
102
  return size;
96
103
  }
104
+ #endif
97
105
 
106
+ /*
107
+ * GC Mark function
108
+ */
109
+ static void
110
+ pgresult_gc_mark( t_pg_result *this )
111
+ {
112
+ int i;
113
+
114
+ rb_gc_mark( this->connection );
115
+ rb_gc_mark( this->typemap );
116
+ rb_gc_mark( this->tuple_hash );
117
+ rb_gc_mark( this->field_map );
118
+
119
+ for( i=0; i < this->nfields; i++ ){
120
+ rb_gc_mark( this->fnames[i] );
121
+ }
122
+ }
123
+
124
+ /*
125
+ * GC Free function
126
+ */
98
127
  static void
99
128
  pgresult_clear( t_pg_result *this )
100
129
  {
@@ -104,15 +133,41 @@ pgresult_clear( t_pg_result *this )
104
133
  rb_gc_adjust_memory_usage(-this->result_size);
105
134
  #endif
106
135
  }
136
+ this->result_size = 0;
137
+ this->nfields = -1;
107
138
  this->pgresult = NULL;
108
139
  }
109
140
 
141
+ static void
142
+ pgresult_gc_free( t_pg_result *this )
143
+ {
144
+ pgresult_clear( this );
145
+ xfree(this);
146
+ }
147
+
110
148
  static size_t
111
149
  pgresult_memsize( t_pg_result *this )
112
150
  {
151
+ /* Ideally the memory 'this' is pointing to should be taken into account as well.
152
+ * However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
153
+ */
113
154
  return this->result_size;
114
155
  }
115
156
 
157
+ static const rb_data_type_t pgresult_type = {
158
+ "pg",
159
+ {
160
+ (void (*)(void*))pgresult_gc_mark,
161
+ (void (*)(void*))pgresult_gc_free,
162
+ (size_t (*)(const void *))pgresult_memsize,
163
+ },
164
+ 0, 0,
165
+ #ifdef RUBY_TYPED_FREE_IMMEDIATELY
166
+ RUBY_TYPED_FREE_IMMEDIATELY,
167
+ #endif
168
+ };
169
+
170
+
116
171
  /*
117
172
  * Global functions
118
173
  */
@@ -124,12 +179,10 @@ static VALUE
124
179
  pg_new_result2(PGresult *result, VALUE rb_pgconn)
125
180
  {
126
181
  int nfields = result ? PQnfields(result) : 0;
127
- VALUE self = pgresult_s_allocate( rb_cPGresult );
182
+ VALUE self;
128
183
  t_pg_result *this;
129
184
 
130
185
  this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
131
- RTYPEDDATA_DATA(self) = this;
132
-
133
186
  this->pgresult = result;
134
187
  this->connection = rb_pgconn;
135
188
  this->typemap = pg_typemap_all_strings;
@@ -137,18 +190,21 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
137
190
  this->nfields = -1;
138
191
  this->tuple_hash = Qnil;
139
192
  this->field_map = Qnil;
140
-
141
- PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
193
+ this->flags = 0;
194
+ self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
142
195
 
143
196
  if( result ){
144
197
  t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
145
198
  VALUE typemap = p_conn->type_map_for_results;
146
-
147
199
  /* Type check is done when assigned to PG::Connection. */
148
200
  t_typemap *p_typemap = DATA_PTR(typemap);
149
201
 
202
+ this->enc_idx = p_conn->enc_idx;
150
203
  this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
151
204
  this->p_typemap = DATA_PTR( this->typemap );
205
+ this->flags = p_conn->flags;
206
+ } else {
207
+ this->enc_idx = rb_locale_encindex();
152
208
  }
153
209
 
154
210
  return self;
@@ -159,22 +215,38 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
159
215
  {
160
216
  VALUE self = pg_new_result2(result, rb_pgconn);
161
217
  t_pg_result *this = pgresult_get_this(self);
162
- t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
163
218
 
164
219
  this->autoclear = 0;
165
220
 
166
- if( p_conn->guess_result_memsize ){
167
- /* Approximate size of underlying pgresult memory storage and account to ruby GC */
168
- this->result_size = pgresult_approx_size(result);
221
+ /* Estimate size of underlying pgresult memory storage and account to ruby GC.
222
+ * There's no need to adjust the GC for xmalloc'ed memory, but libpq is using libc malloc() ruby doesn't know about.
223
+ */
224
+ /* TODO: If someday most systems provide PQresultMemorySize(), it's questionable to store result_size in t_pg_result in addition to the value already stored in PGresult.
225
+ * For now the memory savings don't justify the ifdefs necessary to support both cases.
226
+ */
227
+ this->result_size = pgresult_approx_size(result);
169
228
 
170
229
  #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
171
- rb_gc_adjust_memory_usage(this->result_size);
230
+ rb_gc_adjust_memory_usage(this->result_size);
172
231
  #endif
173
- }
174
232
 
175
233
  return self;
176
234
  }
177
235
 
236
+ static VALUE
237
+ pg_copy_result(t_pg_result *this)
238
+ {
239
+ int nfields = this->nfields == -1 ? (this->pgresult ? PQnfields(this->pgresult) : 0) : this->nfields;
240
+ size_t len = sizeof(*this) + sizeof(*this->fnames) * nfields;
241
+ t_pg_result *copy;
242
+
243
+ copy = (t_pg_result *)xmalloc(len);
244
+ memcpy(copy, this, len);
245
+ this->result_size = 0;
246
+
247
+ return TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, copy);
248
+ }
249
+
178
250
  VALUE
179
251
  pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
180
252
  {
@@ -229,7 +301,7 @@ pg_result_check( VALUE self )
229
301
  }
230
302
  }
231
303
 
232
- PG_ENCODING_SET_NOCHECK( error, ENCODING_GET(self) );
304
+ PG_ENCODING_SET_NOCHECK( error, this->enc_idx );
233
305
 
234
306
  sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
235
307
  klass = lookup_error_class( sqlstate );
@@ -305,37 +377,6 @@ pgresult_autoclear_p( VALUE self )
305
377
  * DATA pointer functions
306
378
  */
307
379
 
308
- /*
309
- * GC Mark function
310
- */
311
- static void
312
- pgresult_gc_mark( t_pg_result *this )
313
- {
314
- int i;
315
-
316
- if( !this ) return;
317
- rb_gc_mark( this->connection );
318
- rb_gc_mark( this->typemap );
319
- rb_gc_mark( this->tuple_hash );
320
- rb_gc_mark( this->field_map );
321
-
322
- for( i=0; i < this->nfields; i++ ){
323
- rb_gc_mark( this->fnames[i] );
324
- }
325
- }
326
-
327
- /*
328
- * GC Free function
329
- */
330
- static void
331
- pgresult_gc_free( t_pg_result *this )
332
- {
333
- if( !this ) return;
334
- pgresult_clear( this );
335
-
336
- xfree(this);
337
- }
338
-
339
380
  /*
340
381
  * Fetch the PG::Result object data pointer and check it's
341
382
  * PGresult data pointer for sanity.
@@ -365,32 +406,30 @@ pgresult_get(VALUE self)
365
406
  return this->pgresult;
366
407
  }
367
408
 
368
-
369
- static const rb_data_type_t pgresult_type = {
370
- "pg",
371
- {
372
- (void (*)(void*))pgresult_gc_mark,
373
- (void (*)(void*))pgresult_gc_free,
374
- (size_t (*)(const void *))pgresult_memsize,
375
- },
376
- 0, 0,
377
- #ifdef RUBY_TYPED_FREE_IMMEDIATELY
378
- RUBY_TYPED_FREE_IMMEDIATELY,
379
- #endif
380
- };
381
-
382
- /*
383
- * Document-method: allocate
384
- *
385
- * call-seq:
386
- * PG::Result.allocate -> result
387
- */
388
- static VALUE
389
- pgresult_s_allocate( VALUE klass )
409
+ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
390
410
  {
391
- VALUE self = TypedData_Wrap_Struct( klass, &pgresult_type, NULL );
392
-
393
- return self;
411
+ VALUE fname;
412
+ #ifdef TRUFFLERUBY
413
+ if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
414
+ #else
415
+ if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
416
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
417
+ fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
418
+ if( fname == Qnil ){
419
+ fname = rb_str_new2(cstr);
420
+ PG_ENCODING_SET_NOCHECK(fname, enc_idx);
421
+ fname = rb_str_intern(fname);
422
+ }
423
+ } else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
424
+ #endif
425
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
426
+ fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
427
+ } else {
428
+ fname = rb_str_new2(cstr);
429
+ PG_ENCODING_SET_NOCHECK(fname, enc_idx);
430
+ fname = rb_obj_freeze(fname);
431
+ }
432
+ return fname;
394
433
  }
395
434
 
396
435
  static void pgresult_init_fnames(VALUE self)
@@ -402,12 +441,9 @@ static void pgresult_init_fnames(VALUE self)
402
441
  int nfields = PQnfields(this->pgresult);
403
442
 
404
443
  for( i=0; i<nfields; i++ ){
405
- VALUE fname = rb_tainted_str_new2(PQfname(this->pgresult, i));
406
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
407
- this->fnames[i] = rb_obj_freeze(fname);
444
+ char *cfname = PQfname(this->pgresult, i);
445
+ this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
408
446
  this->nfields = i + 1;
409
-
410
- RB_GC_GUARD(fname);
411
447
  }
412
448
  this->nfields = nfields;
413
449
  }
@@ -470,8 +506,9 @@ pgresult_result_status(VALUE self)
470
506
  static VALUE
471
507
  pgresult_res_status(VALUE self, VALUE status)
472
508
  {
473
- VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
474
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
509
+ t_pg_result *this = pgresult_get_this_safe(self);
510
+ VALUE ret = rb_str_new2(PQresStatus(NUM2INT(status)));
511
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
475
512
  return ret;
476
513
  }
477
514
 
@@ -484,10 +521,39 @@ pgresult_res_status(VALUE self, VALUE status)
484
521
  static VALUE
485
522
  pgresult_error_message(VALUE self)
486
523
  {
487
- VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
488
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
524
+ t_pg_result *this = pgresult_get_this_safe(self);
525
+ VALUE ret = rb_str_new2(PQresultErrorMessage(this->pgresult));
526
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
527
+ return ret;
528
+ }
529
+
530
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
531
+ /*
532
+ * call-seq:
533
+ * res.verbose_error_message( verbosity, show_context ) -> String
534
+ *
535
+ * Returns a reformatted version of the error message associated with a PGresult object.
536
+ *
537
+ * Available since PostgreSQL-9.6
538
+ */
539
+ static VALUE
540
+ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
541
+ {
542
+ t_pg_result *this = pgresult_get_this_safe(self);
543
+ VALUE ret;
544
+ char *c_str;
545
+
546
+ c_str = PQresultVerboseErrorMessage(this->pgresult, NUM2INT(verbosity), NUM2INT(show_context));
547
+ if(!c_str)
548
+ rb_raise(rb_eNoMemError, "insufficient memory to format error message");
549
+
550
+ ret = rb_str_new2(c_str);
551
+ PQfreemem(c_str);
552
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
553
+
489
554
  return ret;
490
555
  }
556
+ #endif
491
557
 
492
558
  /*
493
559
  * call-seq:
@@ -538,14 +604,14 @@ pgresult_error_message(VALUE self)
538
604
  static VALUE
539
605
  pgresult_error_field(VALUE self, VALUE field)
540
606
  {
541
- PGresult *result = pgresult_get( self );
607
+ t_pg_result *this = pgresult_get_this_safe(self);
542
608
  int fieldcode = NUM2INT( field );
543
- char * fieldstr = PQresultErrorField( result, fieldcode );
609
+ char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
544
610
  VALUE ret = Qnil;
545
611
 
546
612
  if ( fieldstr ) {
547
- ret = rb_tainted_str_new2( fieldstr );
548
- PG_ENCODING_SET_NOCHECK( ret, ENCODING_GET(self ));
613
+ ret = rb_str_new2( fieldstr );
614
+ PG_ENCODING_SET_NOCHECK( ret, this->enc_idx );
549
615
  }
550
616
 
551
617
  return ret;
@@ -583,24 +649,25 @@ pgresult_nfields(VALUE self)
583
649
 
584
650
  /*
585
651
  * call-seq:
586
- * res.fname( index ) -> String
652
+ * res.fname( index ) -> String or Symbol
587
653
  *
588
654
  * Returns the name of the column corresponding to _index_.
655
+ * Depending on #field_name_type= it's a String or Symbol.
656
+ *
589
657
  */
590
658
  static VALUE
591
659
  pgresult_fname(VALUE self, VALUE index)
592
660
  {
593
- VALUE fname;
594
- PGresult *result = pgresult_get(self);
661
+ t_pg_result *this = pgresult_get_this_safe(self);
595
662
  int i = NUM2INT(index);
663
+ char *cfname;
596
664
 
597
- if (i < 0 || i >= PQnfields(result)) {
665
+ if (i < 0 || i >= PQnfields(this->pgresult)) {
598
666
  rb_raise(rb_eArgError,"invalid field number %d", i);
599
667
  }
600
668
 
601
- fname = rb_tainted_str_new2(PQfname(result, i));
602
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
603
- return rb_obj_freeze(fname);
669
+ cfname = PQfname(this->pgresult, i);
670
+ return pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
604
671
  }
605
672
 
606
673
  /*
@@ -899,8 +966,9 @@ pgresult_paramtype(VALUE self, VALUE param_number)
899
966
  static VALUE
900
967
  pgresult_cmd_status(VALUE self)
901
968
  {
902
- VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
903
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
969
+ t_pg_result *this = pgresult_get_this_safe(self);
970
+ VALUE ret = rb_str_new2(PQcmdStatus(this->pgresult));
971
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
904
972
  return ret;
905
973
  }
906
974
 
@@ -1100,8 +1168,12 @@ static VALUE
1100
1168
  pgresult_field_values( VALUE self, VALUE field )
1101
1169
  {
1102
1170
  PGresult *result = pgresult_get( self );
1103
- const char *fieldname = StringValueCStr( field );
1104
- int fnum = PQfnumber( result, fieldname );
1171
+ const char *fieldname;
1172
+ int fnum;
1173
+
1174
+ if( RB_TYPE_P(field, T_SYMBOL) ) field = rb_sym_to_s( field );
1175
+ fieldname = StringValueCStr( field );
1176
+ fnum = PQfnumber( result, fieldname );
1105
1177
 
1106
1178
  if ( fnum < 0 )
1107
1179
  rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
@@ -1144,6 +1216,25 @@ pgresult_tuple_values(VALUE self, VALUE index)
1144
1216
  }
1145
1217
  }
1146
1218
 
1219
+ static void ensure_init_for_tuple(VALUE self)
1220
+ {
1221
+ t_pg_result *this = pgresult_get_this_safe(self);
1222
+
1223
+ if( this->field_map == Qnil ){
1224
+ int i;
1225
+ VALUE field_map = rb_hash_new();
1226
+
1227
+ if( this->nfields == -1 )
1228
+ pgresult_init_fnames( self );
1229
+
1230
+ for( i = 0; i < this->nfields; i++ ){
1231
+ rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1232
+ }
1233
+ rb_obj_freeze(field_map);
1234
+ this->field_map = field_map;
1235
+ }
1236
+ }
1237
+
1147
1238
  /*
1148
1239
  * call-seq:
1149
1240
  * res.tuple( n ) -> PG::Tuple
@@ -1164,19 +1255,7 @@ pgresult_tuple(VALUE self, VALUE index)
1164
1255
  if ( tuple_num < 0 || tuple_num >= num_tuples )
1165
1256
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1166
1257
 
1167
- if( this->field_map == Qnil ){
1168
- int i;
1169
- VALUE field_map = rb_hash_new();
1170
-
1171
- if( this->nfields == -1 )
1172
- pgresult_init_fnames( self );
1173
-
1174
- for( i = 0; i < this->nfields; i++ ){
1175
- rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1176
- }
1177
- rb_obj_freeze(field_map);
1178
- this->field_map = field_map;
1179
- }
1258
+ ensure_init_for_tuple(self);
1180
1259
 
1181
1260
  return pg_tuple_new(self, tuple_num);
1182
1261
  }
@@ -1208,7 +1287,7 @@ pgresult_each(VALUE self)
1208
1287
  * call-seq:
1209
1288
  * res.fields() -> Array
1210
1289
  *
1211
- * Returns an array of Strings representing the names of the fields in the result.
1290
+ * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
1212
1291
  */
1213
1292
  static VALUE
1214
1293
  pgresult_fields(VALUE self)
@@ -1307,11 +1386,17 @@ yield_tuple(VALUE self, int ntuples, int nfields)
1307
1386
  {
1308
1387
  int tuple_num;
1309
1388
  t_pg_result *this = pgresult_get_this(self);
1310
- VALUE result = pg_new_result(this->pgresult, this->connection);
1389
+ VALUE copy;
1311
1390
  UNUSED(nfields);
1312
1391
 
1392
+ /* make a copy of the base result, that is bound to the PG::Tuple */
1393
+ copy = pg_copy_result(this);
1394
+ /* The copy is now owner of the PGresult and is responsible to PQclear it.
1395
+ * We clear the pgresult here, so that it's not double freed on error within yield. */
1396
+ this->pgresult = NULL;
1397
+
1313
1398
  for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1314
- VALUE tuple = pgresult_tuple(result, INT2FIX(tuple_num));
1399
+ VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
1315
1400
  rb_yield( tuple );
1316
1401
  }
1317
1402
  }
@@ -1392,8 +1477,6 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1392
1477
  * # do something with each received row of the second query
1393
1478
  * end
1394
1479
  * conn.get_result # => nil (no more results)
1395
- *
1396
- * Available since PostgreSQL-9.2
1397
1480
  */
1398
1481
  static VALUE
1399
1482
  pgresult_stream_each(VALUE self)
@@ -1410,8 +1493,6 @@ pgresult_stream_each(VALUE self)
1410
1493
  *
1411
1494
  * This method works equally to #stream_each , but yields an Array of
1412
1495
  * values.
1413
- *
1414
- * Available since PostgreSQL-9.2
1415
1496
  */
1416
1497
  static VALUE
1417
1498
  pgresult_stream_each_row(VALUE self)
@@ -1426,21 +1507,81 @@ pgresult_stream_each_row(VALUE self)
1426
1507
  * Yields each row of the result set in single row mode.
1427
1508
  *
1428
1509
  * This method works equally to #stream_each , but yields a PG::Tuple object.
1429
- *
1430
- * Available since PostgreSQL-9.2
1431
1510
  */
1432
1511
  static VALUE
1433
1512
  pgresult_stream_each_tuple(VALUE self)
1434
1513
  {
1514
+ /* allocate VALUEs that are shared between all streamed tuples */
1515
+ ensure_init_for_tuple(self);
1516
+
1435
1517
  return pgresult_stream_any(self, yield_tuple);
1436
1518
  }
1437
1519
 
1520
+ /*
1521
+ * call-seq:
1522
+ * res.field_name_type = Symbol
1523
+ *
1524
+ * Set type of field names specific to this result.
1525
+ * It can be set to one of:
1526
+ * * +:string+ to use String based field names
1527
+ * * +:symbol+ to use Symbol based field names
1528
+ * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future.
1529
+ *
1530
+ * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1531
+ *
1532
+ * This setting affects several result methods:
1533
+ * * keys of Hash returned by #[] , #each and #stream_each
1534
+ * * #fields
1535
+ * * #fname
1536
+ * * field names used by #tuple and #stream_each_tuple
1537
+ *
1538
+ * The type of field names can only be changed before any of the affected methods have been called.
1539
+ *
1540
+ */
1541
+ static VALUE
1542
+ pgresult_field_name_type_set(VALUE self, VALUE sym)
1543
+ {
1544
+ t_pg_result *this = pgresult_get_this(self);
1545
+ if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
1546
+
1547
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
1548
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
1549
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
1550
+ else if ( sym == sym_string );
1551
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
1552
+
1553
+ return sym;
1554
+ }
1555
+
1556
+ /*
1557
+ * call-seq:
1558
+ * res.field_name_type -> Symbol
1559
+ *
1560
+ * Get type of field names.
1561
+ *
1562
+ * See description at #field_name_type=
1563
+ */
1564
+ static VALUE
1565
+ pgresult_field_name_type_get(VALUE self)
1566
+ {
1567
+ t_pg_result *this = pgresult_get_this(self);
1568
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
1569
+ return sym_symbol;
1570
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
1571
+ return sym_static_symbol;
1572
+ } else {
1573
+ return sym_string;
1574
+ }
1575
+ }
1438
1576
 
1439
1577
  void
1440
1578
  init_pg_result()
1441
1579
  {
1442
- rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1443
- rb_define_alloc_func( rb_cPGresult, pgresult_s_allocate );
1580
+ sym_string = ID2SYM(rb_intern("string"));
1581
+ sym_symbol = ID2SYM(rb_intern("symbol"));
1582
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1583
+
1584
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cData );
1444
1585
  rb_include_module(rb_cPGresult, rb_mEnumerable);
1445
1586
  rb_include_module(rb_cPGresult, rb_mPGconstants);
1446
1587
 
@@ -1449,6 +1590,10 @@ init_pg_result()
1449
1590
  rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
1450
1591
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1451
1592
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1593
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
1594
+ rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
1595
+ rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
1596
+ #endif
1452
1597
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1453
1598
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1454
1599
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
@@ -1496,6 +1641,7 @@ init_pg_result()
1496
1641
  rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1497
1642
  rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1498
1643
  rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
1499
- }
1500
-
1501
1644
 
1645
+ rb_define_method(rb_cPGresult, "field_name_type=", pgresult_field_name_type_set, 1 );
1646
+ rb_define_method(rb_cPGresult, "field_name_type", pgresult_field_name_type_get, 0 );
1647
+ }