pgsql 1.0
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.
- data/LICENSE +35 -0
- data/README +47 -0
- data/lib/Rakefile +31 -0
- data/lib/conn.c +902 -0
- data/lib/conn.h +42 -0
- data/lib/conn_exec.c +869 -0
- data/lib/conn_exec.h +14 -0
- data/lib/conn_quote.c +669 -0
- data/lib/conn_quote.h +27 -0
- data/lib/mkrf_conf +38 -0
- data/lib/module.c +47 -0
- data/lib/module.h +39 -0
- data/lib/result.c +891 -0
- data/lib/result.h +32 -0
- data/lib/undef.h +11 -0
- metadata +90 -0
data/lib/conn_quote.h
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
/*
|
2
|
+
* conn_quote.h -- PostgreSQL connection, string handling
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef __CONN_QUOTE_H
|
6
|
+
#define __CONN_QUOTE_H
|
7
|
+
|
8
|
+
#include "conn.h"
|
9
|
+
|
10
|
+
|
11
|
+
extern VALUE rb_cDate;
|
12
|
+
extern VALUE rb_cDateTime;
|
13
|
+
extern VALUE rb_cCurrency;
|
14
|
+
|
15
|
+
|
16
|
+
extern VALUE pg_currency_class( void);
|
17
|
+
|
18
|
+
|
19
|
+
extern VALUE pgconn_stringize( VALUE self, VALUE obj);
|
20
|
+
extern VALUE pgconn_stringize_line( VALUE self, VALUE ary);
|
21
|
+
|
22
|
+
|
23
|
+
extern void Init_pgsql_conn_quote( void);
|
24
|
+
|
25
|
+
|
26
|
+
#endif
|
27
|
+
|
data/lib/mkrf_conf
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# mkrf_conf -- configure Ruby-PgSQL
|
5
|
+
#
|
6
|
+
|
7
|
+
require "autorake/mkconfig"
|
8
|
+
|
9
|
+
Autorake.configure {
|
10
|
+
|
11
|
+
extending_ruby
|
12
|
+
|
13
|
+
if RUBY_VERSION < "1.9" then
|
14
|
+
have_header "ruby.h"
|
15
|
+
have_header "rubyio.h"
|
16
|
+
have_header "st.h"
|
17
|
+
else
|
18
|
+
have_header "ruby/ruby.h"
|
19
|
+
have_header "ruby/io.h"
|
20
|
+
end
|
21
|
+
|
22
|
+
incdir :postgres, `pg_config --pkgincludedir`
|
23
|
+
incdir :postgres_server, `pg_config --includedir-server`
|
24
|
+
|
25
|
+
have_library "crypto"
|
26
|
+
have_library "ssl"
|
27
|
+
have_library "pq"
|
28
|
+
|
29
|
+
have_header "postgres.h"
|
30
|
+
have_header "libpq-fe.h"
|
31
|
+
have_header "catalog/pg_type.h"
|
32
|
+
|
33
|
+
have_func "rb_errinfo"
|
34
|
+
have_func "rb_io_stdio_file"
|
35
|
+
have_func "rb_locale_encoding"
|
36
|
+
|
37
|
+
}
|
38
|
+
|
data/lib/module.c
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
/*
|
2
|
+
* module.c -- Pg module
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "module.h"
|
6
|
+
|
7
|
+
#include "conn.h"
|
8
|
+
|
9
|
+
|
10
|
+
#define PGSQL_VERSION "1.0"
|
11
|
+
|
12
|
+
|
13
|
+
VALUE rb_mPg;
|
14
|
+
VALUE rb_ePgError;
|
15
|
+
|
16
|
+
|
17
|
+
/********************************************************************
|
18
|
+
*
|
19
|
+
* Document-module: Pg
|
20
|
+
*
|
21
|
+
* The module to enclose everything.
|
22
|
+
*
|
23
|
+
* See the Pg::Conn class for information on how to open a database
|
24
|
+
* connection.
|
25
|
+
*/
|
26
|
+
|
27
|
+
/********************************************************************
|
28
|
+
*
|
29
|
+
* Document-class: Pg::Error
|
30
|
+
*
|
31
|
+
* Generic PostgreSQL error.
|
32
|
+
*/
|
33
|
+
|
34
|
+
void
|
35
|
+
Init_pgsql( void)
|
36
|
+
{
|
37
|
+
rb_mPg = rb_define_module( "Pg");
|
38
|
+
|
39
|
+
rb_define_const( rb_mPg, "VERSION",
|
40
|
+
rb_obj_freeze( rb_str_new2( PGSQL_VERSION)));
|
41
|
+
|
42
|
+
rb_ePgError = rb_define_class_under( rb_mPg, "Error", rb_eStandardError);
|
43
|
+
|
44
|
+
Init_pgsql_conn();
|
45
|
+
Init_pgsql_result();
|
46
|
+
}
|
47
|
+
|
data/lib/module.h
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
/*
|
2
|
+
* module.h -- Pg module
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef __MODULE_H
|
6
|
+
#define __MODULE_H
|
7
|
+
|
8
|
+
|
9
|
+
#if defined( HAVE_HEADER_RUBY_H)
|
10
|
+
#include <ruby.h>
|
11
|
+
#elif defined( HAVE_HEADER_RUBY_RUBY_H)
|
12
|
+
#include <ruby/ruby.h>
|
13
|
+
#endif
|
14
|
+
#if defined( HAVE_HEADER_RUBYIO_H)
|
15
|
+
#include "rubyio.h"
|
16
|
+
#elif defined( HAVE_HEADER_RUBY_IO_H)
|
17
|
+
#include "ruby/io.h"
|
18
|
+
#endif
|
19
|
+
#include "undef.h"
|
20
|
+
|
21
|
+
#ifdef HAVE_HEADER_POSTGRES_H
|
22
|
+
#include <postgres.h>
|
23
|
+
#endif
|
24
|
+
#ifdef HAVE_HEADER_LIBPQ_FE_H
|
25
|
+
#include <libpq-fe.h>
|
26
|
+
#endif
|
27
|
+
#ifdef HAVE_HEADER_CATALOG_PG_TYPE_H
|
28
|
+
#include <catalog/pg_type.h>
|
29
|
+
#endif
|
30
|
+
#include "undef.h"
|
31
|
+
|
32
|
+
|
33
|
+
extern VALUE rb_mPg;
|
34
|
+
extern VALUE rb_ePgError;
|
35
|
+
|
36
|
+
extern void Init_pgsql( void);
|
37
|
+
|
38
|
+
#endif
|
39
|
+
|
data/lib/result.c
ADDED
@@ -0,0 +1,891 @@
|
|
1
|
+
/*
|
2
|
+
* result.c -- Pg query results
|
3
|
+
*/
|
4
|
+
|
5
|
+
|
6
|
+
#include "result.h"
|
7
|
+
|
8
|
+
#include "conn_quote.h"
|
9
|
+
|
10
|
+
|
11
|
+
static void pgresult_init( struct pgresult_data *r, PGresult *result, struct pgconn_data *conn);
|
12
|
+
static VALUE pgreserror_new( VALUE result, VALUE cmd, VALUE par);
|
13
|
+
|
14
|
+
static VALUE pgreserror_command( VALUE self);
|
15
|
+
static VALUE pgreserror_params( VALUE self);
|
16
|
+
|
17
|
+
static struct pgresult_data *pgreserror_result( VALUE self);
|
18
|
+
static VALUE pgreserror_status( VALUE self);
|
19
|
+
static VALUE pgreserror_sqlst( VALUE self);
|
20
|
+
static VALUE pgreserror_primary( VALUE self);
|
21
|
+
static VALUE pgreserror_detail( VALUE self);
|
22
|
+
static VALUE pgreserror_hint( VALUE self);
|
23
|
+
static VALUE pgreserror_diag( VALUE self, VALUE field);
|
24
|
+
|
25
|
+
|
26
|
+
static VALUE pgresult_s_translate_results_set( VALUE cls, VALUE fact);
|
27
|
+
|
28
|
+
static void pgresult_mark( struct pgresult_data *ptr);
|
29
|
+
static void pgresult_free( struct pgresult_data *ptr);
|
30
|
+
extern VALUE pgresult_new( PGresult *result, struct pgconn_data *conn, VALUE cmd, VALUE par);
|
31
|
+
|
32
|
+
extern VALUE pgresult_clear( VALUE self);
|
33
|
+
|
34
|
+
static VALUE pgresult_status( VALUE self);
|
35
|
+
|
36
|
+
static VALUE pgresult_fields( VALUE self);
|
37
|
+
static VALUE pgresult_field_indices( VALUE self);
|
38
|
+
static VALUE pgresult_num_fields( VALUE self);
|
39
|
+
static VALUE pgresult_fieldname( VALUE self, VALUE index);
|
40
|
+
static VALUE pgresult_fieldnum( VALUE self, VALUE name);
|
41
|
+
|
42
|
+
extern VALUE pgresult_each( VALUE self);
|
43
|
+
static VALUE pgresult_aref( int argc, VALUE *argv, VALUE self);
|
44
|
+
extern VALUE pg_fetchrow( struct pgresult_data *r, int num);
|
45
|
+
extern VALUE pg_fetchresult( struct pgresult_data *r, int row, int col);
|
46
|
+
static VALUE pgresult_num_tuples( VALUE self);
|
47
|
+
|
48
|
+
static VALUE pgresult_type( VALUE self, VALUE index);
|
49
|
+
static VALUE pgresult_size( VALUE self, VALUE index);
|
50
|
+
static VALUE pgresult_getvalue( VALUE self, VALUE row, VALUE col);
|
51
|
+
static VALUE pgresult_getlength( VALUE self, VALUE row, VALUE col);
|
52
|
+
static VALUE pgresult_getisnull( VALUE self, VALUE row, VALUE col);
|
53
|
+
static VALUE pgresult_getvalue_byname( VALUE self, VALUE row, VALUE field_name);
|
54
|
+
|
55
|
+
static VALUE pgresult_cmdtuples( VALUE self);
|
56
|
+
static VALUE pgresult_cmdstatus( VALUE self);
|
57
|
+
static VALUE pgresult_oid( VALUE self);
|
58
|
+
|
59
|
+
|
60
|
+
static VALUE rb_cBigDecimal;
|
61
|
+
|
62
|
+
static VALUE rb_cPgResult;
|
63
|
+
static VALUE rb_ePgResError;
|
64
|
+
|
65
|
+
static ID id_new;
|
66
|
+
static ID id_parse;
|
67
|
+
static ID id_result;
|
68
|
+
|
69
|
+
static int translate_results = 1;
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
VALUE
|
75
|
+
pgreserror_new( VALUE result, VALUE cmd, VALUE par)
|
76
|
+
{
|
77
|
+
struct pgresult_data *r;
|
78
|
+
VALUE rse, msg;
|
79
|
+
|
80
|
+
Data_Get_Struct( result, struct pgresult_data, r);
|
81
|
+
msg = pgconn_mkstring( r->conn, PQresultErrorMessage( r->res));
|
82
|
+
rse = rb_class_new_instance( 1, &msg, rb_ePgResError);
|
83
|
+
rb_ivar_set( rse, id_result, result);
|
84
|
+
rb_ivar_set( rse, rb_intern( "@command"), cmd);
|
85
|
+
rb_ivar_set( rse, rb_intern( "@parameters"), par);
|
86
|
+
return rse;
|
87
|
+
}
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
static struct pgresult_data *
|
92
|
+
pgreserror_result( VALUE self)
|
93
|
+
{
|
94
|
+
struct pgresult_data *r;
|
95
|
+
|
96
|
+
Data_Get_Struct( rb_ivar_get( self, id_result), struct pgresult_data, r);
|
97
|
+
return r;
|
98
|
+
}
|
99
|
+
|
100
|
+
/*
|
101
|
+
* call-seq:
|
102
|
+
* pgqe.status() => num
|
103
|
+
*
|
104
|
+
* Forward PostgreSQL's error code.
|
105
|
+
*
|
106
|
+
*/
|
107
|
+
VALUE
|
108
|
+
pgreserror_status( VALUE self)
|
109
|
+
{
|
110
|
+
struct pgresult_data *r;
|
111
|
+
|
112
|
+
r = pgreserror_result( self);
|
113
|
+
return INT2FIX( PQresultStatus( r->res));
|
114
|
+
}
|
115
|
+
|
116
|
+
/*
|
117
|
+
* call-seq:
|
118
|
+
* pgqe.sqlstate() => string
|
119
|
+
*
|
120
|
+
* Forward PostgreSQL's error code.
|
121
|
+
*
|
122
|
+
*/
|
123
|
+
VALUE
|
124
|
+
pgreserror_sqlst( VALUE self)
|
125
|
+
{
|
126
|
+
struct pgresult_data *r;
|
127
|
+
|
128
|
+
r = pgreserror_result( self);
|
129
|
+
return pgconn_mkstring( r->conn, PQresultErrorField( r->res, PG_DIAG_SQLSTATE));
|
130
|
+
}
|
131
|
+
|
132
|
+
/*
|
133
|
+
* call-seq:
|
134
|
+
* pgqe.primary() => string
|
135
|
+
*
|
136
|
+
* Forward PostgreSQL's primary error message.
|
137
|
+
*
|
138
|
+
*/
|
139
|
+
VALUE
|
140
|
+
pgreserror_primary( VALUE self)
|
141
|
+
{
|
142
|
+
struct pgresult_data *r;
|
143
|
+
|
144
|
+
r = pgreserror_result( self);
|
145
|
+
return pgconn_mkstring( r->conn, PQresultErrorField( r->res, PG_DIAG_MESSAGE_PRIMARY));
|
146
|
+
}
|
147
|
+
|
148
|
+
|
149
|
+
/*
|
150
|
+
* call-seq:
|
151
|
+
* pgqe.details() => string
|
152
|
+
*
|
153
|
+
* Forward PostgreSQL's error details.
|
154
|
+
*
|
155
|
+
*/
|
156
|
+
VALUE
|
157
|
+
pgreserror_detail( VALUE self)
|
158
|
+
{
|
159
|
+
struct pgresult_data *r;
|
160
|
+
|
161
|
+
r = pgreserror_result( self);
|
162
|
+
return pgconn_mkstring( r->conn, PQresultErrorField( r->res, PG_DIAG_MESSAGE_DETAIL));
|
163
|
+
}
|
164
|
+
|
165
|
+
|
166
|
+
/*
|
167
|
+
* call-seq:
|
168
|
+
* pgqe.hint() => string
|
169
|
+
*
|
170
|
+
* Forward PostgreSQL's error hint.
|
171
|
+
*
|
172
|
+
*/
|
173
|
+
VALUE
|
174
|
+
pgreserror_hint( VALUE self)
|
175
|
+
{
|
176
|
+
struct pgresult_data *r;
|
177
|
+
|
178
|
+
r = pgreserror_result( self);
|
179
|
+
return pgconn_mkstring( r->conn, PQresultErrorField( r->res, PG_DIAG_MESSAGE_HINT));
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
/*
|
184
|
+
* call-seq:
|
185
|
+
* pgqe.diag( field) => string
|
186
|
+
*
|
187
|
+
* Error diagnose message. Give one of the PG_DIAG_* constants
|
188
|
+
* to specify a field.
|
189
|
+
*
|
190
|
+
*/
|
191
|
+
VALUE
|
192
|
+
pgreserror_diag( VALUE self, VALUE field)
|
193
|
+
{
|
194
|
+
struct pgresult_data *r;
|
195
|
+
|
196
|
+
r = pgreserror_result( self);
|
197
|
+
return pgconn_mkstring( r->conn, PQresultErrorField( r->res, NUM2INT( field)));
|
198
|
+
}
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
/*
|
203
|
+
* call-seq:
|
204
|
+
* Pg::Conn.translate_results = boolean
|
205
|
+
*
|
206
|
+
* When true (default), results are translated to an appropriate Ruby class.
|
207
|
+
* When false, results are returned as +Strings+.
|
208
|
+
*
|
209
|
+
*/
|
210
|
+
VALUE
|
211
|
+
pgresult_s_translate_results_set( VALUE cls, VALUE fact)
|
212
|
+
{
|
213
|
+
translate_results = RTEST( fact) ? 1 : 0;
|
214
|
+
return Qnil;
|
215
|
+
}
|
216
|
+
|
217
|
+
|
218
|
+
|
219
|
+
void
|
220
|
+
pgresult_mark( struct pgresult_data *ptr)
|
221
|
+
{
|
222
|
+
rb_gc_mark( ptr->fields);
|
223
|
+
rb_gc_mark( ptr->indices);
|
224
|
+
}
|
225
|
+
|
226
|
+
void
|
227
|
+
pgresult_free( struct pgresult_data *ptr)
|
228
|
+
{
|
229
|
+
if (ptr->res != NULL)
|
230
|
+
PQclear( ptr->res);
|
231
|
+
free( ptr);
|
232
|
+
}
|
233
|
+
|
234
|
+
void
|
235
|
+
pgresult_init( struct pgresult_data *r, PGresult *result, struct pgconn_data *conn)
|
236
|
+
{
|
237
|
+
r->res = result;
|
238
|
+
r->conn = conn;
|
239
|
+
r->fields = Qnil;
|
240
|
+
r->indices = Qnil;
|
241
|
+
}
|
242
|
+
|
243
|
+
VALUE
|
244
|
+
pgresult_new( PGresult *result, struct pgconn_data *conn, VALUE cmd, VALUE par)
|
245
|
+
{
|
246
|
+
struct pgresult_data *r;
|
247
|
+
VALUE res;
|
248
|
+
|
249
|
+
res = Data_Make_Struct( rb_cPgResult, struct pgresult_data, 0, &pgresult_free, r);
|
250
|
+
pgresult_init( r, result, conn);
|
251
|
+
switch (PQresultStatus( result)) {
|
252
|
+
case PGRES_EMPTY_QUERY:
|
253
|
+
case PGRES_COMMAND_OK:
|
254
|
+
case PGRES_TUPLES_OK:
|
255
|
+
case PGRES_COPY_OUT:
|
256
|
+
case PGRES_COPY_IN:
|
257
|
+
break;
|
258
|
+
case PGRES_BAD_RESPONSE:
|
259
|
+
case PGRES_NONFATAL_ERROR:
|
260
|
+
case PGRES_FATAL_ERROR:
|
261
|
+
rb_exc_raise( pgreserror_new( res, cmd, par));
|
262
|
+
break;
|
263
|
+
default:
|
264
|
+
rb_raise( rb_ePgError, "internal error: unknown result status.");
|
265
|
+
break;
|
266
|
+
}
|
267
|
+
return res;
|
268
|
+
}
|
269
|
+
|
270
|
+
/*
|
271
|
+
* call-seq:
|
272
|
+
* res.clear()
|
273
|
+
*
|
274
|
+
* Clears the Pg::Result object as the result of the query.
|
275
|
+
*/
|
276
|
+
VALUE
|
277
|
+
pgresult_clear( VALUE self)
|
278
|
+
{
|
279
|
+
struct pgresult_data *r;
|
280
|
+
|
281
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
282
|
+
if (r->res != NULL) {
|
283
|
+
PQclear( r->res);
|
284
|
+
r->res = NULL;
|
285
|
+
}
|
286
|
+
return Qnil;
|
287
|
+
}
|
288
|
+
|
289
|
+
|
290
|
+
/*
|
291
|
+
* call-seq:
|
292
|
+
* res.status() -> int
|
293
|
+
*
|
294
|
+
* Returns the status of the query. The status value is one of:
|
295
|
+
* * +EMPTY_QUERY+
|
296
|
+
* * +COMMAND_OK+
|
297
|
+
* * +TUPLES_OK+
|
298
|
+
* * +COPY_OUT+
|
299
|
+
* * +COPY_IN+
|
300
|
+
*/
|
301
|
+
VALUE
|
302
|
+
pgresult_status( VALUE self)
|
303
|
+
{
|
304
|
+
struct pgresult_data *r;
|
305
|
+
|
306
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
307
|
+
return INT2FIX( PQresultStatus( r->res));
|
308
|
+
}
|
309
|
+
|
310
|
+
|
311
|
+
|
312
|
+
/*
|
313
|
+
* call-seq:
|
314
|
+
* res.fields()
|
315
|
+
*
|
316
|
+
* Returns an array of Strings representing the names of the fields in the
|
317
|
+
* result.
|
318
|
+
*
|
319
|
+
* res = conn.exec( "SELECT foo, bar AS biggles, jim, jam FROM mytable")
|
320
|
+
* res.fields => [ 'foo', 'biggles', 'jim', 'jam']
|
321
|
+
*/
|
322
|
+
VALUE
|
323
|
+
pgresult_fields( VALUE self)
|
324
|
+
{
|
325
|
+
struct pgresult_data *r;
|
326
|
+
|
327
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
328
|
+
if (NIL_P( r->fields)) {
|
329
|
+
VALUE ary;
|
330
|
+
int n, i;
|
331
|
+
VALUE str;
|
332
|
+
|
333
|
+
n = PQnfields( r->res);
|
334
|
+
ary = rb_ary_new2( n);
|
335
|
+
for (i = 0; n; i++, n--) {
|
336
|
+
str = pgconn_mkstring( r->conn, PQfname( r->res, i));
|
337
|
+
rb_str_freeze( str);
|
338
|
+
rb_ary_push( ary, str);
|
339
|
+
}
|
340
|
+
rb_ary_freeze( ary);
|
341
|
+
r->fields = ary;
|
342
|
+
}
|
343
|
+
return r->fields;
|
344
|
+
}
|
345
|
+
|
346
|
+
/*
|
347
|
+
* call-seq:
|
348
|
+
* res.field_indices()
|
349
|
+
*
|
350
|
+
* Returns a hash that points to field numbers.
|
351
|
+
* result.
|
352
|
+
*
|
353
|
+
* res = conn.exec( "SELECT foo, bar AS biggles FROM mytable")
|
354
|
+
* res.field_indices => { 'foo' => 0, 'biggles' => 1 }
|
355
|
+
*/
|
356
|
+
VALUE
|
357
|
+
pgresult_field_indices( VALUE self)
|
358
|
+
{
|
359
|
+
struct pgresult_data *r;
|
360
|
+
|
361
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
362
|
+
if (NIL_P( r->indices)) {
|
363
|
+
VALUE hsh;
|
364
|
+
int n, i;
|
365
|
+
VALUE str;
|
366
|
+
|
367
|
+
n = PQnfields( r->res);
|
368
|
+
hsh = rb_hash_new();
|
369
|
+
for (i = 0; n; i++, n--) {
|
370
|
+
str = pgconn_mkstring( r->conn, PQfname( r->res, i));
|
371
|
+
rb_str_freeze( str);
|
372
|
+
rb_hash_aset( hsh, str, INT2FIX( i));
|
373
|
+
}
|
374
|
+
rb_hash_freeze( hsh);
|
375
|
+
r->indices = hsh;
|
376
|
+
}
|
377
|
+
return r->indices;
|
378
|
+
}
|
379
|
+
|
380
|
+
/*
|
381
|
+
* call-seq:
|
382
|
+
* res.num_fields()
|
383
|
+
*
|
384
|
+
* Returns the number of fields (columns) in the query result.
|
385
|
+
*
|
386
|
+
* Similar to <code>res.result[0].length</code> (but faster).
|
387
|
+
*/
|
388
|
+
VALUE
|
389
|
+
pgresult_num_fields( VALUE self)
|
390
|
+
{
|
391
|
+
struct pgresult_data *r;
|
392
|
+
|
393
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
394
|
+
return INT2FIX( PQnfields( r->res));
|
395
|
+
}
|
396
|
+
|
397
|
+
/*
|
398
|
+
* call-seq:
|
399
|
+
* res.fieldname( index)
|
400
|
+
*
|
401
|
+
* Returns the name of the field (column) corresponding to the index.
|
402
|
+
*
|
403
|
+
* res = conn.exec "SELECT foo, bar AS biggles, jim, jam FROM mytable"
|
404
|
+
* res.fieldname 2 #=> 'jim'
|
405
|
+
* res.fieldname 1 #=> 'biggles'
|
406
|
+
*
|
407
|
+
* Equivalent to <code>res.fields[_index_]</code>.
|
408
|
+
*/
|
409
|
+
VALUE
|
410
|
+
pgresult_fieldname( VALUE self, VALUE index)
|
411
|
+
{
|
412
|
+
struct pgresult_data *r;
|
413
|
+
|
414
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
415
|
+
return pgconn_mkstring( r->conn, PQfname( r->res, NUM2INT( index)));
|
416
|
+
}
|
417
|
+
|
418
|
+
/*
|
419
|
+
* call-seq:
|
420
|
+
* res.fieldnum( name)
|
421
|
+
*
|
422
|
+
* Returns the index of the field specified by the string _name_.
|
423
|
+
*
|
424
|
+
* res = conn.exec "SELECT foo, bar AS biggles, jim, jam FROM mytable"
|
425
|
+
* res.fieldnum 'foo' #=> 0
|
426
|
+
*
|
427
|
+
* Raises an ArgumentError if the specified _name_ isn't one of the field
|
428
|
+
* names; raises a TypeError if _name_ is not a String.
|
429
|
+
*/
|
430
|
+
VALUE
|
431
|
+
pgresult_fieldnum( VALUE self, VALUE name)
|
432
|
+
{
|
433
|
+
struct pgresult_data *r;
|
434
|
+
int n;
|
435
|
+
|
436
|
+
StringValue( name);
|
437
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
438
|
+
n = PQfnumber( r->res, pgconn_destring( r->conn, name, NULL));
|
439
|
+
if (n == -1)
|
440
|
+
rb_raise( rb_eArgError, "Unknown field: %s", RSTRING_PTR( name));
|
441
|
+
return INT2FIX( n);
|
442
|
+
}
|
443
|
+
|
444
|
+
|
445
|
+
|
446
|
+
|
447
|
+
/*
|
448
|
+
* call-seq:
|
449
|
+
* res.each { |tuple| ... } -> nil or int
|
450
|
+
*
|
451
|
+
* Invokes the block for each tuple (row) in the result.
|
452
|
+
*
|
453
|
+
* Return the number of rows the query resulted in, or +nil+ if there
|
454
|
+
* wasn't any (like <code>Numeric#nonzero?</code>).
|
455
|
+
*/
|
456
|
+
VALUE
|
457
|
+
pgresult_each( VALUE self)
|
458
|
+
{
|
459
|
+
struct pgresult_data *r;
|
460
|
+
int m, j;
|
461
|
+
|
462
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
463
|
+
for (j = 0, m = PQntuples( r->res); m; j++, m--)
|
464
|
+
rb_yield( pg_fetchrow( r, j));
|
465
|
+
return m ? INT2FIX( m) : Qnil;
|
466
|
+
}
|
467
|
+
|
468
|
+
/*
|
469
|
+
* call-seq:
|
470
|
+
* res[ n] -> ary
|
471
|
+
* res[ n, m] -> obj
|
472
|
+
*
|
473
|
+
* Returns the tuple (row) corresponding to _n_. Returns +nil+ if <code>_n_ >=
|
474
|
+
* res.num_tuples</code>.
|
475
|
+
*
|
476
|
+
* Equivalent to <code>res.result[n]</code>.
|
477
|
+
*/
|
478
|
+
VALUE
|
479
|
+
pgresult_aref( int argc, VALUE *argv, VALUE self)
|
480
|
+
{
|
481
|
+
struct pgresult_data *r;
|
482
|
+
int a;
|
483
|
+
VALUE aj, ai;
|
484
|
+
int j, i;
|
485
|
+
|
486
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
487
|
+
a = rb_scan_args( argc, argv, "11", &aj, &ai);
|
488
|
+
j = NUM2INT( aj);
|
489
|
+
if (j < PQntuples( r->res)) {
|
490
|
+
if (a == 1) {
|
491
|
+
return pg_fetchrow( r, j);
|
492
|
+
} else {
|
493
|
+
if (TYPE( ai) == T_STRING) {
|
494
|
+
ai = rb_hash_aref( pgresult_field_indices( self), ai);
|
495
|
+
if (NIL_P( ai))
|
496
|
+
return Qnil;
|
497
|
+
}
|
498
|
+
i = NUM2INT( ai);
|
499
|
+
if (i < PQnfields( r->res))
|
500
|
+
return pg_fetchresult( r, j, i);
|
501
|
+
}
|
502
|
+
}
|
503
|
+
return Qnil;
|
504
|
+
}
|
505
|
+
|
506
|
+
|
507
|
+
VALUE
|
508
|
+
pg_fetchrow( struct pgresult_data *r, int num)
|
509
|
+
{
|
510
|
+
VALUE row;
|
511
|
+
int n, i;
|
512
|
+
|
513
|
+
n = PQnfields( r->res);
|
514
|
+
if (num < PQntuples( r->res)) {
|
515
|
+
row = rb_ary_new2( n);
|
516
|
+
for (i = 0, n; n; ++i, --n)
|
517
|
+
rb_ary_store( row, i, pg_fetchresult( r, num, i));
|
518
|
+
} else
|
519
|
+
row = Qnil;
|
520
|
+
return row;
|
521
|
+
}
|
522
|
+
|
523
|
+
VALUE
|
524
|
+
pg_fetchresult( struct pgresult_data *r, int row, int col)
|
525
|
+
{
|
526
|
+
char *string;
|
527
|
+
Oid typ;
|
528
|
+
VALUE ret;
|
529
|
+
|
530
|
+
if (PQgetisnull( r->res, row, col))
|
531
|
+
return Qnil;
|
532
|
+
|
533
|
+
string = PQgetvalue( r->res, row, col);
|
534
|
+
if (string == NULL)
|
535
|
+
return Qnil;
|
536
|
+
|
537
|
+
if (!translate_results)
|
538
|
+
return pgconn_mkstring( r->conn, string);
|
539
|
+
|
540
|
+
typ = PQftype( r->res, col);
|
541
|
+
switch (typ) {
|
542
|
+
case NUMERICOID:
|
543
|
+
{
|
544
|
+
int typmod;
|
545
|
+
|
546
|
+
typmod = PQfmod( r->res, col);
|
547
|
+
if (typmod == -1 || (typmod - VARHDRSZ) & 0xffff)
|
548
|
+
break;
|
549
|
+
}
|
550
|
+
/* if scale == 0 fall through and return inum */
|
551
|
+
case INT8OID:
|
552
|
+
case INT4OID:
|
553
|
+
case INT2OID:
|
554
|
+
case OIDOID:
|
555
|
+
return rb_cstr_to_inum( string, 10, 0);
|
556
|
+
case FLOAT8OID:
|
557
|
+
case FLOAT4OID:
|
558
|
+
return rb_float_new( rb_cstr_to_dbl( string, Qfalse));
|
559
|
+
case BOOLOID:
|
560
|
+
return *string == 't' ? Qtrue : Qfalse;
|
561
|
+
/* strchr( "tTyY", *string) != NULL */
|
562
|
+
case BYTEAOID:
|
563
|
+
return rb_str_new2( string);
|
564
|
+
default:
|
565
|
+
break;
|
566
|
+
}
|
567
|
+
ret = pgconn_mkstring( r->conn, string);
|
568
|
+
switch (typ) {
|
569
|
+
case NUMERICOID:
|
570
|
+
return rb_funcall( rb_cBigDecimal, id_new, 1, ret);
|
571
|
+
case DATEOID:
|
572
|
+
return rb_funcall( rb_cDate, id_parse, 1, ret);
|
573
|
+
case TIMEOID:
|
574
|
+
case TIMETZOID:
|
575
|
+
return rb_funcall( rb_cTime, id_parse, 1, ret);
|
576
|
+
case TIMESTAMPOID:
|
577
|
+
case TIMESTAMPTZOID:
|
578
|
+
return rb_funcall( rb_cDateTime, id_parse, 1, ret);
|
579
|
+
case CASHOID:
|
580
|
+
return RTEST( pg_currency_class()) ?
|
581
|
+
rb_funcall( rb_cCurrency, id_parse, 1, ret) : ret;
|
582
|
+
default:
|
583
|
+
return ret;
|
584
|
+
}
|
585
|
+
}
|
586
|
+
|
587
|
+
/*
|
588
|
+
* call-seq:
|
589
|
+
* res.num_tuples()
|
590
|
+
*
|
591
|
+
* Returns the number of tuples (rows) in the query result.
|
592
|
+
*
|
593
|
+
* Similar to <code>res.rows.length</code> (but faster).
|
594
|
+
*/
|
595
|
+
VALUE
|
596
|
+
pgresult_num_tuples( VALUE self)
|
597
|
+
{
|
598
|
+
struct pgresult_data *r;
|
599
|
+
|
600
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
601
|
+
return INT2FIX( PQntuples( r->res));
|
602
|
+
}
|
603
|
+
|
604
|
+
|
605
|
+
|
606
|
+
/*
|
607
|
+
* call-seq:
|
608
|
+
* res.type( index)
|
609
|
+
*
|
610
|
+
* Returns the data type associated with the given column number.
|
611
|
+
*
|
612
|
+
* The integer returned is the internal +OID+ number (in PostgreSQL) of the
|
613
|
+
* type. If you have the PostgreSQL source available, you can see the OIDs for
|
614
|
+
* every column type in the file <code>src/include/catalog/pg_type.h</code>.
|
615
|
+
*/
|
616
|
+
VALUE
|
617
|
+
pgresult_type( VALUE self, VALUE index)
|
618
|
+
{
|
619
|
+
struct pgresult_data *r;
|
620
|
+
int n;
|
621
|
+
|
622
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
623
|
+
n = PQftype( r->res, NUM2INT( index));
|
624
|
+
return n ? INT2FIX( n) : Qnil;
|
625
|
+
}
|
626
|
+
|
627
|
+
/*
|
628
|
+
* call-seq:
|
629
|
+
* res.size( index)
|
630
|
+
*
|
631
|
+
* Returns the size of the field type in bytes. Returns <code>-1</code> if the
|
632
|
+
* field is variable sized.
|
633
|
+
*
|
634
|
+
* res = conn.exec "SELECT myInt, myVarChar50 FROM foo"
|
635
|
+
* res.size 0 #=> 4
|
636
|
+
* res.size 1 #=> -1
|
637
|
+
*/
|
638
|
+
VALUE
|
639
|
+
pgresult_size( VALUE self, VALUE index)
|
640
|
+
{
|
641
|
+
struct pgresult_data *r;
|
642
|
+
int n;
|
643
|
+
|
644
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
645
|
+
n = PQfsize( r->res, NUM2INT( index));
|
646
|
+
return n ? INT2FIX( n) : Qnil;
|
647
|
+
}
|
648
|
+
|
649
|
+
/*
|
650
|
+
* call-seq:
|
651
|
+
* res.value( row, col)
|
652
|
+
*
|
653
|
+
* Returns the value in tuple number <i>row</i>, field number
|
654
|
+
* <i>col</i>. (Row <i>row</i>, column <i>col</i>.)
|
655
|
+
*
|
656
|
+
* Equivalent to <code>res.row[<i>row</i>][<i>col</i>]</code> (but
|
657
|
+
* faster).
|
658
|
+
*/
|
659
|
+
VALUE
|
660
|
+
pgresult_getvalue( VALUE self, VALUE row, VALUE col)
|
661
|
+
{
|
662
|
+
struct pgresult_data *r;
|
663
|
+
|
664
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
665
|
+
return pg_fetchresult( r, NUM2INT( row), NUM2INT( col));
|
666
|
+
}
|
667
|
+
|
668
|
+
|
669
|
+
/*
|
670
|
+
* call-seq:
|
671
|
+
* res.getlength( row, col) -> int
|
672
|
+
*
|
673
|
+
* Returns the (String) length of the field in bytes.
|
674
|
+
*
|
675
|
+
* Equivalent to
|
676
|
+
* <code>res.value(<i>row</i>,<i>col</i>).length</code>.
|
677
|
+
*/
|
678
|
+
VALUE
|
679
|
+
pgresult_getlength( VALUE self, VALUE row, VALUE col)
|
680
|
+
{
|
681
|
+
struct pgresult_data *r;
|
682
|
+
|
683
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
684
|
+
return INT2FIX( PQgetlength( r->res, NUM2INT( row), NUM2INT( col)));
|
685
|
+
}
|
686
|
+
|
687
|
+
/*
|
688
|
+
* call-seq:
|
689
|
+
* res.getisnull( row, col) -> boolean
|
690
|
+
*
|
691
|
+
* Returns +true+ if the specified value is +nil+; +false+ otherwise.
|
692
|
+
*
|
693
|
+
* Equivalent to
|
694
|
+
* <code>res.value(<i>row</i>,<i>col</i>)==+nil+</code>.
|
695
|
+
*/
|
696
|
+
VALUE
|
697
|
+
pgresult_getisnull( VALUE self, VALUE row, VALUE col)
|
698
|
+
{
|
699
|
+
struct pgresult_data *r;
|
700
|
+
|
701
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
702
|
+
return PQgetisnull( r->res, NUM2INT( row), NUM2INT( col)) ? Qtrue : Qfalse;
|
703
|
+
}
|
704
|
+
|
705
|
+
/*
|
706
|
+
* call-seq:
|
707
|
+
* res.value_byname( row, field_name )
|
708
|
+
*
|
709
|
+
* Returns the value in tuple number <i>row</i>, for the field named
|
710
|
+
* <i>field_name</i>.
|
711
|
+
*
|
712
|
+
* Equivalent to (but faster than) either of:
|
713
|
+
*
|
714
|
+
* res.row[<i>row</i>][ res.fieldnum(<i>field_name</i>) ]
|
715
|
+
* res.value( <i>row</i>, res.fieldnum(<i>field_name</i>) )
|
716
|
+
*
|
717
|
+
* <i>(This method internally calls #value as like the second example above;
|
718
|
+
* it is slower than using the field index directly.)</i>
|
719
|
+
*/
|
720
|
+
VALUE
|
721
|
+
pgresult_getvalue_byname( VALUE self, VALUE row, VALUE field)
|
722
|
+
{
|
723
|
+
return pgresult_getvalue( self, row, pgresult_fieldnum( self, field));
|
724
|
+
}
|
725
|
+
|
726
|
+
|
727
|
+
|
728
|
+
/*
|
729
|
+
* call-seq:
|
730
|
+
* res.cmdtuples()
|
731
|
+
*
|
732
|
+
* Returns the number of tuples (rows) affected by the SQL command.
|
733
|
+
*
|
734
|
+
* If the SQL command that generated the Pg::Result was not one of +INSERT+,
|
735
|
+
* +UPDATE+, +DELETE+, +MOVE+, or +FETCH+, or if no tuples (rows) were
|
736
|
+
* affected, <code>0</code> is returned.
|
737
|
+
*/
|
738
|
+
VALUE
|
739
|
+
pgresult_cmdtuples( VALUE self)
|
740
|
+
{
|
741
|
+
struct pgresult_data *r;
|
742
|
+
char *n;
|
743
|
+
|
744
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
745
|
+
n = PQcmdTuples( r->res);
|
746
|
+
return *n ? rb_cstr_to_inum( n, 10, 0) : Qnil;
|
747
|
+
}
|
748
|
+
|
749
|
+
/*
|
750
|
+
* call-seq:
|
751
|
+
* res.cmdstatus()
|
752
|
+
*
|
753
|
+
* Returns the status string of the last query command.
|
754
|
+
*/
|
755
|
+
VALUE
|
756
|
+
pgresult_cmdstatus( VALUE self)
|
757
|
+
{
|
758
|
+
struct pgresult_data *r;
|
759
|
+
char *n;
|
760
|
+
|
761
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
762
|
+
n = PQcmdStatus( r->res);
|
763
|
+
return n ? pgconn_mkstring( r->conn, n) : Qnil;
|
764
|
+
}
|
765
|
+
|
766
|
+
/*
|
767
|
+
* call-seq:
|
768
|
+
* res.oid() -> int
|
769
|
+
*
|
770
|
+
* Returns the +oid+.
|
771
|
+
*/
|
772
|
+
VALUE
|
773
|
+
pgresult_oid( VALUE self)
|
774
|
+
{
|
775
|
+
struct pgresult_data *r;
|
776
|
+
Oid n;
|
777
|
+
|
778
|
+
Data_Get_Struct( self, struct pgresult_data, r);
|
779
|
+
n = PQoidValue( r->res);
|
780
|
+
return n == InvalidOid ? Qnil : INT2FIX( n);
|
781
|
+
}
|
782
|
+
|
783
|
+
|
784
|
+
|
785
|
+
|
786
|
+
/********************************************************************
|
787
|
+
*
|
788
|
+
* Document-class: Pg::Result
|
789
|
+
*
|
790
|
+
* The class to represent the query result tuples (rows).
|
791
|
+
* An instance of this class is created as the result of every query.
|
792
|
+
* You may need to invoke the #clear method of the instance when finished with
|
793
|
+
* the result for better memory performance.
|
794
|
+
*/
|
795
|
+
|
796
|
+
/********************************************************************
|
797
|
+
*
|
798
|
+
* Document-class: Pg::Result::Error
|
799
|
+
*
|
800
|
+
* The information in a result that is an error.
|
801
|
+
*/
|
802
|
+
|
803
|
+
void
|
804
|
+
Init_pgsql_result( void)
|
805
|
+
{
|
806
|
+
rb_require( "bigdecimal");
|
807
|
+
rb_cBigDecimal = rb_const_get( rb_cObject, rb_intern( "BigDecimal"));
|
808
|
+
|
809
|
+
rb_cPgResult = rb_define_class_under( rb_mPg, "Result", rb_cObject);
|
810
|
+
|
811
|
+
|
812
|
+
rb_ePgResError = rb_define_class_under( rb_cPgResult, "Error", rb_ePgError);
|
813
|
+
rb_undef_method( CLASS_OF( rb_ePgResError), "new");
|
814
|
+
|
815
|
+
rb_define_attr( rb_ePgResError, "command", 1, 0);
|
816
|
+
rb_define_attr( rb_ePgResError, "parameters", 1, 0);
|
817
|
+
|
818
|
+
rb_define_method( rb_ePgResError, "status", &pgreserror_status, 0);
|
819
|
+
rb_define_method( rb_ePgResError, "sqlstate", &pgreserror_sqlst, 0);
|
820
|
+
rb_define_alias( rb_ePgResError, "errcode", "sqlstate");
|
821
|
+
rb_define_method( rb_ePgResError, "primary", &pgreserror_primary, 0);
|
822
|
+
rb_define_method( rb_ePgResError, "details", &pgreserror_detail, 0);
|
823
|
+
rb_define_method( rb_ePgResError, "hint", &pgreserror_hint, 0);
|
824
|
+
|
825
|
+
rb_define_method( rb_ePgResError, "diag", &pgreserror_diag, 1);
|
826
|
+
|
827
|
+
#define PGD_DEF( c) rb_define_const( rb_ePgResError, #c, INT2FIX( PG_DIAG_ ## c))
|
828
|
+
PGD_DEF( SEVERITY);
|
829
|
+
PGD_DEF( SQLSTATE);
|
830
|
+
PGD_DEF( MESSAGE_PRIMARY);
|
831
|
+
PGD_DEF( MESSAGE_DETAIL);
|
832
|
+
PGD_DEF( MESSAGE_HINT);
|
833
|
+
PGD_DEF( STATEMENT_POSITION);
|
834
|
+
PGD_DEF( INTERNAL_POSITION);
|
835
|
+
PGD_DEF( INTERNAL_QUERY);
|
836
|
+
PGD_DEF( CONTEXT);
|
837
|
+
PGD_DEF( SOURCE_FILE);
|
838
|
+
PGD_DEF( SOURCE_LINE);
|
839
|
+
PGD_DEF( SOURCE_FUNCTION);
|
840
|
+
#undef PGD_DEF
|
841
|
+
|
842
|
+
rb_define_singleton_method( rb_cPgResult, "translate_results=", pgresult_s_translate_results_set, 1);
|
843
|
+
|
844
|
+
rb_undef_method( CLASS_OF( rb_cPgResult), "new");
|
845
|
+
rb_define_method( rb_cPgResult, "clear", &pgresult_clear, 0);
|
846
|
+
rb_define_alias( rb_cPgResult, "close", "clear");
|
847
|
+
|
848
|
+
rb_define_method( rb_cPgResult, "status", &pgresult_status, 0);
|
849
|
+
|
850
|
+
rb_define_method( rb_cPgResult, "fields", &pgresult_fields, 0);
|
851
|
+
rb_define_method( rb_cPgResult, "field_indices", &pgresult_field_indices, 0);
|
852
|
+
rb_define_alias( rb_cPgResult, "indices", "field_indices");
|
853
|
+
rb_define_method( rb_cPgResult, "num_fields", &pgresult_num_fields, 0);
|
854
|
+
rb_define_method( rb_cPgResult, "fieldname", &pgresult_fieldname, 1);
|
855
|
+
rb_define_method( rb_cPgResult, "fieldnum", &pgresult_fieldnum, 1);
|
856
|
+
|
857
|
+
rb_define_method( rb_cPgResult, "each", &pgresult_each, 0);
|
858
|
+
rb_include_module( rb_cPgResult, rb_mEnumerable);
|
859
|
+
rb_define_alias( rb_cPgResult, "rows", "entries");
|
860
|
+
rb_define_alias( rb_cPgResult, "result", "entries");
|
861
|
+
rb_define_method( rb_cPgResult, "[]", &pgresult_aref, -1);
|
862
|
+
rb_define_method( rb_cPgResult, "num_tuples", &pgresult_num_tuples, 0);
|
863
|
+
|
864
|
+
rb_define_method( rb_cPgResult, "type", &pgresult_type, 1);
|
865
|
+
rb_define_method( rb_cPgResult, "size", &pgresult_size, 1);
|
866
|
+
rb_define_method( rb_cPgResult, "getvalue", &pgresult_getvalue, 2);
|
867
|
+
rb_define_method( rb_cPgResult, "getlength", &pgresult_getlength, 2);
|
868
|
+
rb_define_method( rb_cPgResult, "getisnull", &pgresult_getisnull, 2);
|
869
|
+
rb_define_method( rb_cPgResult, "getvalue_byname", &pgresult_getvalue_byname, 2);
|
870
|
+
|
871
|
+
#define RESC_DEF( c) rb_define_const( rb_cPgResult, #c, INT2FIX( PGRES_ ## c))
|
872
|
+
RESC_DEF( EMPTY_QUERY);
|
873
|
+
RESC_DEF( COMMAND_OK);
|
874
|
+
RESC_DEF( TUPLES_OK);
|
875
|
+
RESC_DEF( COPY_OUT);
|
876
|
+
RESC_DEF( COPY_IN);
|
877
|
+
RESC_DEF( BAD_RESPONSE);
|
878
|
+
RESC_DEF( NONFATAL_ERROR);
|
879
|
+
RESC_DEF( FATAL_ERROR);
|
880
|
+
#undef RESC_DEF
|
881
|
+
|
882
|
+
rb_define_method( rb_cPgResult, "cmdtuples", &pgresult_cmdtuples, 0);
|
883
|
+
rb_define_method( rb_cPgResult, "cmdstatus", &pgresult_cmdstatus, 0);
|
884
|
+
rb_define_method( rb_cPgResult, "oid", &pgresult_oid, 0);
|
885
|
+
|
886
|
+
|
887
|
+
id_new = rb_intern( "new");
|
888
|
+
id_parse = rb_intern( "parse");
|
889
|
+
id_result = rb_intern( "result");
|
890
|
+
}
|
891
|
+
|