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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/History.rdoc +86 -0
- data/Manifest.txt +3 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +44 -9
- data/Rakefile +8 -6
- data/Rakefile.cross +57 -56
- 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 +21 -18
- data/ext/pg_binary_decoder.c +9 -9
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +21 -9
- data/ext/pg_connection.c +388 -298
- data/ext/pg_copy_coder.c +6 -3
- data/ext/pg_record_coder.c +491 -0
- data/ext/pg_result.c +279 -127
- 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 +9 -4
- 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/pg.rb +4 -4
- data/lib/pg/basic_type_mapping.rb +81 -18
- 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 +11 -11
- data/spec/pg/basic_type_mapping_spec.rb +140 -18
- data/spec/pg/connection_spec.rb +166 -89
- data/spec/pg/result_spec.rb +194 -4
- data/spec/pg/tuple_spec.rb +55 -2
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_column_spec.rb +5 -1
- data/spec/pg/type_map_by_oid_spec.rb +2 -2
- data/spec/pg/type_spec.rb +180 -6
- metadata +31 -30
- 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,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
|
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
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
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,
|
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
|
294
|
-
*
|
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
|
392
|
-
|
393
|
-
|
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
|
-
|
406
|
-
|
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
|
-
|
474
|
-
|
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
|
-
|
488
|
-
|
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
|
-
|
613
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
542
614
|
int fieldcode = NUM2INT( field );
|
543
|
-
char * fieldstr = PQresultErrorField(
|
615
|
+
char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
|
544
616
|
VALUE ret = Qnil;
|
545
617
|
|
546
618
|
if ( fieldstr ) {
|
547
|
-
ret =
|
548
|
-
PG_ENCODING_SET_NOCHECK( ret,
|
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
|
-
|
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(
|
671
|
+
if (i < 0 || i >= PQnfields(this->pgresult)) {
|
598
672
|
rb_raise(rb_eArgError,"invalid field number %d", i);
|
599
673
|
}
|
600
674
|
|
601
|
-
|
602
|
-
|
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
|
-
|
903
|
-
|
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
|
1104
|
-
int fnum
|
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
|
-
|
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
|
-
*
|
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
|
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(
|
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
|
-
|
1443
|
-
|
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
|
+
}
|