pg 0.15.0.pre.454-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
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
+