pg 1.1.4 → 1.2.3

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 (57) 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 +86 -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 +44 -9
  10. data/Rakefile +8 -6
  11. data/Rakefile.cross +57 -56
  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 +21 -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 +21 -9
  20. data/ext/pg_connection.c +388 -298
  21. data/ext/pg_copy_coder.c +6 -3
  22. data/ext/pg_record_coder.c +491 -0
  23. data/ext/pg_result.c +279 -127
  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 +9 -4
  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/pg.rb +4 -4
  37. data/lib/pg/basic_type_mapping.rb +81 -18
  38. data/lib/pg/binary_decoder.rb +1 -0
  39. data/lib/pg/coder.rb +22 -1
  40. data/lib/pg/connection.rb +2 -2
  41. data/lib/pg/constants.rb +1 -0
  42. data/lib/pg/exceptions.rb +1 -0
  43. data/lib/pg/result.rb +13 -1
  44. data/lib/pg/text_decoder.rb +2 -3
  45. data/lib/pg/text_encoder.rb +8 -18
  46. data/lib/pg/type_map_by_column.rb +2 -1
  47. data/spec/helpers.rb +11 -11
  48. data/spec/pg/basic_type_mapping_spec.rb +140 -18
  49. data/spec/pg/connection_spec.rb +166 -89
  50. data/spec/pg/result_spec.rb +194 -4
  51. data/spec/pg/tuple_spec.rb +55 -2
  52. data/spec/pg/type_map_by_class_spec.rb +1 -1
  53. data/spec/pg/type_map_by_column_spec.rb +5 -1
  54. data/spec/pg/type_map_by_oid_spec.rb +2 -2
  55. data/spec/pg/type_spec.rb +180 -6
  56. metadata +31 -30
  57. 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,46 @@ 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
+ /* Needed by sequel_pg gem, do not delete */
171
+ int pg_get_result_enc_idx(VALUE self)
172
+ {
173
+ return pgresult_get_this(self)->enc_idx;
174
+ }
175
+
116
176
  /*
117
177
  * Global functions
118
178
  */
@@ -124,12 +184,10 @@ static VALUE
124
184
  pg_new_result2(PGresult *result, VALUE rb_pgconn)
125
185
  {
126
186
  int nfields = result ? PQnfields(result) : 0;
127
- VALUE self = pgresult_s_allocate( rb_cPGresult );
187
+ VALUE self;
128
188
  t_pg_result *this;
129
189
 
130
190
  this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
131
- RTYPEDDATA_DATA(self) = this;
132
-
133
191
  this->pgresult = result;
134
192
  this->connection = rb_pgconn;
135
193
  this->typemap = pg_typemap_all_strings;
@@ -137,18 +195,21 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn)
137
195
  this->nfields = -1;
138
196
  this->tuple_hash = Qnil;
139
197
  this->field_map = Qnil;
140
-
141
- PG_ENCODING_SET_NOCHECK(self, ENCODING_GET(rb_pgconn));
198
+ this->flags = 0;
199
+ self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
142
200
 
143
201
  if( result ){
144
202
  t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
145
203
  VALUE typemap = p_conn->type_map_for_results;
146
-
147
204
  /* Type check is done when assigned to PG::Connection. */
148
205
  t_typemap *p_typemap = DATA_PTR(typemap);
149
206
 
207
+ this->enc_idx = p_conn->enc_idx;
150
208
  this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
151
209
  this->p_typemap = DATA_PTR( this->typemap );
210
+ this->flags = p_conn->flags;
211
+ } else {
212
+ this->enc_idx = rb_locale_encindex();
152
213
  }
153
214
 
154
215
  return self;
@@ -159,22 +220,38 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
159
220
  {
160
221
  VALUE self = pg_new_result2(result, rb_pgconn);
161
222
  t_pg_result *this = pgresult_get_this(self);
162
- t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
163
223
 
164
224
  this->autoclear = 0;
165
225
 
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);
226
+ /* Estimate size of underlying pgresult memory storage and account to ruby GC.
227
+ * There's no need to adjust the GC for xmalloc'ed memory, but libpq is using libc malloc() ruby doesn't know about.
228
+ */
229
+ /* 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.
230
+ * For now the memory savings don't justify the ifdefs necessary to support both cases.
231
+ */
232
+ this->result_size = pgresult_approx_size(result);
169
233
 
