pg 0.15.0.pre.454-x64-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.gemtest +0 -0
  3. data/BSDL +22 -0
  4. data/ChangeLog +2945 -0
  5. data/Contributors.rdoc +46 -0
  6. data/History.rdoc +205 -0
  7. data/LICENSE +56 -0
  8. data/Manifest.txt +53 -0
  9. data/POSTGRES +23 -0
  10. data/README-OS_X.rdoc +68 -0
  11. data/README-Windows.rdoc +67 -0
  12. data/README.ja.rdoc +14 -0
  13. data/README.rdoc +111 -0
  14. data/Rakefile +156 -0
  15. data/Rakefile.cross +271 -0
  16. data/ext/extconf.rb +91 -0
  17. data/ext/gvl_wrappers.c +13 -0
  18. data/ext/gvl_wrappers.h +185 -0
  19. data/ext/pg.c +525 -0
  20. data/ext/pg.h +126 -0
  21. data/ext/pg_connection.c +3600 -0
  22. data/ext/pg_result.c +939 -0
  23. data/ext/vc/pg.sln +26 -0
  24. data/ext/vc/pg_18/pg.vcproj +216 -0
  25. data/ext/vc/pg_19/pg_19.vcproj +209 -0
  26. data/lib/2.0/pg_ext.so +0 -0
  27. data/lib/pg.rb +52 -0
  28. data/lib/pg/connection.rb +71 -0
  29. data/lib/pg/constants.rb +11 -0
  30. data/lib/pg/exceptions.rb +11 -0
  31. data/lib/pg/result.rb +16 -0
  32. data/sample/array_insert.rb +20 -0
  33. data/sample/async_api.rb +106 -0
  34. data/sample/async_copyto.rb +39 -0
  35. data/sample/async_mixed.rb +56 -0
  36. data/sample/check_conn.rb +21 -0
  37. data/sample/copyfrom.rb +81 -0
  38. data/sample/copyto.rb +19 -0
  39. data/sample/cursor.rb +21 -0
  40. data/sample/disk_usage_report.rb +186 -0
  41. data/sample/issue-119.rb +94 -0
  42. data/sample/losample.rb +69 -0
  43. data/sample/minimal-testcase.rb +17 -0
  44. data/sample/notify_wait.rb +72 -0
  45. data/sample/pg_statistics.rb +294 -0
  46. data/sample/replication_monitor.rb +231 -0
  47. data/sample/test_binary_values.rb +33 -0
  48. data/sample/wal_shipper.rb +434 -0
  49. data/sample/warehouse_partitions.rb +320 -0
  50. data/spec/data/expected_trace.out +26 -0
  51. data/spec/data/random_binary_data +0 -0
  52. data/spec/lib/helpers.rb +279 -0
  53. data/spec/pg/connection_spec.rb +1013 -0
  54. data/spec/pg/result_spec.rb +278 -0
  55. data/spec/pg_spec.rb +31 -0
  56. metadata +275 -0
  57. metadata.gz.sig +0 -0
