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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +63 -0
- data/Manifest.txt +3 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +43 -8
- data/Rakefile +3 -3
- data/Rakefile.cross +6 -3
- data/ext/errorcodes.def +64 -0
- data/ext/errorcodes.txt +18 -2
- data/ext/extconf.rb +6 -6
- data/ext/pg.c +132 -95
- data/ext/pg.h +20 -18
- data/ext/pg_binary_decoder.c +9 -9
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +5 -5
- data/ext/pg_connection.c +388 -298
- data/ext/pg_copy_coder.c +5 -3
- data/ext/pg_record_coder.c +490 -0
- data/ext/pg_result.c +269 -123
- data/ext/pg_text_decoder.c +14 -8
- data/ext/pg_text_encoder.c +180 -48
- data/ext/pg_tuple.c +14 -6
- data/ext/pg_type_map.c +1 -1
- data/ext/pg_type_map_all_strings.c +4 -4
- data/ext/pg_type_map_by_class.c +4 -3
- data/ext/pg_type_map_by_column.c +7 -6
- data/ext/pg_type_map_by_mri_type.c +1 -1
- data/ext/pg_type_map_by_oid.c +3 -2
- data/ext/pg_type_map_in_ruby.c +1 -1
- data/ext/{util.c → pg_util.c} +5 -5
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/2.2/pg_ext.so +0 -0
- data/lib/2.3/pg_ext.so +0 -0
- data/lib/2.4/pg_ext.so +0 -0
- data/lib/2.5/pg_ext.so +0 -0
- data/lib/2.6/pg_ext.so +0 -0
- data/lib/libpq.dll +0 -0
- data/lib/pg.rb +2 -3
- data/lib/pg/basic_type_mapping.rb +79 -16
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +22 -1
- data/lib/pg/connection.rb +2 -2
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +1 -0
- data/lib/pg/result.rb +13 -1
- data/lib/pg/text_decoder.rb +2 -3
- data/lib/pg/text_encoder.rb +8 -18
- data/lib/pg/type_map_by_column.rb +2 -1
- data/spec/helpers.rb +10 -8
- data/spec/pg/basic_type_mapping_spec.rb +150 -13
- data/spec/pg/connection_spec.rb +89 -50
- data/spec/pg/result_spec.rb +193 -3
- data/spec/pg/tuple_spec.rb +55 -2
- data/spec/pg/type_map_by_column_spec.rb +5 -1
- data/spec/pg/type_spec.rb +180 -6
- metadata +27 -25
- metadata.gz.sig +0 -0
data/ext/pg_result.c
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
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,
|
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
|
392
|
-
|
393
|
-
|
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
|
-
|
406
|
-
|
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
|
-
|
474
|
-
|
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
|
-
|
488
|
-
|
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
|
-
|
607
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
542
608
|
int fieldcode = NUM2INT( field );
|
543
|
-
char * fieldstr = PQresultErrorField(
|
609
|
+
char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
|
544
610
|
VALUE ret = Qnil;
|
545
611
|
|
546
612
|
if ( fieldstr ) {
|
547
|
-
ret =
|
548
|
-
PG_ENCODING_SET_NOCHECK( ret,
|
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
|
-
|
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(
|
665
|
+
if (i < 0 || i >= PQnfields(this->pgresult)) {
|
598
666
|
rb_raise(rb_eArgError,"invalid field number %d", i);
|
599
667
|
}
|
600
668
|
|
601
|
-
|
602
|
-
|
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
|
-
|
903
|
-
|
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
|
1104
|
-
int fnum
|
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
|
-
|
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
|
-
*
|
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
|
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(
|
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
|
-
|
1443
|
-
|
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
|
+
}
|