170
234
  #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
171
- rb_gc_adjust_memory_usage(this->result_size);
235
+ rb_gc_adjust_memory_usage(this->result_size);
172
236
  #endif
173
- }
174
237
 
175
238
  return self;
176
239
  }
177
240
 
241
+ static VALUE
242
+ pg_copy_result(t_pg_result *this)
243
+ {
244
+ int nfields = this->nfields == -1 ? (this->pgresult ? PQnfields(this->pgresult) : 0) : this->nfields;
245
+ size_t len = sizeof(*this) + sizeof(*this->fnames) * nfields;
246
+ t_pg_result *copy;
247
+
248
+ copy = (t_pg_result *)xmalloc(len);
249
+ memcpy(copy, this, len);
250
+ this->result_size = 0;
251
+
252
+ return TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, copy);
253
+ }
254
+
178
255
  VALUE
179
256
  pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
180
257
  {
@@ -229,7 +306,7 @@ pg_result_check( VALUE self )
229
306
  }
230
307
  }
231
308
 
232
- PG_ENCODING_SET_NOCHECK( error, ENCODING_GET(self) );
309
+ PG_ENCODING_SET_NOCHECK( error, this->enc_idx );
233
310
 
234
311
  sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
235
312
  klass = lookup_error_class( sqlstate );
@@ -261,8 +338,7 @@ pg_result_check( VALUE self )
261
338
  * Special care must be taken when PG::Tuple objects are used.
262
339
  * In this case #clear must not be called unless all PG::Tuple objects of this result are fully materialized.
263
340
  *
264
- * If PG::Result#autoclear? is true then the result is marked as cleared
265
- * and the underlying C struct will be cleared automatically by libpq.
341
+ * If PG::Result#autoclear? is +true+ then the result is only marked as cleared but clearing the underlying C struct will happen when the callback returns.
266
342
  *
267
343
  */
268
344
  VALUE
@@ -290,8 +366,10 @@ pgresult_cleared_p( VALUE self )
290
366
  * call-seq:
291
367
  * res.autoclear? -> boolean
292
368
  *
293
- * Returns +true+ if the underlying C struct will be cleared automatically by libpq.
294
- * Elsewise the result is cleared by PG::Result#clear or by the GC when it's no longer in use.
369
+ * Returns +true+ if the underlying C struct will be cleared at the end of a callback.
370
+ * This applies only to Result objects received by the block to PG::Cinnection#set_notice_receiver .
371
+ *
372
+ * All other Result objects are automatically cleared by the GC when the object is no longer in use or manually by PG::Result#clear .
295
373
  *
296
374
  */
297
375
  VALUE
@@ -305,37 +383,6 @@ pgresult_autoclear_p( VALUE self )
305
383
  * DATA pointer functions
306
384
  */