@@ -0,0 +1,939 @@
1
+ /*
2
+ * pg_result.c - PG::Result class extension
3
+ * $Id$
4
+ *
5
+ */
6
+
7
+ #include "pg.h"
8
+
9
+
10
+ VALUE rb_cPGresult;
11
+
12
+ static void pgresult_gc_free( PGresult * );
13
+ static PGresult* pgresult_get( VALUE );
14
+
15
+
16
+ /*
17
+ * Global functions
18
+ */
19
+
20
+ /*
21
+ * Result constructor
22
+ */
23
+ VALUE
24
+ pg_new_result(PGresult *result, VALUE rb_pgconn)
25
+ {
26
+ PGconn *conn = pg_get_pgconn( rb_pgconn );
27
+ VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, pgresult_gc_free, result);
28
+ #ifdef M17N_SUPPORTED
29
+ rb_encoding *enc = pg_conn_enc_get( conn );
30
+ ENCODING_SET( val, rb_enc_to_index(enc) );
31
+ #endif
32
+
33
+ rb_iv_set( val, "@connection", rb_pgconn );
34
+
35
+ return val;
36
+ }
37
+
38
+ /*
39
+ * call-seq:
40
+ * res.check -> nil
41
+ *
42
+ * Raises appropriate exception if PG::Result is in a bad state.
43
+ */
44
+ VALUE
45
+ pg_result_check( VALUE self )
46
+ {
47
+ VALUE error, exception;
48
+ VALUE rb_pgconn = rb_iv_get( self, "@connection" );
49
+ PGconn *conn = pg_get_pgconn(rb_pgconn);
50
+ PGresult *result;
51
+ #ifdef M17N_SUPPORTED
52
+ rb_encoding *enc = pg_conn_enc_get( conn );
53
+ #endif
54
+
55
+ Data_Get_Struct(self, PGresult, result);
56
+
57
+ if(result == NULL)
58
+ {
59
+ error = rb_str_new2( PQerrorMessage(conn) );
60
+ }
61
+ else
62
+ {
63
+ switch (PQresultStatus(result))
64
+ {
65
+ case PGRES_TUPLES_OK:
66
+ case PGRES_COPY_OUT:
67
+ case PGRES_COPY_IN:
68
+ #ifdef HAVE_CONST_PGRES_COPY_BOTH
69
+ case PGRES_COPY_BOTH:
70
+ #endif
71
+ #ifdef HAVE_CONST_PGRES_SINGLE_TUPLE
72
+ case PGRES_SINGLE_TUPLE:
73
+ #endif
74
+ case PGRES_EMPTY_QUERY:
75
+ case PGRES_COMMAND_OK:
76
+ return Qnil;
77
+ case PGRES_BAD_RESPONSE:
78
+ case PGRES_FATAL_ERROR:
79
+ case PGRES_NONFATAL_ERROR:
80
+ error = rb_str_new2( PQresultErrorMessage(result) );
81
+ break;
82
+ default:
83
+ error = rb_str_new2( "internal error : unknown result status." );
84
+ }
85
+ }
86
+
87
+ #ifdef M17N_SUPPORTED
88
+ rb_enc_set_index( error, rb_enc_to_index(enc) );
89
+ #endif
90
+ exception = rb_exc_new3( rb_ePGerror, error );
91
+ rb_iv_set( exception, "@connection", rb_pgconn );
92
+ rb_iv_set( exception, "@result", self );
93
+ rb_exc_raise( exception );
94
+
95
+ /* Not reached */
96
+ return Qnil;
97
+ }
98
+
99
+
100
+ /*
101
+ * :TODO: This shouldn't be a global function, but it needs to be as long as pg_new_result
102
+ * doesn't handle blocks, check results, etc. Once connection and result are disentangled
103
+ * a bit more, I can make this a static pgresult_clear() again.
104
+ */
105
+
106
+ /*
107
+ * call-seq:
108
+ * res.clear() -> nil
109
+ *
110
+ * Clears the PG::Result object as the result of the query.
111
+ */
112
+ VALUE
113
+ pg_result_clear(VALUE self)
114
+ {
115
+ PQclear(pgresult_get(self));
116
+ DATA_PTR(self) = NULL;
117
+ return Qnil;
118
+ }
119
+
120
+
121
+
122
+ /*
123
+ * DATA pointer functions
124
+ */
125
+
126
+ /*
127
+ * GC Free function
128
+ */
129
+ static void
130
+ pgresult_gc_free( PGresult *result )
131
+ {
132
+ if(result != NULL)
133
+ PQclear(result);
134
+ }
135
+
136
+ /*
137
+ * Fetch the data pointer for the result object
138
+ */
139
+ static PGresult*
140
+ pgresult_get(VALUE self)
141
+ {
142
+ PGresult *result;
143
+ Data_Get_Struct(self, PGresult, result);
144
+ if (result == NULL) rb_raise(rb_ePGerror, "result has been cleared");
145
+ return result;
146
+ }
147
+
148
+
149
+ /********************************************************************
150
+ *
151
+ * Document-class: PG::Result
152
+ *
153
+ * The class to represent the query result tuples (rows).
154
+ * An instance of this class is created as the result of every query.
155
+ * You may need to invoke the #clear method of the instance when finished with
156
+ * the result for better memory performance.
157
+ *
158
+ * Example:
159
+ * require 'pg'
160
+ * conn = PGconn.open(:dbname => 'test')
161
+ * res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
162
+ * res.getvalue(0,0) # '1'
163
+ * res[0]['b'] # '2'
164
+ * res[0]['c'] # nil
165
+ *
166
+ */
167
+
168
+ /**************************************************************************
169
+ * PG::Result INSTANCE METHODS
170
+ **************************************************************************/
171
+
172
+ /*
173
+ * call-seq:
174
+ * res.result_status() -> Fixnum
175
+ *
176
+ * Returns the status of the query. The status value is one of:
177
+ * * +PGRES_EMPTY_QUERY+
178
+ * * +PGRES_COMMAND_OK+
179
+ * * +PGRES_TUPLES_OK+
180
+ * * +PGRES_COPY_OUT+
181
+ * * +PGRES_COPY_IN+
182
+ * * +PGRES_BAD_RESPONSE+
183
+ * * +PGRES_NONFATAL_ERROR+
184
+ * * +PGRES_FATAL_ERROR+
185
+ * * +PGRES_COPY_BOTH+
186
+ */
187
+ static VALUE
188
+ pgresult_result_status(VALUE self)
189
+ {
190
+ return INT2FIX(PQresultStatus(pgresult_get(self)));
191
+ }
192
+
193
+ /*
194
+ * call-seq:
195
+ * res.res_status( status ) -> String
196
+ *
197
+ * Returns the string representation of status +status+.
198
+ *
199
+ */
200
+ static VALUE
201
+ pgresult_res_status(VALUE self, VALUE status)
202
+ {
203
+ VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
204
+ ASSOCIATE_INDEX(ret, self);
205
+ return ret;
206
+ }
207
+
208
+ /*
209
+ * call-seq:
210
+ * res.error_message() -> String
211
+ *
212
+ * Returns the error message of the command as a string.
213
+ */
214
+ static VALUE
215
+ pgresult_error_message(VALUE self)
216
+ {
217
+ VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(pgresult_get(self)));
218
+ ASSOCIATE_INDEX(ret, self);
219
+ return ret;
220
+ }
221
+
222
+ /*
223
+ * call-seq:
224
+ * res.error_field(fieldcode) -> String
225
+ *
226
+ * Returns the individual field of an error.
227
+ *
228
+ * +fieldcode+ is one of:
229
+ * * +PG_DIAG_SEVERITY+
230
+ * * +PG_DIAG_SQLSTATE+
231
+ * * +PG_DIAG_MESSAGE_PRIMARY+
232
+ * * +PG_DIAG_MESSAGE_DETAIL+
233
+ * * +PG_DIAG_MESSAGE_HINT+
234
+ * * +PG_DIAG_STATEMENT_POSITION+
235
+ * * +PG_DIAG_INTERNAL_POSITION+
236
+ * * +PG_DIAG_INTERNAL_QUERY+
237
+ * * +PG_DIAG_CONTEXT+
238
+ * * +PG_DIAG_SOURCE_FILE+
239
+ * * +PG_DIAG_SOURCE_LINE+
240
+ * * +PG_DIAG_SOURCE_FUNCTION+
241
+ *
242
+ * An example:
243
+ *
244
+ * begin
245
+ * conn.exec( "SELECT * FROM nonexistant_table" )
246
+ * rescue PG::Error => err
247
+ * p [
248
+ * result.error_field( PG::Result::PG_DIAG_SEVERITY ),
249
+ * result.error_field( PG::Result::PG_DIAG_SQLSTATE ),
250
+ * result.error_field( PG::Result::PG_DIAG_MESSAGE_PRIMARY ),
251
+ * result.error_field( PG::Result::PG_DIAG_MESSAGE_DETAIL ),
252
+ * result.error_field( PG::Result::PG_DIAG_MESSAGE_HINT ),
253
+ * result.error_field( PG::Result::PG_DIAG_STATEMENT_POSITION ),
254
+ * result.error_field( PG::Result::PG_DIAG_INTERNAL_POSITION ),
255
+ * result.error_field( PG::Result::PG_DIAG_INTERNAL_QUERY ),
256
+ * result.error_field( PG::Result::PG_DIAG_CONTEXT ),
257
+ * result.error_field( PG::Result::PG_DIAG_SOURCE_FILE ),
258
+ * result.error_field( PG::Result::PG_DIAG_SOURCE_LINE ),
259
+ * result.error_field( PG::Result::PG_DIAG_SOURCE_FUNCTION ),
260
+ * ]
261
+ * end
262
+ *
263
+ * Outputs:
264
+ *
265
+ * ["ERROR", "42P01", "relation \"nonexistant_table\" does not exist", nil, nil,
266
+ * "15", nil, nil, nil, "path/to/parse_relation.c", "857", "parserOpenTable"]
267
+ */
268
+ static VALUE
269
+ pgresult_error_field(VALUE self, VALUE field)
270
+ {
271
+ PGresult *result = pgresult_get( self );
272
+ int fieldcode = NUM2INT( field );
273
+ char * fieldstr = PQresultErrorField( result, fieldcode );
274
+ VALUE ret = Qnil;
275
+
276
+ if ( fieldstr ) {
277
+ ret = rb_tainted_str_new2( fieldstr );
278
+ ASSOCIATE_INDEX( ret, self );
279
+ }
280
+
281
+ return ret;
282
+ }
283
+
284
+ /*
285
+ * call-seq:
286
+ * res.ntuples() -> Fixnum
287
+ *
288
+ * Returns the number of tuples in the query result.
289
+ */
290
+ static VALUE
291
+ pgresult_ntuples(VALUE self)
292
+ {
293
+ return INT2FIX(PQntuples(pgresult_get(self)));
294
+ }
295
+
296
+ /*
297
+ * call-seq:
298
+ * res.nfields() -> Fixnum
299
+ *
300
+ * Returns the number of columns in the query result.
301
+ */
302
+ static VALUE
303
+ pgresult_nfields(VALUE self)
304
+ {
305
+ return INT2NUM(PQnfields(pgresult_get(self)));
306
+ }
307
+
308
+ /*
309
+ * call-seq:
310
+ * res.fname( index ) -> String
311
+ *
312
+ * Returns the name of the column corresponding to _index_.
313
+ */
314
+ static VALUE
315
+ pgresult_fname(VALUE self, VALUE index)
316
+ {
317
+ VALUE fname;
318
+ PGresult *result;
319
+ int i = NUM2INT(index);
320
+
321
+ result = pgresult_get(self);
322
+ if (i < 0 || i >= PQnfields(result)) {
323
+ rb_raise(rb_eArgError,"invalid field number %d", i);
324
+ }
325
+ fname = rb_tainted_str_new2(PQfname(result, i));
326
+ ASSOCIATE_INDEX(fname, self);
327
+ return fname;
328
+ }
329
+
330
+ /*
331
+ * call-seq:
332
+ * res.fnumber( name ) -> Fixnum
333
+ *
334
+ * Returns the index of the field specified by the string +name+.
335
+ * The given +name+ is treated like an identifier in an SQL command, that is,
336
+ * it is downcased unless double-quoted. For example, given a query result
337
+ * generated from the SQL command:
338
+ *
339
+ * result = conn.exec( %{SELECT 1 AS FOO, 2 AS "BAR"} )
340
+ *
341
+ * we would have the results:
342
+ *
343
+ * result.fname( 0 ) # => "foo"
344
+ * result.fname( 1 ) # => "BAR"
345
+ * result.fnumber( "FOO" ) # => 0
346
+ * result.fnumber( "foo" ) # => 0
347
+ * result.fnumber( "BAR" ) # => ArgumentError
348
+ * result.fnumber( %{"BAR"} ) # => 1
349
+ *
350
+ * Raises an ArgumentError if the specified +name+ isn't one of the field names;
351
+ * raises a TypeError if +name+ is not a String.
352
+ */
353
+ static VALUE
354
+ pgresult_fnumber(VALUE self, VALUE name)
355
+ {
356
+ int n;
357
+
358
+ Check_Type(name, T_STRING);
359
+
360
+ n = PQfnumber(pgresult_get(self), StringValuePtr(name));
361
+ if (n == -1) {
362
+ rb_raise(rb_eArgError,"Unknown field: %s", StringValuePtr(name));
363
+ }
364
+ return INT2FIX(n);
365
+ }
366
+
367
+ /*
368
+ * call-seq:
369
+ * res.ftable( column_number ) -> Fixnum
370
+ *
371
+ * Returns the Oid of the table from which the column _column_number_
372
+ * was fetched.
373
+ *
374
+ * Raises ArgumentError if _column_number_ is out of range or if
375
+ * the Oid is undefined for that column.
376
+ */
377
+ static VALUE
378
+ pgresult_ftable(VALUE self, VALUE column_number)
379
+ {
380
+ Oid n ;
381
+ int col_number = NUM2INT(column_number);
382
+ PGresult *pgresult = pgresult_get(self);
383
+
384
+ if( col_number < 0 || col_number >= PQnfields(pgresult))
385
+ rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
386
+
387
+ n = PQftable(pgresult, col_number);
388
+ return INT2FIX(n);
389
+ }
390
+
391
+ /*
392
+ * call-seq:
393
+ * res.ftablecol( column_number ) -> Fixnum
394
+ *
395
+ * Returns the column number (within its table) of the table from
396
+ * which the column _column_number_ is made up.
397
+ *
398
+ * Raises ArgumentError if _column_number_ is out of range or if
399
+ * the column number from its table is undefined for that column.
400
+ */
401
+ static VALUE
402
+ pgresult_ftablecol(VALUE self, VALUE column_number)
403
+ {
404
+ int col_number = NUM2INT(column_number);
405
+ PGresult *pgresult = pgresult_get(self);
406
+
407
+ int n;
408
+
409
+ if( col_number < 0 || col_number >= PQnfields(pgresult))
410
+ rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
411
+
412
+ n = PQftablecol(pgresult, col_number);
413
+ return INT2FIX(n);
414
+ }
415
+
416
+ /*
417
+ * call-seq:
418
+ * res.fformat( column_number ) -> Fixnum
419
+ *
420
+ * Returns the format (0 for text, 1 for binary) of column
421
+ * _column_number_.
422
+ *
423
+ * Raises ArgumentError if _column_number_ is out of range.
424
+ */
425
+ static VALUE
426
+ pgresult_fformat(VALUE self, VALUE column_number)
427
+ {
428
+ PGresult *result = pgresult_get(self);
429
+ int fnumber = NUM2INT(column_number);
430
+ if (fnumber < 0 || fnumber >= PQnfields(result)) {
431
+ rb_raise(rb_eArgError, "Column number is out of range: %d",
432
+ fnumber);
433
+ }
434
+ return INT2FIX(PQfformat(result, fnumber));
435
+ }
436
+
437
+ /*
438
+ * call-seq:
439
+ * res.ftype( column_number )
440
+ *
441
+ * Returns the data type associated with _column_number_.
442
+ *
443
+ * The integer returned is the internal +OID+ number (in PostgreSQL)
444
+ * of the type. To get a human-readable value for the type, use the
445
+ * returned OID and the field's #fmod value with the format_type() SQL
446
+ * function:
447
+ *
448
+ * # Get the type of the second column of the result 'res'
449
+ * typename = conn.
450
+ * exec( "SELECT format_type($1,$2)", [res.ftype(1), res.fmod(1)] ).
451
+ * getvalue( 0, 0 )
452
+ *
453
+ * Raises an ArgumentError if _column_number_ is out of range.
454
+ */
455
+ static VALUE
456
+ pgresult_ftype(VALUE self, VALUE index)
457
+ {
458
+ PGresult* result = pgresult_get(self);
459
+ int i = NUM2INT(index);
460
+ if (i < 0 || i >= PQnfields(result)) {
461
+ rb_raise(rb_eArgError, "invalid field number %d", i);
462
+ }
463
+ return INT2NUM(PQftype(result, i));
464
+ }
465
+
466
+ /*
467
+ * call-seq:
468
+ * res.fmod( column_number )
469
+ *
470
+ * Returns the type modifier associated with column _column_number_. See
471
+ * the #ftype method for an example of how to use this.
472
+ *
473
+ * Raises an ArgumentError if _column_number_ is out of range.
474
+ */
475
+ static VALUE
476
+ pgresult_fmod(VALUE self, VALUE column_number)
477
+ {
478
+ PGresult *result = pgresult_get(self);
479
+ int fnumber = NUM2INT(column_number);
480
+ int modifier;
481
+ if (fnumber < 0 || fnumber >= PQnfields(result)) {
482
+ rb_raise(rb_eArgError, "Column number is out of range: %d",
483
+ fnumber);
484
+ }
485
+ modifier = PQfmod(result,fnumber);
486
+
487
+ return INT2NUM(modifier);
488
+ }
489
+
490
+ /*
491
+ * call-seq:
492
+ * res.fsize( index )
493
+ *
494
+ * Returns the size of the field type in bytes. Returns <tt>-1</tt> if the field is variable sized.
495
+ *
496
+ * res = conn.exec("SELECT myInt, myVarChar50 FROM foo")
497
+ * res.size(0) => 4
498
+ * res.size(1) => -1
499
+ */
500
+ static VALUE
501
+ pgresult_fsize(VALUE self, VALUE index)
502
+ {
503
+ PGresult *result;
504
+ int i = NUM2INT(index);
505
+
506
+ result = pgresult_get(self);
507
+ if (i < 0 || i >= PQnfields(result)) {
508
+ rb_raise(rb_eArgError,"invalid field number %d", i);
509
+ }
510
+ return INT2NUM(PQfsize(result, i));
511
+ }
512
+
513
+ /*
514
+ * call-seq:
515
+ * res.getvalue( tup_num, field_num )
516
+ *
517
+ * Returns the value in tuple number _tup_num_, field _field_num_,
518
+ * or +nil+ if the field is +NULL+.
519
+ */
520
+ static VALUE
521
+ pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
522
+ {
523
+ VALUE val;
524
+ PGresult *result;
525
+ int i = NUM2INT(tup_num);
526
+ int j = NUM2INT(field_num);
527
+
528
+ result = pgresult_get(self);
529
+ if(i < 0 || i >= PQntuples(result)) {
530
+ rb_raise(rb_eArgError,"invalid tuple number %d", i);
531
+ }
532
+ if(j < 0 || j >= PQnfields(result)) {
533
+ rb_raise(rb_eArgError,"invalid field number %d", j);
534
+ }
535
+ if(PQgetisnull(result, i, j))
536
+ return Qnil;
537
+ val = rb_tainted_str_new(PQgetvalue(result, i, j),
538
+ PQgetlength(result, i, j));
539
+
540
+ #ifdef M17N_SUPPORTED
541
+ /* associate client encoding for text format only */
542
+ if ( 0 == PQfformat(result, j) ) {
543
+ ASSOCIATE_INDEX( val, self );
544
+ } else {
545
+ rb_enc_associate( val, rb_ascii8bit_encoding() );
546
+ }
547
+ #endif
548
+
549
+ return val;
550
+ }
551
+
552
+ /*
553
+ * call-seq:
554
+ * res.getisnull(tuple_position, field_position) -> boolean
555
+ *
556
+ * Returns +true+ if the specified value is +nil+; +false+ otherwise.
557
+ */
558
+ static VALUE
559
+ pgresult_getisnull(VALUE self, VALUE tup_num, VALUE field_num)
560
+ {
561
+ PGresult *result;
562
+ int i = NUM2INT(tup_num);
563
+ int j = NUM2INT(field_num);
564
+
565
+ result = pgresult_get(self);
566
+ if (i < 0 || i >= PQntuples(result)) {
567
+ rb_raise(rb_eArgError,"invalid tuple number %d", i);
568
+ }
569
+ if (j < 0 || j >= PQnfields(result)) {
570
+ rb_raise(rb_eArgError,"invalid field number %d", j);
571
+ }
572
+ return PQgetisnull(result, i, j) ? Qtrue : Qfalse;
573
+ }
574
+
575
+ /*
576
+ * call-seq:
577
+ * res.getlength( tup_num, field_num ) -> Fixnum
578
+ *
579
+ * Returns the (String) length of the field in bytes.
580
+ *
581
+ * Equivalent to <tt>res.value(<i>tup_num</i>,<i>field_num</i>).length</tt>.
582
+ */
583
+ static VALUE
584
+ pgresult_getlength(VALUE self, VALUE tup_num, VALUE field_num)
585
+ {
586
+ PGresult *result;
587
+ int i = NUM2INT(tup_num);
588
+ int j = NUM2INT(field_num);
589
+
590
+ result = pgresult_get(self);
591
+ if (i < 0 || i >= PQntuples(result)) {
592
+ rb_raise(rb_eArgError,"invalid tuple number %d", i);
593
+ }
594
+ if (j < 0 || j >= PQnfields(result)) {
595
+ rb_raise(rb_eArgError,"invalid field number %d", j);
596
+ }
597
+ return INT2FIX(PQgetlength(result, i, j));
598
+ }
599
+
600
+ /*
601
+ * call-seq:
602
+ * res.nparams() -> Fixnum
603
+ *
604
+ * Returns the number of parameters of a prepared statement.
605
+ * Only useful for the result returned by conn.describePrepared
606
+ */
607
+ static VALUE
608
+ pgresult_nparams(VALUE self)
609
+ {
610
+ PGresult *result;
611
+
612
+ result = pgresult_get(self);
613
+ return INT2FIX(PQnparams(result));
614
+ }
615
+
616
+ /*
617
+ * call-seq:
618
+ * res.paramtype( param_number ) -> Oid
619
+ *
620
+ * Returns the Oid of the data type of parameter _param_number_.
621
+ * Only useful for the result returned by conn.describePrepared
622
+ */
623
+ static VALUE
624
+ pgresult_paramtype(VALUE self, VALUE param_number)
625
+ {
626
+ PGresult *result;
627
+
628
+ result = pgresult_get(self);
629
+ return INT2FIX(PQparamtype(result,NUM2INT(param_number)));
630
+ }
631
+
632
+ /*
633
+ * call-seq:
634
+ * res.cmd_status() -> String
635
+ *
636
+ * Returns the status string of the last query command.
637
+ */
638
+ static VALUE
639
+ pgresult_cmd_status(VALUE self)
640
+ {
641
+ VALUE ret = rb_tainted_str_new2(PQcmdStatus(pgresult_get(self)));
642
+ ASSOCIATE_INDEX(ret, self);
643
+ return ret;
644
+ }
645
+
646
+ /*
647
+ * call-seq:
648
+ * res.cmd_tuples() -> Fixnum
649
+ *
650
+ * Returns the number of tuples (rows) affected by the SQL command.
651
+ *
652
+ * If the SQL command that generated the PG::Result was not one of:
653
+ * * +INSERT+
654
+ * * +UPDATE+
655
+ * * +DELETE+
656
+ * * +MOVE+
657
+ * * +FETCH+
658
+ * or if no tuples were affected, <tt>0</tt> is returned.
659
+ */
660
+ static VALUE
661
+ pgresult_cmd_tuples(VALUE self)
662
+ {
663
+ long n;
664
+ n = strtol(PQcmdTuples(pgresult_get(self)),NULL, 10);
665
+ return INT2NUM(n);
666
+ }
667
+
668
+ /*
669
+ * call-seq:
670
+ * res.oid_value() -> Fixnum
671
+ *
672
+ * Returns the +oid+ of the inserted row if applicable,
673
+ * otherwise +nil+.
674
+ */
675
+ static VALUE
676
+ pgresult_oid_value(VALUE self)
677
+ {
678
+ Oid n = PQoidValue(pgresult_get(self));
679
+ if (n == InvalidOid)
680
+ return Qnil;
681
+ else
682
+ return INT2FIX(n);
683
+ }
684
+
685
+ /* Utility methods not in libpq */
686
+
687
+ /*
688
+ * call-seq:
689
+ * res[ n ] -> Hash
690
+ *
691
+ * Returns tuple _n_ as a hash.
692
+ */
693
+ static VALUE
694
+ pgresult_aref(VALUE self, VALUE index)
695
+ {
696
+ PGresult *result = pgresult_get(self);
697
+ int tuple_num = NUM2INT(index);
698
+ int field_num;
699
+ VALUE fname,val;
700
+ VALUE tuple;
701
+
702
+ if ( tuple_num < 0 || tuple_num >= PQntuples(result) )
703
+ rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
704
+
705
+ tuple = rb_hash_new();
706
+ for ( field_num = 0; field_num < PQnfields(result); field_num++ ) {
707
+ fname = rb_tainted_str_new2( PQfname(result,field_num) );
708
+ ASSOCIATE_INDEX(fname, self);
709
+ if ( PQgetisnull(result, tuple_num, field_num) ) {
710
+ rb_hash_aset( tuple, fname, Qnil );
711
+ }
712
+ else {
713
+ val = rb_tainted_str_new( PQgetvalue(result, tuple_num, field_num ),
714
+ PQgetlength(result, tuple_num, field_num) );
715
+
716
+ #ifdef M17N_SUPPORTED
717
+ /* associate client encoding for text format only */
718
+ if ( 0 == PQfformat(result, field_num) ) {
719
+ ASSOCIATE_INDEX( val, self );
720
+ } else {
721
+ rb_enc_associate( val, rb_ascii8bit_encoding() );
722
+ }
723
+ #endif
724
+
725
+ rb_hash_aset( tuple, fname, val );
726
+ }
727
+ }
728
+ return tuple;
729
+ }
730
+
731
+ /*
732
+ * call-seq:
733
+ * res.each_row { |row| ... }
734
+ *
735
+ * Yields each row of the result. The row is a list of column values.
736
+ */
737
+ static VALUE
738
+ pgresult_each_row(VALUE self)
739
+ {
740
+ PGresult* result = (PGresult*) pgresult_get(self);
741
+ int row;
742
+ int field;
743
+ int num_rows = PQntuples(result);
744
+ int num_fields = PQnfields(result);
745
+
746
+ for ( row = 0; row < num_rows; row++ ) {
747
+ VALUE new_row = rb_ary_new2(num_fields);
748
+
749
+ /* populate the row */
750
+ for ( field = 0; field < num_fields; field++ ) {
751
+ if ( PQgetisnull(result, row, field) ) {
752
+ rb_ary_store( new_row, field, Qnil );
753
+ }
754
+ else {
755
+ VALUE val = rb_tainted_str_new( PQgetvalue(result, row, field),
756
+ PQgetlength(result, row, field) );
757
+
758
+ #ifdef M17N_SUPPORTED
759
+ /* associate client encoding for text format only */
760
+ if ( 0 == PQfformat(result, field) ) {
761
+ ASSOCIATE_INDEX( val, self );
762
+ } else {
763
+ rb_enc_associate( val, rb_ascii8bit_encoding() );
764
+ }
765
+ #endif
766
+ rb_ary_store( new_row, field, val );
767
+ }
768
+ }
769
+ rb_yield( new_row );
770
+ }
771
+
772
+ return Qnil;
773
+ }
774
+
775
+
776
+ /*
777
+ * Make a Ruby array out of the encoded values from the specified
778
+ * column in the given result.
779
+ */
780
+ static VALUE
781
+ make_column_result_array( VALUE self, int col )
782
+ {
783
+ PGresult *result = pgresult_get( self );
784
+ int rows = PQntuples( result );
785
+ int i;
786
+ VALUE val = Qnil;
787
+ VALUE results = rb_ary_new2( rows );
788
+
789
+ if ( col >= PQnfields(result) )
790
+ rb_raise( rb_eIndexError, "no column %d in result", col );
791
+
792
+ for ( i=0; i < rows; i++ ) {
793
+ val = rb_tainted_str_new( PQgetvalue(result, i, col),
794
+ PQgetlength(result, i, col) );
795
+
796
+ #ifdef M17N_SUPPORTED
797
+ /* associate client encoding for text format only */
798
+ if ( 0 == PQfformat(result, col) ) {
799
+ ASSOCIATE_INDEX( val, self );
800
+ } else {
801
+ rb_enc_associate( val, rb_ascii8bit_encoding() );
802
+ }
803
+ #endif
804
+
805
+ rb_ary_store( results, i, val );
806
+ }
807
+
808
+ return results;
809
+ }
810
+
811
+
812
+ /*
813
+ * call-seq:
814
+ * res.column_values( n ) -> array
815
+ *
816
+ * Returns an Array of the values from the nth column of each
817
+ * tuple in the result.
818
+ *
819
+ */
820
+ static VALUE
821
+ pgresult_column_values(VALUE self, VALUE index)
822
+ {
823
+ int col = NUM2INT( index );
824
+ return make_column_result_array( self, col );
825
+ }
826
+
827
+
828
+ /*
829
+ * call-seq:
830
+ * res.field_values( field ) -> array
831
+ *
832
+ * Returns an Array of the values from the given _field_ of each tuple in the result.
833
+ *
834
+ */
835
+ static VALUE
836
+ pgresult_field_values( VALUE self, VALUE field )
837
+ {
838
+ PGresult *result = pgresult_get( self );
839
+ const char *fieldname = StringValuePtr( field );
840
+ int fnum = PQfnumber( result, fieldname );
841
+
842
+ if ( fnum < 0 )
843
+ rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
844
+
845
+ return make_column_result_array( self, fnum );
846
+ }
847
+
848
+
849
+ /*
850
+ * call-seq:
851
+ * res.each{ |tuple| ... }
852
+ *
853
+ * Invokes block for each tuple in the result set.
854
+ */
855
+ static VALUE
856
+ pgresult_each(VALUE self)
857
+ {
858
+ PGresult *result = pgresult_get(self);
859
+ int tuple_num;
860
+
861
+ for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
862
+ rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
863
+ }
864
+ return self;
865
+ }
866
+
867
+ /*
868
+ * call-seq:
869
+ * res.fields() -> Array
870
+ *
871
+ * Returns an array of Strings representing the names of the fields in the result.
872
+ */
873
+ static VALUE
874
+ pgresult_fields(VALUE self)
875
+ {
876
+ PGresult *result = pgresult_get( self );
877
+ int n = PQnfields( result );
878
+ VALUE fields = rb_ary_new2( n );
879
+ int i;
880
+
881
+ for ( i = 0; i < n; i++ ) {
882
+ VALUE val = rb_tainted_str_new2(PQfname(result, i));
883
+ ASSOCIATE_INDEX(val, self);
884
+ rb_ary_store( fields, i, val );
885
+ }
886
+
887
+ return fields;
888
+ }
889
+
890
+
891
+ void
892
+ init_pg_result()
893
+ {
894
+ rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cObject );
895
+ rb_include_module(rb_cPGresult, rb_mEnumerable);
896
+ rb_include_module(rb_cPGresult, rb_mPGconstants);
897
+
898
+ /****** PG::Result INSTANCE METHODS: libpq ******/
899
+ rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
900
+ rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
901
+ rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
902
+ rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
903
+ rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
904
+ rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
905
+ rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
906
+ rb_define_method(rb_cPGresult, "check", pg_result_check, 0);
907
+ rb_define_alias (rb_cPGresult, "check_result", "check");
908
+ rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
909
+ rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
910
+ rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
911
+ rb_define_alias(rb_cPGresult, "num_fields", "nfields");
912
+ rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
913
+ rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
914
+ rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
915
+ rb_define_method(rb_cPGresult, "ftablecol", pgresult_ftablecol, 1);
916
+ rb_define_method(rb_cPGresult, "fformat", pgresult_fformat, 1);
917
+ rb_define_method(rb_cPGresult, "ftype", pgresult_ftype, 1);
918
+ rb_define_method(rb_cPGresult, "fmod", pgresult_fmod, 1);
919
+ rb_define_method(rb_cPGresult, "fsize", pgresult_fsize, 1);
920
+ rb_define_method(rb_cPGresult, "getvalue", pgresult_getvalue, 2);
921
+ rb_define_method(rb_cPGresult, "getisnull", pgresult_getisnull, 2);
922
+ rb_define_method(rb_cPGresult, "getlength", pgresult_getlength, 2);
923
+ rb_define_method(rb_cPGresult, "nparams", pgresult_nparams, 0);
924
+ rb_define_method(rb_cPGresult, "paramtype", pgresult_paramtype, 1);
925
+ rb_define_method(rb_cPGresult, "cmd_status", pgresult_cmd_status, 0);
926
+ rb_define_method(rb_cPGresult, "cmd_tuples", pgresult_cmd_tuples, 0);
927
+ rb_define_alias(rb_cPGresult, "cmdtuples", "cmd_tuples");
928
+ rb_define_method(rb_cPGresult, "oid_value", pgresult_oid_value, 0);
929
+
930
+ /****** PG::Result INSTANCE METHODS: other ******/
931
+ rb_define_method(rb_cPGresult, "[]", pgresult_aref, 1);
932
+ rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
933
+ rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
934
+ rb_define_method(rb_cPGresult, "each_row", pgresult_each_row, 0);
935
+ rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
936
+ rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
937
+ }
938
+
939
+