pg 1.1.3 → 1.4.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/.appveyor.yml +36 -0
- data/.gems +6 -0
- data/.github/workflows/binary-gems.yml +86 -0
- data/.github/workflows/source-gem.yml +129 -0
- data/.gitignore +13 -0
- data/.hgsigs +34 -0
- data/.hgtags +41 -0
- data/.irbrc +23 -0
- data/.pryrc +23 -0
- data/.tm_properties +21 -0
- data/.travis.yml +49 -0
- data/Gemfile +14 -0
- data/History.rdoc +291 -6
- data/Manifest.txt +3 -3
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +51 -15
- data/Rakefile +31 -140
- data/Rakefile.cross +60 -56
- data/certs/ged.pem +24 -0
- data/certs/larskanis-2022.pem +26 -0
- data/ext/errorcodes.def +76 -0
- data/ext/errorcodes.rb +0 -0
- data/ext/errorcodes.txt +21 -2
- data/ext/extconf.rb +101 -26
- data/ext/gvl_wrappers.c +4 -0
- data/ext/gvl_wrappers.h +23 -0
- data/ext/pg.c +190 -122
- data/ext/pg.h +43 -17
- data/ext/pg_binary_decoder.c +20 -16
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +95 -29
- data/ext/pg_connection.c +1214 -919
- data/ext/pg_copy_coder.c +50 -18
- data/ext/pg_record_coder.c +521 -0
- data/ext/pg_result.c +344 -153
- data/ext/pg_text_decoder.c +15 -9
- data/ext/pg_text_encoder.c +185 -53
- data/ext/pg_tuple.c +63 -35
- data/ext/pg_type_map.c +42 -9
- data/ext/pg_type_map_all_strings.c +19 -5
- data/ext/pg_type_map_by_class.c +54 -24
- data/ext/pg_type_map_by_column.c +73 -34
- data/ext/pg_type_map_by_mri_type.c +48 -19
- data/ext/pg_type_map_by_oid.c +55 -25
- data/ext/pg_type_map_in_ruby.c +51 -20
- data/ext/{util.c → pg_util.c} +7 -7
- data/ext/{util.h → pg_util.h} +0 -0
- data/lib/pg/basic_type_map_based_on_result.rb +47 -0
- data/lib/pg/basic_type_map_for_queries.rb +193 -0
- data/lib/pg/basic_type_map_for_results.rb +81 -0
- data/lib/pg/basic_type_registry.rb +301 -0
- data/lib/pg/binary_decoder.rb +1 -0
- data/lib/pg/coder.rb +23 -2
- data/lib/pg/connection.rb +669 -71
- data/lib/pg/constants.rb +1 -0
- data/lib/pg/exceptions.rb +8 -1
- 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/lib/pg/version.rb +4 -0
- data/lib/pg.rb +48 -33
- data/misc/openssl-pg-segfault.rb +31 -0
- data/misc/postgres/History.txt +9 -0
- data/misc/postgres/Manifest.txt +5 -0
- data/misc/postgres/README.txt +21 -0
- data/misc/postgres/Rakefile +21 -0
- data/misc/postgres/lib/postgres.rb +16 -0
- data/misc/ruby-pg/History.txt +9 -0
- data/misc/ruby-pg/Manifest.txt +5 -0
- data/misc/ruby-pg/README.txt +21 -0
- data/misc/ruby-pg/Rakefile +21 -0
- data/misc/ruby-pg/lib/ruby/pg.rb +16 -0
- data/pg.gemspec +32 -0
- data/rakelib/task_extension.rb +46 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +102 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copydata.rb +71 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +177 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +285 -0
- data/sample/replication_monitor.rb +222 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +311 -0
- data.tar.gz.sig +0 -0
- metadata +94 -237
- metadata.gz.sig +0 -0
- data/ChangeLog +0 -6595
- data/lib/pg/basic_type_mapping.rb +0 -459
- data/spec/data/expected_trace.out +0 -26
- data/spec/data/random_binary_data +0 -0
- data/spec/helpers.rb +0 -381
- data/spec/pg/basic_type_mapping_spec.rb +0 -508
- data/spec/pg/connection_spec.rb +0 -1849
- data/spec/pg/connection_sync_spec.rb +0 -41
- data/spec/pg/result_spec.rb +0 -491
- data/spec/pg/tuple_spec.rb +0 -280
- data/spec/pg/type_map_by_class_spec.rb +0 -138
- data/spec/pg/type_map_by_column_spec.rb +0 -222
- data/spec/pg/type_map_by_mri_type_spec.rb +0 -136
- data/spec/pg/type_map_by_oid_spec.rb +0 -149
- data/spec/pg/type_map_in_ruby_spec.rb +0 -164
- data/spec/pg/type_map_spec.rb +0 -22
- data/spec/pg/type_spec.rb +0 -949
- data/spec/pg_spec.rb +0 -50
data/ext/pg_result.c
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pg_result.c - PG::Result class extension
|
|
3
|
-
* $Id
|
|
3
|
+
* $Id$
|
|
4
4
|
*
|
|
5
5
|
*/
|
|
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,25 +101,97 @@ pgresult_approx_size(PGresult *result)
|
|
|
94
101
|
|
|
95
102
|
return size;
|
|
96
103
|
}
|
|
104
|
+
#endif
|
|
97
105
|
|
|
106
|
+
/*
|
|
107
|
+
* GC Mark function
|
|
108
|
+
*/
|
|
98
109
|
static void
|
|
99
|
-
|
|
110
|
+
pgresult_gc_mark( void *_this )
|
|
100
111
|
{
|
|
112
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
113
|
+
int i;
|
|
114
|
+
|
|
115
|
+
rb_gc_mark_movable( this->connection );
|
|
116
|
+
rb_gc_mark_movable( this->typemap );
|
|
117
|
+
rb_gc_mark_movable( this->tuple_hash );
|
|
118
|
+
rb_gc_mark_movable( this->field_map );
|
|
119
|
+
|
|
120
|
+
for( i=0; i < this->nfields; i++ ){
|
|
121
|
+
rb_gc_mark_movable( this->fnames[i] );
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
static void
|
|
126
|
+
pgresult_gc_compact( void *_this )
|
|
127
|
+
{
|
|
128
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
129
|
+
int i;
|
|
130
|
+
|
|
131
|
+
pg_gc_location( this->connection );
|
|
132
|
+
pg_gc_location( this->typemap );
|
|
133
|
+
pg_gc_location( this->tuple_hash );
|
|
134
|
+
pg_gc_location( this->field_map );
|
|
135
|
+
|
|
136
|
+
for( i=0; i < this->nfields; i++ ){
|
|
137
|
+
pg_gc_location( this->fnames[i] );
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* GC Free function
|
|
143
|
+
*/
|
|
144
|
+
static void
|
|
145
|
+
pgresult_clear( void *_this )
|
|
146
|
+
{
|
|
147
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
101
148
|
if( this->pgresult && !this->autoclear ){
|
|
102
149
|
PQclear(this->pgresult);
|
|
103
150
|
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
|
104
151
|
rb_gc_adjust_memory_usage(-this->result_size);
|
|
105
152
|
#endif
|
|
106
153
|
}
|
|
154
|
+
this->result_size = 0;
|
|
155
|
+
this->nfields = -1;
|
|
107
156
|
this->pgresult = NULL;
|
|
108
157
|
}
|
|
109
158
|
|
|
159
|
+
static void
|
|
160
|
+
pgresult_gc_free( void *_this )
|
|
161
|
+
{
|
|
162
|
+
t_pg_result *this = (t_pg_result *)_this;
|
|
163
|
+
pgresult_clear( this );
|
|
164
|
+
xfree(this);
|
|
165
|
+
}
|
|
166
|
+
|
|
110
167
|
static size_t
|
|
111
|
-
pgresult_memsize(
|
|
168
|
+
pgresult_memsize( const void *_this )
|
|
112
169
|
{
|
|
170
|
+
const t_pg_result *this = (const t_pg_result *)_this;
|
|
171
|
+
/* Ideally the memory 'this' is pointing to should be taken into account as well.
|
|
172
|
+
* However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
|
|
173
|
+
*/
|
|
113
174
|
return this->result_size;
|
|
114
175
|
}
|
|
115
176
|
|
|
177
|
+
static const rb_data_type_t pgresult_type = {
|
|
178
|
+
"PG::Result",
|
|
179
|
+
{
|
|
180
|
+
pgresult_gc_mark,
|
|
181
|
+
pgresult_gc_free,
|
|
182
|
+
pgresult_memsize,
|
|
183
|
+
pg_compact_callback(pgresult_gc_compact),
|
|
184
|
+
},
|
|
185
|
+
0, 0,
|
|
186
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/* Needed by sequel_pg gem, do not delete */
|
|
190
|
+
int pg_get_result_enc_idx(VALUE self)
|
|
191
|
+
{
|
|
192
|
+
return pgresult_get_this(self)->enc_idx;
|
|
193
|
+
}
|
|
194
|
+
|
|
116
195
|
/*
|
|
117
196
|
* Global functions
|
|
118
197
|
*/
|
|
@@ -124,31 +203,32 @@ static VALUE
|
|
|
124
203
|
pg_new_result2(PGresult *result, VALUE rb_pgconn)
|
|
125
204
|
{
|
|
126
205
|
int nfields = result ? PQnfields(result) : 0;
|
|
127
|
-
VALUE self
|
|
206
|
+
VALUE self;
|
|
128
207
|
t_pg_result *this;
|
|
129
208
|
|
|
130
209
|
this = (t_pg_result *)xmalloc(sizeof(*this) + sizeof(*this->fnames) * nfields);
|
|
131
|
-
RTYPEDDATA_DATA(self) = this;
|
|
132
|
-
|
|
133
210
|
this->pgresult = result;
|
|
134
211
|
this->connection = rb_pgconn;
|
|
135
212
|
this->typemap = pg_typemap_all_strings;
|
|
136
|
-
this->p_typemap =
|
|
213
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
|
137
214
|
this->nfields = -1;
|
|
138
215
|
this->tuple_hash = Qnil;
|
|
139
216
|
this->field_map = Qnil;
|
|
140
|
-
|
|
141
|
-
|
|
217
|
+
this->flags = 0;
|
|
218
|
+
self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
|
|
142
219
|
|
|
143
220
|
if( result ){
|
|
144
221
|
t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
|
|
145
222
|
VALUE typemap = p_conn->type_map_for_results;
|
|
146
|
-
|
|
147
223
|
/* Type check is done when assigned to PG::Connection. */
|
|
148
|
-
t_typemap *p_typemap =
|
|
224
|
+
t_typemap *p_typemap = RTYPEDDATA_DATA(typemap);
|
|
149
225
|
|
|
226
|
+
this->enc_idx = p_conn->enc_idx;
|
|
150
227
|
this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
|
151
|
-
this->p_typemap =
|
|
228
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
|
229
|
+
this->flags = p_conn->flags;
|
|
230
|
+
} else {
|
|
231
|
+
this->enc_idx = rb_locale_encindex();
|
|
152
232
|
}
|
|
153
233
|
|
|
154
234
|
return self;
|
|
@@ -159,22 +239,38 @@ pg_new_result(PGresult *result, VALUE rb_pgconn)
|
|
|
159
239
|
{
|
|
160
240
|
VALUE self = pg_new_result2(result, rb_pgconn);
|
|
161
241
|
t_pg_result *this = pgresult_get_this(self);
|
|
162
|
-
t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
|
|
163
242
|
|
|
164
243
|
this->autoclear = 0;
|
|
165
244
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
245
|
+
/* Estimate size of underlying pgresult memory storage and account to ruby GC.
|
|
246
|
+
* There's no need to adjust the GC for xmalloc'ed memory, but libpq is using libc malloc() ruby doesn't know about.
|
|
247
|
+
*/
|
|
248
|
+
/* 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.
|
|
249
|
+
* For now the memory savings don't justify the ifdefs necessary to support both cases.
|
|
250
|
+
*/
|
|
251
|
+
this->result_size = pgresult_approx_size(result);
|
|
169
252
|
|
|
170
253
|
#ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
|
|
171
|
-
|
|
254
|
+
rb_gc_adjust_memory_usage(this->result_size);
|
|
172
255
|
#endif
|
|
173
|
-
}
|
|
174
256
|
|
|
175
257
|
return self;
|
|
176
258
|
}
|
|
177
259
|
|
|
260
|
+
static VALUE
|
|
261
|
+
pg_copy_result(t_pg_result *this)
|
|
262
|
+
{
|
|
263
|
+
int nfields = this->nfields == -1 ? (this->pgresult ? PQnfields(this->pgresult) : 0) : this->nfields;
|
|
264
|
+
size_t len = sizeof(*this) + sizeof(*this->fnames) * nfields;
|
|
265
|
+
t_pg_result *copy;
|
|
266
|
+
|
|
267
|
+
copy = (t_pg_result *)xmalloc(len);
|
|
268
|
+
memcpy(copy, this, len);
|
|
269
|
+
this->result_size = 0;
|
|
270
|
+
|
|
271
|
+
return TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, copy);
|
|
272
|
+
}
|
|
273
|
+
|
|
178
274
|
VALUE
|
|
179
275
|
pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
|
|
180
276
|
{
|
|
@@ -193,7 +289,11 @@ pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
|
|
|
193
289
|
* call-seq:
|
|
194
290
|
* res.check -> nil
|
|
195
291
|
*
|
|
196
|
-
* Raises appropriate exception if PG::Result is in a bad state
|
|
292
|
+
* Raises appropriate exception if PG::Result is in a bad state, which is:
|
|
293
|
+
* * +PGRES_BAD_RESPONSE+
|
|
294
|
+
* * +PGRES_FATAL_ERROR+
|
|
295
|
+
* * +PGRES_NONFATAL_ERROR+
|
|
296
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
197
297
|
*/
|
|
198
298
|
VALUE
|
|
199
299
|
pg_result_check( VALUE self )
|
|
@@ -218,10 +318,16 @@ pg_result_check( VALUE self )
|
|
|
218
318
|
case PGRES_SINGLE_TUPLE:
|
|
219
319
|
case PGRES_EMPTY_QUERY:
|
|
220
320
|
case PGRES_COMMAND_OK:
|
|
321
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
322
|
+
case PGRES_PIPELINE_SYNC:
|
|
323
|
+
#endif
|
|
221
324
|
return self;
|
|
222
325
|
case PGRES_BAD_RESPONSE:
|
|
223
326
|
case PGRES_FATAL_ERROR:
|
|
224
327
|
case PGRES_NONFATAL_ERROR:
|
|
328
|
+
#ifdef HAVE_PQENTERPIPELINEMODE
|
|
329
|
+
case PGRES_PIPELINE_ABORTED:
|
|
330
|
+
#endif
|
|
225
331
|
error = rb_str_new2( PQresultErrorMessage(this->pgresult) );
|
|
226
332
|
break;
|
|
227
333
|
default:
|
|
@@ -229,7 +335,7 @@ pg_result_check( VALUE self )
|
|
|
229
335
|
}
|
|
230
336
|
}
|
|
231
337
|
|
|
232
|
-
PG_ENCODING_SET_NOCHECK( error,
|
|
338
|
+
PG_ENCODING_SET_NOCHECK( error, this->enc_idx );
|
|
233
339
|
|
|
234
340
|
sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
|
|
235
341
|
klass = lookup_error_class( sqlstate );
|
|
@@ -261,8 +367,7 @@ pg_result_check( VALUE self )
|
|
|
261
367
|
* Special care must be taken when PG::Tuple objects are used.
|
|
262
368
|
* In this case #clear must not be called unless all PG::Tuple objects of this result are fully materialized.
|
|
263
369
|
*
|
|
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.
|
|
370
|
+
* 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
371
|
*
|
|
267
372
|
*/
|
|
268
373
|
VALUE
|
|
@@ -277,7 +382,7 @@ pg_result_clear(VALUE self)
|
|
|
277
382
|
* call-seq:
|
|
278
383
|
* res.cleared? -> boolean
|
|
279
384
|
*
|
|
280
|
-
* Returns +true+ if the backend result memory has been
|
|
385
|
+
* Returns +true+ if the backend result memory has been freed.
|
|
281
386
|
*/
|
|
282
387
|
VALUE
|
|
283
388
|
pgresult_cleared_p( VALUE self )
|
|
@@ -290,8 +395,10 @@ pgresult_cleared_p( VALUE self )
|
|
|
290
395
|
* call-seq:
|
|
291
396
|
* res.autoclear? -> boolean
|
|
292
397
|
*
|
|
293
|
-
* Returns +true+ if the underlying C struct will be cleared
|
|
294
|
-
*
|
|
398
|
+
* Returns +true+ if the underlying C struct will be cleared at the end of a callback.
|
|
399
|
+
* This applies only to Result objects received by the block to PG::Connection#set_notice_receiver .
|
|
400
|
+
*
|
|
401
|
+
* 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
402
|
*
|
|
296
403
|
*/
|
|
297
404
|
VALUE
|
|
@@ -305,37 +412,6 @@ pgresult_autoclear_p( VALUE self )
|
|
|
305
412
|
* DATA pointer functions
|
|
306
413
|
*/
|
|
307
414
|
|
|
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
415
|
/*
|
|
340
416
|
* Fetch the PG::Result object data pointer and check it's
|
|
341
417
|
* PGresult data pointer for sanity.
|
|
@@ -365,32 +441,30 @@ pgresult_get(VALUE self)
|
|
|
365
441
|
return this->pgresult;
|
|
366
442
|
}
|
|
367
443
|
|
|
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 )
|
|
444
|
+
static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
|
|
390
445
|
{
|
|
391
|
-
VALUE
|
|
392
|
-
|
|
393
|
-
|
|
446
|
+
VALUE fname;
|
|
447
|
+
#ifdef TRUFFLERUBY
|
|
448
|
+
if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
|
|
449
|
+
#else
|
|
450
|
+
if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
|
451
|
+
rb_encoding *enc = rb_enc_from_index(enc_idx);
|
|
452
|
+
fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
|
|
453
|
+
if( fname == Qnil ){
|
|
454
|
+
fname = rb_str_new2(cstr);
|
|
455
|
+
PG_ENCODING_SET_NOCHECK(fname, enc_idx);
|
|
456
|
+
fname = rb_str_intern(fname);
|
|
457
|
+
}
|
|
458
|
+
} else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
|
459
|
+
#endif
|
|
460
|
+
rb_encoding *enc = rb_enc_from_index(enc_idx);
|
|
461
|
+
fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
|
|
462
|
+
} else {
|
|
463
|
+
fname = rb_str_new2(cstr);
|
|
464
|
+
PG_ENCODING_SET_NOCHECK(fname, enc_idx);
|
|
465
|
+
fname = rb_obj_freeze(fname);
|
|
466
|
+
}
|
|
467
|
+
return fname;
|
|
394
468
|
}
|
|
395
469
|
|
|
396
470
|
static void pgresult_init_fnames(VALUE self)
|
|
@@ -402,12 +476,9 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
402
476
|
int nfields = PQnfields(this->pgresult);
|
|
403
477
|
|
|
404
478
|
for( i=0; i<nfields; i++ ){
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
this->fnames[i] = rb_obj_freeze(fname);
|
|
479
|
+
char *cfname = PQfname(this->pgresult, i);
|
|
480
|
+
this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
|
|
408
481
|
this->nfields = i + 1;
|
|
409
|
-
|
|
410
|
-
RB_GC_GUARD(fname);
|
|
411
482
|
}
|
|
412
483
|
this->nfields = nfields;
|
|
413
484
|
}
|
|
@@ -419,6 +490,8 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
419
490
|
*
|
|
420
491
|
* The class to represent the query result tuples (rows).
|
|
421
492
|
* An instance of this class is created as the result of every query.
|
|
493
|
+
* All result rows and columns are stored in a memory block attached to the PG::Result object.
|
|
494
|
+
* Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
|
|
422
495
|
*
|
|
423
496
|
* Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
|
|
424
497
|
* You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
|
|
@@ -451,6 +524,9 @@ static void pgresult_init_fnames(VALUE self)
|
|
|
451
524
|
* * +PGRES_NONFATAL_ERROR+
|
|
452
525
|
* * +PGRES_FATAL_ERROR+
|
|
453
526
|
* * +PGRES_COPY_BOTH+
|
|
527
|
+
* * +PGRES_SINGLE_TUPLE+
|
|
528
|
+
* * +PGRES_PIPELINE_SYNC+
|
|
529
|
+
* * +PGRES_PIPELINE_ABORTED+
|
|
454
530
|
*/
|
|
455
531
|
static VALUE
|
|
456
532
|
pgresult_result_status(VALUE self)
|
|
@@ -462,14 +538,15 @@ pgresult_result_status(VALUE self)
|
|
|
462
538
|
* call-seq:
|
|
463
539
|
* res.res_status( status ) -> String
|
|
464
540
|
*
|
|
465
|
-
* Returns the string representation of
|
|
541
|
+
* Returns the string representation of +status+.
|
|
466
542
|
*
|
|
467
543
|
*/
|
|
468
544
|
static VALUE
|
|
469
545
|
pgresult_res_status(VALUE self, VALUE status)
|
|
470
546
|
{
|
|
471
|
-
|
|
472
|
-
|
|
547
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
548
|
+
VALUE ret = rb_str_new2(PQresStatus(NUM2INT(status)));
|
|
549
|
+
PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
|
|
473
550
|
return ret;
|
|
474
551
|
}
|
|
475
552
|
|
|
@@ -482,11 +559,40 @@ pgresult_res_status(VALUE self, VALUE status)
|
|
|
482
559
|
static VALUE
|
|
483
560
|
pgresult_error_message(VALUE self)
|
|
484
561
|
{
|
|
485
|
-
|
|
486
|
-
|
|
562
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
563
|
+
VALUE ret = rb_str_new2(PQresultErrorMessage(this->pgresult));
|
|
564
|
+
PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
|
|
487
565
|
return ret;
|
|
488
566
|
}
|
|
489
567
|
|
|
568
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
569
|
+
/*
|
|
570
|
+
* call-seq:
|
|
571
|
+
* res.verbose_error_message( verbosity, show_context ) -> String
|
|
572
|
+
*
|
|
573
|
+
* Returns a reformatted version of the error message associated with a PGresult object.
|
|
574
|
+
*
|
|
575
|
+
* Available since PostgreSQL-9.6
|
|
576
|
+
*/
|
|
577
|
+
static VALUE
|
|
578
|
+
pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
|
|
579
|
+
{
|
|
580
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
581
|
+
VALUE ret;
|
|
582
|
+
char *c_str;
|
|
583
|
+
|
|
584
|
+
c_str = PQresultVerboseErrorMessage(this->pgresult, NUM2INT(verbosity), NUM2INT(show_context));
|
|
585
|
+
if(!c_str)
|
|
586
|
+
rb_raise(rb_eNoMemError, "insufficient memory to format error message");
|
|
587
|
+
|
|
588
|
+
ret = rb_str_new2(c_str);
|
|
589
|
+
PQfreemem(c_str);
|
|
590
|
+
PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
|
|
591
|
+
|
|
592
|
+
return ret;
|
|
593
|
+
}
|
|
594
|
+
#endif
|
|
595
|
+
|
|
490
596
|
/*
|
|
491
597
|
* call-seq:
|
|
492
598
|
* res.error_field(fieldcode) -> String
|
|
@@ -536,14 +642,14 @@ pgresult_error_message(VALUE self)
|
|
|
536
642
|
static VALUE
|
|
537
643
|
pgresult_error_field(VALUE self, VALUE field)
|
|
538
644
|
{
|
|
539
|
-
|
|
645
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
540
646
|
int fieldcode = NUM2INT( field );
|
|
541
|
-
char * fieldstr = PQresultErrorField(
|
|
647
|
+
char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
|
|
542
648
|
VALUE ret = Qnil;
|
|
543
649
|
|
|
544
650
|
if ( fieldstr ) {
|
|
545
|
-
ret =
|
|
546
|
-
PG_ENCODING_SET_NOCHECK( ret,
|
|
651
|
+
ret = rb_str_new2( fieldstr );
|
|
652
|
+
PG_ENCODING_SET_NOCHECK( ret, this->enc_idx );
|
|
547
653
|
}
|
|
548
654
|
|
|
549
655
|
return ret;
|
|
@@ -581,24 +687,25 @@ pgresult_nfields(VALUE self)
|
|
|
581
687
|
|
|
582
688
|
/*
|
|
583
689
|
* call-seq:
|
|
584
|
-
* res.fname( index ) -> String
|
|
690
|
+
* res.fname( index ) -> String or Symbol
|
|
585
691
|
*
|
|
586
692
|
* Returns the name of the column corresponding to _index_.
|
|
693
|
+
* Depending on #field_name_type= it's a String or Symbol.
|
|
694
|
+
*
|
|
587
695
|
*/
|
|
588
696
|
static VALUE
|
|
589
697
|
pgresult_fname(VALUE self, VALUE index)
|
|
590
698
|
{
|
|
591
|
-
|
|
592
|
-
PGresult *result = pgresult_get(self);
|
|
699
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
593
700
|
int i = NUM2INT(index);
|
|
701
|
+
char *cfname;
|
|
594
702
|
|
|
595
|
-
if (i < 0 || i >= PQnfields(
|
|
703
|
+
if (i < 0 || i >= PQnfields(this->pgresult)) {
|
|
596
704
|
rb_raise(rb_eArgError,"invalid field number %d", i);
|
|
597
705
|
}
|
|
598
706
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
return rb_obj_freeze(fname);
|
|
707
|
+
cfname = PQfname(this->pgresult, i);
|
|
708
|
+
return pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
|
|
602
709
|
}
|
|
603
710
|
|
|
604
711
|
/*
|
|
@@ -897,8 +1004,9 @@ pgresult_paramtype(VALUE self, VALUE param_number)
|
|
|
897
1004
|
static VALUE
|
|
898
1005
|
pgresult_cmd_status(VALUE self)
|
|
899
1006
|
{
|
|
900
|
-
|
|
901
|
-
|
|
1007
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
1008
|
+
VALUE ret = rb_str_new2(PQcmdStatus(this->pgresult));
|
|
1009
|
+
PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
|
|
902
1010
|
return ret;
|
|
903
1011
|
}
|
|
904
1012
|
|
|
@@ -927,7 +1035,7 @@ pgresult_cmd_tuples(VALUE self)
|
|
|
927
1035
|
{
|
|
928
1036
|
long n;
|
|
929
1037
|
n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
|
|
930
|
-
return
|
|
1038
|
+
return LONG2NUM(n);
|
|
931
1039
|
}
|
|
932
1040
|
|
|
933
1041
|
/*
|
|
@@ -1098,8 +1206,12 @@ static VALUE
|
|
|
1098
1206
|
pgresult_field_values( VALUE self, VALUE field )
|
|
1099
1207
|
{
|
|
1100
1208
|
PGresult *result = pgresult_get( self );
|
|
1101
|
-
const char *fieldname
|
|
1102
|
-
int fnum
|
|
1209
|
+
const char *fieldname;
|
|
1210
|
+
int fnum;
|
|
1211
|
+
|
|
1212
|
+
if( RB_TYPE_P(field, T_SYMBOL) ) field = rb_sym_to_s( field );
|
|
1213
|
+
fieldname = StringValueCStr( field );
|
|
1214
|
+
fnum = PQfnumber( result, fieldname );
|
|
1103
1215
|
|
|
1104
1216
|
if ( fnum < 0 )
|
|
1105
1217
|
rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
|
|
@@ -1142,6 +1254,25 @@ pgresult_tuple_values(VALUE self, VALUE index)
|
|
|
1142
1254
|
}
|
|
1143
1255
|
}
|
|
1144
1256
|
|
|
1257
|
+
static void ensure_init_for_tuple(VALUE self)
|
|
1258
|
+
{
|
|
1259
|
+
t_pg_result *this = pgresult_get_this_safe(self);
|
|
1260
|
+
|
|
1261
|
+
if( this->field_map == Qnil ){
|
|
1262
|
+
int i;
|
|
1263
|
+
VALUE field_map = rb_hash_new();
|
|
1264
|
+
|
|
1265
|
+
if( this->nfields == -1 )
|
|
1266
|
+
pgresult_init_fnames( self );
|
|
1267
|
+
|
|
1268
|
+
for( i = 0; i < this->nfields; i++ ){
|
|
1269
|
+
rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
|
|
1270
|
+
}
|
|
1271
|
+
rb_obj_freeze(field_map);
|
|
1272
|
+
this->field_map = field_map;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1145
1276
|
/*
|
|
1146
1277
|
* call-seq:
|
|
1147
1278
|
* res.tuple( n ) -> PG::Tuple
|
|
@@ -1162,19 +1293,7 @@ pgresult_tuple(VALUE self, VALUE index)
|
|
|
1162
1293
|
if ( tuple_num < 0 || tuple_num >= num_tuples )
|
|
1163
1294
|
rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
|
|
1164
1295
|
|
|
1165
|
-
|
|
1166
|
-
int i;
|
|
1167
|
-
VALUE field_map = rb_hash_new();
|
|
1168
|
-
|
|
1169
|
-
if( this->nfields == -1 )
|
|
1170
|
-
pgresult_init_fnames( self );
|
|
1171
|
-
|
|
1172
|
-
for( i = 0; i < this->nfields; i++ ){
|
|
1173
|
-
rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
|
|
1174
|
-
}
|
|
1175
|
-
rb_obj_freeze(field_map);
|
|
1176
|
-
this->field_map = field_map;
|
|
1177
|
-
}
|
|
1296
|
+
ensure_init_for_tuple(self);
|
|
1178
1297
|
|
|
1179
1298
|
return pg_tuple_new(self, tuple_num);
|
|
1180
1299
|
}
|
|
@@ -1206,7 +1325,7 @@ pgresult_each(VALUE self)
|
|
|
1206
1325
|
* call-seq:
|
|
1207
1326
|
* res.fields() -> Array
|
|
1208
1327
|
*
|
|
1209
|
-
*
|
|
1328
|
+
* Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
|
|
1210
1329
|
*/
|
|
1211
1330
|
static VALUE
|
|
1212
1331
|
pgresult_fields(VALUE self)
|
|
@@ -1238,14 +1357,11 @@ pgresult_type_map_set(VALUE self, VALUE typemap)
|
|
|
1238
1357
|
t_pg_result *this = pgresult_get_this(self);
|
|
1239
1358
|
t_typemap *p_typemap;
|
|
1240
1359
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
rb_obj_classname( typemap ) );
|
|
1244
|
-
}
|
|
1245
|
-
Data_Get_Struct(typemap, t_typemap, p_typemap);
|
|
1360
|
+
/* Check type of method param */
|
|
1361
|
+
TypedData_Get_Struct(typemap, t_typemap, &pg_typemap_type, p_typemap);
|
|
1246
1362
|
|
|
1247
1363
|
this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
|
|
1248
|
-
this->p_typemap =
|
|
1364
|
+
this->p_typemap = RTYPEDDATA_DATA( this->typemap );
|
|
1249
1365
|
|
|
1250
1366
|
return typemap;
|
|
1251
1367
|
}
|
|
@@ -1267,7 +1383,7 @@ pgresult_type_map_get(VALUE self)
|
|
|
1267
1383
|
|
|
1268
1384
|
|
|
1269
1385
|
static void
|
|
1270
|
-
yield_hash(VALUE self, int ntuples, int nfields)
|
|
1386
|
+
yield_hash(VALUE self, int ntuples, int nfields, void *data)
|
|
1271
1387
|
{
|
|
1272
1388
|
int tuple_num;
|
|
1273
1389
|
t_pg_result *this = pgresult_get_this(self);
|
|
@@ -1281,7 +1397,7 @@ yield_hash(VALUE self, int ntuples, int nfields)
|
|
|
1281
1397
|
}
|
|
1282
1398
|
|
|
1283
1399
|
static void
|
|
1284
|
-
yield_array(VALUE self, int ntuples, int nfields)
|
|
1400
|
+
yield_array(VALUE self, int ntuples, int nfields, void *data)
|
|
1285
1401
|
{
|
|
1286
1402
|
int row;
|
|
1287
1403
|
t_pg_result *this = pgresult_get_this(self);
|
|
@@ -1301,21 +1417,28 @@ yield_array(VALUE self, int ntuples, int nfields)
|
|
|
1301
1417
|
}
|
|
1302
1418
|
|
|
1303
1419
|
static void
|
|
1304
|
-
yield_tuple(VALUE self, int ntuples, int nfields)
|
|
1420
|
+
yield_tuple(VALUE self, int ntuples, int nfields, void *data)
|
|
1305
1421
|
{
|
|
1306
1422
|
int tuple_num;
|
|
1307
1423
|
t_pg_result *this = pgresult_get_this(self);
|
|
1308
|
-
VALUE
|
|
1424
|
+
VALUE copy;
|
|
1309
1425
|
UNUSED(nfields);
|
|
1310
1426
|
|
|
1427
|
+
/* make a copy of the base result, that is bound to the PG::Tuple */
|
|
1428
|
+
copy = pg_copy_result(this);
|
|
1429
|
+
/* The copy is now owner of the PGresult and is responsible to PQclear it.
|
|
1430
|
+
* We clear the pgresult here, so that it's not double freed on error within yield. */
|
|
1431
|
+
this->pgresult = NULL;
|
|
1432
|
+
|
|
1311
1433
|
for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
|
|
1312
|
-
VALUE tuple = pgresult_tuple(
|
|
1434
|
+
VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
|
|
1313
1435
|
rb_yield( tuple );
|
|
1314
1436
|
}
|
|
1315
1437
|
}
|
|
1316
1438
|
|
|
1317
|
-
static
|
|
1318
|
-
|
|
1439
|
+
/* Non-static, and data pointer for use by sequel_pg */
|
|
1440
|
+
VALUE
|
|
1441
|
+
pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int, void*), void* data)
|
|
1319
1442
|
{
|
|
1320
1443
|
t_pg_result *this;
|
|
1321
1444
|
int nfields;
|
|
@@ -1334,6 +1457,7 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
|
1334
1457
|
|
|
1335
1458
|
switch( PQresultStatus(pgresult) ){
|
|
1336
1459
|
case PGRES_TUPLES_OK:
|
|
1460
|
+
case PGRES_COMMAND_OK:
|
|
1337
1461
|
if( ntuples == 0 )
|
|
1338
1462
|
return self;
|
|
1339
1463
|
rb_raise( rb_eInvalidResultStatus, "PG::Result is not in single row mode");
|
|
@@ -1343,14 +1467,19 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
|
1343
1467
|
pg_result_check( self );
|
|
1344
1468
|
}
|
|
1345
1469
|
|
|
1346
|
-
yielder( self, ntuples, nfields );
|
|
1470
|
+
yielder( self, ntuples, nfields, data );
|
|
1471
|
+
|
|
1472
|
+
if( gvl_PQisBusy(pgconn) ){
|
|
1473
|
+
/* wait for input (without blocking) before reading each result */
|
|
1474
|
+
pgconn_block( 0, NULL, this->connection );
|
|
1475
|
+
}
|
|
1347
1476
|
|
|
1348
1477
|
pgresult = gvl_PQgetResult(pgconn);
|
|
1349
1478
|
if( pgresult == NULL )
|
|
1350
|
-
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another
|
|
1479
|
+
rb_raise( rb_eNoResultError, "no result received - possibly an intersection with another query");
|
|
1351
1480
|
|
|
1352
1481
|
if( nfields != PQnfields(pgresult) )
|
|
1353
|
-
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields
|
|
1482
|
+
rb_raise( rb_eInvalidChangeOfResultFields, "number of fields changed in single row mode from %d to %d - this is a sign for intersection with another query", nfields, PQnfields(pgresult));
|
|
1354
1483
|
|
|
1355
1484
|
this->pgresult = pgresult;
|
|
1356
1485
|
}
|
|
@@ -1390,13 +1519,11 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int))
|
|
|
1390
1519
|
* # do something with each received row of the second query
|
|
1391
1520
|
* end
|
|
1392
1521
|
* conn.get_result # => nil (no more results)
|
|
1393
|
-
*
|
|
1394
|
-
* Available since PostgreSQL-9.2
|
|
1395
1522
|
*/
|
|
1396
1523
|
static VALUE
|
|
1397
1524
|
pgresult_stream_each(VALUE self)
|
|
1398
1525
|
{
|
|
1399
|
-
return pgresult_stream_any(self, yield_hash);
|
|
1526
|
+
return pgresult_stream_any(self, yield_hash, NULL);
|
|
1400
1527
|
}
|
|
1401
1528
|
|
|
1402
1529
|
/*
|
|
@@ -1408,13 +1535,11 @@ pgresult_stream_each(VALUE self)
|
|
|
1408
1535
|
*
|
|
1409
1536
|
* This method works equally to #stream_each , but yields an Array of
|
|
1410
1537
|
* values.
|
|
1411
|
-
*
|
|
1412
|
-
* Available since PostgreSQL-9.2
|
|
1413
1538
|
*/
|
|
1414
1539
|
static VALUE
|
|
1415
1540
|
pgresult_stream_each_row(VALUE self)
|
|
1416
1541
|
{
|
|
1417
|
-
return pgresult_stream_any(self, yield_array);
|
|
1542
|
+
return pgresult_stream_any(self, yield_array, NULL);
|
|
1418
1543
|
}
|
|
1419
1544
|
|
|
1420
1545
|
/*
|
|
@@ -1424,21 +1549,82 @@ pgresult_stream_each_row(VALUE self)
|
|
|
1424
1549
|
* Yields each row of the result set in single row mode.
|
|
1425
1550
|
*
|
|
1426
1551
|
* This method works equally to #stream_each , but yields a PG::Tuple object.
|
|
1427
|
-
*
|
|
1428
|
-
* Available since PostgreSQL-9.2
|
|
1429
1552
|
*/
|
|
1430
1553
|
static VALUE
|
|
1431
1554
|
pgresult_stream_each_tuple(VALUE self)
|
|
1432
1555
|
{
|
|
1433
|
-
|
|
1556
|
+
/* allocate VALUEs that are shared between all streamed tuples */
|
|
1557
|
+
ensure_init_for_tuple(self);
|
|
1558
|
+
|
|
1559
|
+
return pgresult_stream_any(self, yield_tuple, NULL);
|
|
1434
1560
|
}
|
|
1435
1561
|
|
|
1562
|
+
/*
|
|
1563
|
+
* call-seq:
|
|
1564
|
+
* res.field_name_type = Symbol
|
|
1565
|
+
*
|
|
1566
|
+
* Set type of field names specific to this result.
|
|
1567
|
+
* It can be set to one of:
|
|
1568
|
+
* * +:string+ to use String based field names
|
|
1569
|
+
* * +:symbol+ to use Symbol based field names
|
|
1570
|
+
* * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably be removed in future.
|
|
1571
|
+
*
|
|
1572
|
+
* The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
|
|
1573
|
+
*
|
|
1574
|
+
* This setting affects several result methods:
|
|
1575
|
+
* * keys of Hash returned by #[] , #each and #stream_each
|
|
1576
|
+
* * #fields
|
|
1577
|
+
* * #fname
|
|
1578
|
+
* * field names used by #tuple and #stream_each_tuple
|
|
1579
|
+
*
|
|
1580
|
+
* The type of field names can only be changed before any of the affected methods have been called.
|
|
1581
|
+
*
|
|
1582
|
+
*/
|
|
1583
|
+
static VALUE
|
|
1584
|
+
pgresult_field_name_type_set(VALUE self, VALUE sym)
|
|
1585
|
+
{
|
|
1586
|
+
t_pg_result *this = pgresult_get_this(self);
|
|
1587
|
+
if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
|
|
1588
|
+
|
|
1589
|
+
this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
|
|
1590
|
+
if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
|
|
1591
|
+
else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
|
|
1592
|
+
else if ( sym == sym_string );
|
|
1593
|
+
else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
|
|
1594
|
+
|
|
1595
|
+
return sym;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
/*
|
|
1599
|
+
* call-seq:
|
|
1600
|
+
* res.field_name_type -> Symbol
|
|
1601
|
+
*
|
|
1602
|
+
* Get type of field names.
|
|
1603
|
+
*
|
|
1604
|
+
* See description at #field_name_type=
|
|
1605
|
+
*/
|
|
1606
|
+
static VALUE
|
|
1607
|
+
pgresult_field_name_type_get(VALUE self)
|
|
1608
|
+
{
|
|
1609
|
+
t_pg_result *this = pgresult_get_this(self);
|
|
1610
|
+
if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
|
|
1611
|
+
return sym_symbol;
|
|
1612
|
+
} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
|
|
1613
|
+
return sym_static_symbol;
|
|
1614
|
+
} else {
|
|
1615
|
+
return sym_string;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1436
1618
|
|
|
1437
1619
|
void
|
|
1438
1620
|
init_pg_result()
|
|
1439
1621
|
{
|
|
1622
|
+
sym_string = ID2SYM(rb_intern("string"));
|
|
1623
|
+
sym_symbol = ID2SYM(rb_intern("symbol"));
|
|
1624
|
+
sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
|
|
1625
|
+
|
|
1440
1626
|
rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
|
|
1441
|
-
|
|
1627
|
+
rb_undef_alloc_func(rb_cPGresult);
|
|
1442
1628
|
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
|
1443
1629
|
rb_include_module(rb_cPGresult, rb_mPGconstants);
|
|
1444
1630
|
|
|
@@ -1447,6 +1633,10 @@ init_pg_result()
|
|
|
1447
1633
|
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
|
|
1448
1634
|
rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
|
|
1449
1635
|
rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
|
|
1636
|
+
#ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
|
|
1637
|
+
rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
|
|
1638
|
+
rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
|
|
1639
|
+
#endif
|
|
1450
1640
|
rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
|
|
1451
1641
|
rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
|
|
1452
1642
|
rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
|
|
@@ -1494,6 +1684,7 @@ init_pg_result()
|
|
|
1494
1684
|
rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
|
|
1495
1685
|
rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
|
|
1496
1686
|
rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
1687
|
|
|
1688
|
+
rb_define_method(rb_cPGresult, "field_name_type=", pgresult_field_name_type_set, 1 );
|
|
1689
|
+
rb_define_method(rb_cPGresult, "field_name_type", pgresult_field_name_type_get, 0 );
|
|
1690
|
+
}
|