307
385
 
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
386
  /*
340
387
  * Fetch the PG::Result object data pointer and check it's
341
388
  * PGresult data pointer for sanity.
@@ -365,32 +412,30 @@ pgresult_get(VALUE self)
365
412
  return this->pgresult;
366
413
  }
367
414
 
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 )
415
+ static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
390
416
  {
391
- VALUE self = TypedData_Wrap_Struct( klass, &pgresult_type, NULL );
392
-
393
- return self;
417
+ VALUE fname;
418
+ #ifdef TRUFFLERUBY
419
+ if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
420
+ #else
421
+ if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
422
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
423
+ fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
424
+ if( fname == Qnil ){
425
+ fname = rb_str_new2(cstr);
426
+ PG_ENCODING_SET_NOCHECK(fname, enc_idx);
427
+ fname = rb_str_intern(fname);
428
+ }
429
+ } else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
430
+ #endif
431
+ rb_encoding *enc = rb_enc_from_index(enc_idx);
432
+ fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
433
+ } else {
434
+ fname = rb_str_new2(cstr);
435
+ PG_ENCODING_SET_NOCHECK(fname, enc_idx);
436
+ fname = rb_obj_freeze(fname);
437
+ }
438
+ return fname;
394
439
  }
395
440
 
396
441
  static void pgresult_init_fnames(VALUE self)
@@ -402,12 +447,9 @@ static void pgresult_init_fnames(VALUE self)
402
447
  int nfields = PQnfields(this->pgresult);
403
448
 
404
449
  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);
450
+ char *cfname = PQfname(this->pgresult, i);
451
+ this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
408
452
  this->nfields = i + 1;
409
-
410
- RB_GC_GUARD(fname);
411
453
  }
412
454
  this->nfields = nfields;
413
455
  }
@@ -470,8 +512,9 @@ pgresult_result_status(VALUE self)
470
512
  static VALUE
471
513
  pgresult_res_status(VALUE self, VALUE status)
472
514
  {
473
- VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
474
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
515
+ t_pg_result *this = pgresult_get_this_safe(self);
516
+ VALUE ret = rb_str_new2(PQresStatus(NUM2INT(status)));
517
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
475
518
  return ret;
476
519
  }
477
520
 
@@ -484,11 +527,40 @@ pgresult_res_status(VALUE self, VALUE status)
484
527
  static VALUE
485
528
  pgresult_error_message(VALUE self)
486
529
  {
487
- VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
488
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
530
+ t_pg_result *this = pgresult_get_this_safe(self);
531
+ VALUE ret = rb_str_new2(PQresultErrorMessage(this->pgresult));
532
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
489
533
  return ret;
490
534
  }
491
535
 
536
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
537
+ /*
538
+ * call-seq:
539
+ * res.verbose_error_message( verbosity, show_context ) -> String
540
+ *
541
+ * Returns a reformatted version of the error message associated with a PGresult object.
542
+ *
543
+ * Available since PostgreSQL-9.6
544
+ */
545
+ static VALUE
546
+ pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
547
+ {
548
+ t_pg_result *this = pgresult_get_this_safe(self);
549
+ VALUE ret;
550
+ char *c_str;
551
+
552
+ c_str = PQresultVerboseErrorMessage(this->pgresult, NUM2INT(verbosity), NUM2INT(show_context));
553
+ if(!c_str)
554
+ rb_raise(rb_eNoMemError, "insufficient memory to format error message");
555
+
556
+ ret = rb_str_new2(c_str);
557
+ PQfreemem(c_str);
558
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
559
+
560
+ return ret;
561
+ }
562
+ #endif
563
+
492
564
  /*
493
565
  * call-seq:
494
566
  * res.error_field(fieldcode) -> String
@@ -538,14 +610,14 @@ pgresult_error_message(VALUE self)
538
610
  static VALUE
539
611
  pgresult_error_field(VALUE self, VALUE field)
540
612
  {
541
- PGresult *result = pgresult_get( self );
613
+ t_pg_result *this = pgresult_get_this_safe(self);
542
614
  int fieldcode = NUM2INT( field );
543
- char * fieldstr = PQresultErrorField( result, fieldcode );
615
+ char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
544
616
  VALUE ret = Qnil;
545
617
 
546
618
  if ( fieldstr ) {
547
- ret = rb_tainted_str_new2( fieldstr );
548
- PG_ENCODING_SET_NOCHECK( ret, ENCODING_GET(self ));
619
+ ret = rb_str_new2( fieldstr );
620
+ PG_ENCODING_SET_NOCHECK( ret, this->enc_idx );
549
621
  }
550
622
 
551
623
  return ret;
@@ -583,24 +655,25 @@ pgresult_nfields(VALUE self)
583
655
 
584
656
  /*
585
657
  * call-seq:
586
- * res.fname( index ) -> String
658
+ * res.fname( index ) -> String or Symbol
587
659
  *
588
660
  * Returns the name of the column corresponding to _index_.
661
+ * Depending on #field_name_type= it's a String or Symbol.
662
+ *
589
663
  */
590
664
  static VALUE
591
665
  pgresult_fname(VALUE self, VALUE index)
