pg 0.12.2-x86-mingw32 → 0.13.0-x86-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 (50) hide show
  1. data/.hoerc +2 -0
  2. data/.tm_properties +12 -0
  3. data/ChangeLog +166 -59
  4. data/Contributors.rdoc +7 -0
  5. data/History.rdoc +29 -0
  6. data/LICENSE +12 -14
  7. data/Manifest.txt +15 -14
  8. data/{BSD → POSTGRES} +0 -0
  9. data/{README.OS_X.rdoc → README-OS_X.rdoc} +0 -0
  10. data/{README.windows.rdoc → README-Windows.rdoc} +0 -0
  11. data/README.ja.rdoc +1 -1
  12. data/README.rdoc +39 -27
  13. data/Rakefile +1 -5
  14. data/Rakefile.cross +2 -2
  15. data/ext/extconf.rb +8 -2
  16. data/ext/pg.c +232 -4297
  17. data/ext/pg.h +88 -23
  18. data/ext/pg_connection.c +3288 -0
  19. data/ext/pg_result.c +905 -0
  20. data/lib/1.8/pg_ext.so +0 -0
  21. data/lib/1.9/pg_ext.so +0 -0
  22. data/lib/pg.rb +26 -43
  23. data/lib/pg/connection.rb +58 -0
  24. data/lib/pg/constants.rb +11 -0
  25. data/lib/pg/exceptions.rb +11 -0
  26. data/lib/pg/result.rb +11 -0
  27. data/misc/openssl-pg-segfault.rb +1 -1
  28. data/sample/async_api.rb +16 -21
  29. data/sample/async_copyto.rb +1 -1
  30. data/sample/async_mixed.rb +56 -0
  31. data/sample/copyfrom.rb +1 -1
  32. data/sample/copyto.rb +1 -1
  33. data/sample/cursor.rb +1 -1
  34. data/sample/losample.rb +6 -6
  35. data/sample/notify_wait.rb +51 -22
  36. data/sample/test_binary_values.rb +4 -6
  37. data/spec/lib/helpers.rb +14 -10
  38. data/spec/{pgconn_spec.rb → pg/connection_spec.rb} +228 -60
  39. data/spec/{pgresult_spec.rb → pg/result_spec.rb} +31 -35
  40. data/spec/pg_spec.rb +22 -0
  41. metadata +52 -41
  42. data/GPL +0 -340
  43. data/ext/compat.c +0 -541
  44. data/ext/compat.h +0 -184
  45. data/sample/psql.rb +0 -1181
  46. data/sample/psqlHelp.rb +0 -158
  47. data/sample/test1.rb +0 -60
  48. data/sample/test2.rb +0 -44
  49. data/sample/test4.rb +0 -71
  50. data/spec/m17n_spec.rb +0 -170
@@ -0,0 +1,905 @@
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, 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
+