pg_jruby 0.14.1.rc2-java → 0.17.1-java

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