592
666
  {
593
- VALUE fname;
594
- PGresult *result = pgresult_get(self);
667
+ t_pg_result *this = pgresult_get_this_safe(self);
595
668
  int i = NUM2INT(index);
669
+ char *cfname;
596
670
 
597
- if (i < 0 || i >= PQnfields(result)) {
671
+ if (i < 0 || i >= PQnfields(this->pgresult)) {
598
672
  rb_raise(rb_eArgError,"invalid field number %d", i);
599
673
  }
600
674
 
601
- fname = rb_tainted_str_new2(PQfname(result, i));
602
- PG_ENCODING_SET_NOCHECK(fname, ENCODING_GET(self));
603
- return rb_obj_freeze(fname);
675
+ cfname = PQfname(this->pgresult, i);
676
+ return pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
604
677
  }
605
678
 
606
679
  /*
@@ -899,8 +972,9 @@ pgresult_paramtype(VALUE self, VALUE param_number)
899
972
  static VALUE
900
973
  pgresult_cmd_status(VALUE self)
901
974
  {
902
- VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
903
- PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET(self));
975
+ t_pg_result *this = pgresult_get_this_safe(self);
976
+ VALUE ret = rb_str_new2(PQcmdStatus(this->pgresult));
977
+ PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
904
978
  return ret;
905
979
  }
906
980
 
@@ -1100,8 +1174,12 @@ static VALUE
1100
1174
  pgresult_field_values( VALUE self, VALUE field )
1101
1175
  {
1102
1176
  PGresult *result = pgresult_get( self );
1103
- const char *fieldname = StringValueCStr( field );
1104
- int fnum = PQfnumber( result, fieldname );
1177
+ const char *fieldname;
1178
+ int fnum;
1179
+
1180
+ if( RB_TYPE_P(field, T_SYMBOL) ) field = rb_sym_to_s( field );
1181
+ fieldname = StringValueCStr( field );
1182
+ fnum = PQfnumber( result, fieldname );
1105
1183
 
1106
1184
  if ( fnum < 0 )
1107
1185
  rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
@@ -1144,6 +1222,25 @@ pgresult_tuple_values(VALUE self, VALUE index)
1144
1222
  }
1145
1223
  }
1146
1224
 
1225
+ static void ensure_init_for_tuple(VALUE self)
1226
+ {
1227
+ t_pg_result *this = pgresult_get_this_safe(self);
1228
+
1229
+ if( this->field_map == Qnil ){
1230
+ int i;
1231
+ VALUE field_map = rb_hash_new();
1232
+
1233
+ if( this->nfields == -1 )
1234
+ pgresult_init_fnames( self );
1235
+
1236
+ for( i = 0; i < this->nfields; i++ ){
1237
+ rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
1238
+ }
1239
+ rb_obj_freeze(field_map);
1240
+ this->field_map = field_map;
1241
+ }
1242
+ }
1243
+
1147
1244
  /*
1148
1245
  * call-seq:
1149
1246
  * res.tuple( n ) -> PG::Tuple
@@ -1164,19 +1261,7 @@ pgresult_tuple(VALUE self, VALUE index)
1164
1261
  if ( tuple_num < 0 || tuple_num >= num_tuples )
1165
1262
  rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
1166
1263
 
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
- }
1264
+ ensure_init_for_tuple(self);
1180
1265
 
1181
1266
  return pg_tuple_new(self, tuple_num);
1182
1267
  }
@@ -1208,7 +1293,7 @@ pgresult_each(VALUE self)
1208
1293
  * call-seq:
1209
1294
  * res.fields() -> Array
1210
1295
  *
1211
- * Returns an array of Strings representing the names of the fields in the result.
1296
+ * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
1212
1297
  */
1213
1298
  static VALUE
1214
1299
  pgresult_fields(VALUE self)
@@ -1307,11 +1392,17 @@ yield_tuple(VALUE self, int ntuples, int nfields)
1307
1392
  {
1308
1393
  int tuple_num;
1309
1394
  t_pg_result *this = pgresult_get_this(self);
1310
- VALUE result = pg_new_result(this->pgresult, this->connection);
1395
+ VALUE copy;
1311
1396
  UNUSED(nfields);
1312
1397
 
1398
+ /* make a copy of the base result, that is bound to the PG::Tuple */
1399
+ copy = pg_copy_result(this);
1400
+ /* The copy is now owner of the PGresult and is responsible to PQclear it.
1401
+ * We clear the pgresult here, so that it's not double freed on error within yield. */
1402
+ this->pgresult = NULL;
1403
+
1313
1404
  for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
1314
- VALUE tuple = pgresult_tuple(result, INT2FIX(tuple_num));
1405
+ VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
1315
1406
  rb_yield( tuple );
1316
1407
  }
1317
1408
  }
@@ -1392,8 +1483,6 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
1392
1483
  * # do something with each received row of the second query
1393
1484
  * end
1394
1485
  * conn.get_result # => nil (no more results)
1395
- *
1396
- * Available since PostgreSQL-9.2
1397
1486
  */
