pg 0.12.2 → 0.13.0.pre298

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