1398
1487
  static VALUE
1399
1488
  pgresult_stream_each(VALUE self)
@@ -1410,8 +1499,6 @@ pgresult_stream_each(VALUE self)
1410
1499
  *
1411
1500
  * This method works equally to #stream_each , but yields an Array of
1412
1501
  * values.
1413
- *
1414
- * Available since PostgreSQL-9.2
1415
1502
  */
1416
1503
  static VALUE
1417
1504
  pgresult_stream_each_row(VALUE self)
@@ -1426,21 +1513,81 @@ pgresult_stream_each_row(VALUE self)
1426
1513
  * Yields each row of the result set in single row mode.
1427
1514
  *
1428
1515
  * This method works equally to #stream_each , but yields a PG::Tuple object.
1429
- *
1430
- * Available since PostgreSQL-9.2
1431
1516
  */
1432
1517
  static VALUE
1433
1518
  pgresult_stream_each_tuple(VALUE self)
1434
1519
  {
1520
+ /* allocate VALUEs that are shared between all streamed tuples */
1521
+ ensure_init_for_tuple(self);
1522
+
1435
1523
  return pgresult_stream_any(self, yield_tuple);
1436
1524
  }
1437
1525
 
1526
+ /*
1527
+ * call-seq:
1528
+ * res.field_name_type = Symbol
1529
+ *
1530
+ * Set type of field names specific to this result.
1531
+ * It can be set to one of:
1532
+ * * +:string+ to use String based field names
1533
+ * * +:symbol+ to use Symbol based field names
1534
+ * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future.
1535
+ *
1536
+ * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
1537
+ *
1538
+ * This setting affects several result methods:
1539
+ * * keys of Hash returned by #[] , #each and #stream_each
1540
+ * * #fields
1541
+ * * #fname
1542
+ * * field names used by #tuple and #stream_each_tuple
1543
+ *
1544
+ * The type of field names can only be changed before any of the affected methods have been called.
1545
+ *
1546
+ */
1547
+ static VALUE
1548
+ pgresult_field_name_type_set(VALUE self, VALUE sym)
1549
+ {
1550
+ t_pg_result *this = pgresult_get_this(self);
1551
+ if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
1552
+
1553
+ this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
1554
+ if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
1555
+ else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
1556
+ else if ( sym == sym_string );
1557
+ else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
1558
+
1559
+ return sym;
1560
+ }
1561
+
1562
+ /*
1563
+ * call-seq:
1564
+ * res.field_name_type -> Symbol
1565
+ *
1566
+ * Get type of field names.
1567
+ *
1568
+ * See description at #field_name_type=
1569
+ */
1570
+ static VALUE
1571
+ pgresult_field_name_type_get(VALUE self)
1572
+ {
1573
+ t_pg_result *this = pgresult_get_this(self);
1574
+ if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
1575
+ return sym_symbol;
1576
+ } else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
1577
+ return sym_static_symbol;
1578
+ } else {
1579
+ return sym_string;
1580
+ }
1581
+ }
1438
1582
 
1439
1583
  void
1440
1584
  init_pg_result()
1441
1585
  {
1442
- rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
1443
- rb_define_alloc_func( rb_cPGresult, pgresult_s_allocate );
1586
+ sym_string = ID2SYM(rb_intern("string"));
1587
+ sym_symbol = ID2SYM(rb_intern("symbol"));
1588
+ sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
1589
+
1590
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cData );
1444
1591
  rb_include_module(rb_cPGresult, rb_mEnumerable);
1445
1592
  rb_include_module(rb_cPGresult, rb_mPGconstants);
1446
1593
 
@@ -1449,6 +1596,10 @@ init_pg_result()
1449
1596
  rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
1450
1597
  rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
1451
1598
  rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
1599
+ #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
1600
+ rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
1601
+ rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
1602
+ #endif
1452
1603
  rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
1453
1604
  rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
1454
1605
  rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
@@ -1496,6 +1647,7 @@ init_pg_result()
1496
1647
  rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
1497
1648
  rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
1498
1649
  rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
1499
- }
1500
-
1501
1650
 
1651
+ rb_define_method(rb_cPGresult, "field_name_type=", pgresult_field_name_type_set, 1 );
1652
+ rb_define_method(rb_cPGresult, "field_name_type", pgresult_field_name_type_get, 0 );
1653
+ }