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/LICENSE
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
_
|
2
|
+
_ __ __ _ ___ __ _| |
|
3
|
+
| '_ \ / _` / __|/ _` | |
|
4
|
+
| |_) | (_| \__ \ (_| | |
|
5
|
+
| .__/ \__, |___/\__, |_|
|
6
|
+
|_| |___/ |_|
|
7
|
+
|
8
|
+
|
9
|
+
Copyright (c) 2011-2013, Bertram Scharpf <software@bertram-scharpf.de>.
|
10
|
+
All rights reserved.
|
11
|
+
|
12
|
+
Redistribution and use in source and binary forms, with or without
|
13
|
+
modification, are permitted provided that the following conditions are
|
14
|
+
met:
|
15
|
+
|
16
|
+
* Redistributions of source code must retain the above copyright
|
17
|
+
notice, this list of conditions and the following disclaimer.
|
18
|
+
|
19
|
+
* Redistributions in binary form must reproduce the above copyright
|
20
|
+
notice, this list of conditions and the following disclaimer in
|
21
|
+
the documentation and/or other materials provided with the
|
22
|
+
distribution.
|
23
|
+
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
25
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
26
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
27
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
28
|
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
29
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
30
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
31
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
32
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
33
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
34
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
|
data/README
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
_
|
2
|
+
_ __ __ _ ___ __ _| |
|
3
|
+
| '_ \ / _` / __|/ _` | |
|
4
|
+
| |_) | (_| \__ \ (_| | |
|
5
|
+
| .__/ \__, |___/\__, |_|
|
6
|
+
|_| |___/ |_|
|
7
|
+
|
8
|
+
== Description
|
9
|
+
|
10
|
+
A PostgreSQL library that was carefully designed.
|
11
|
+
|
12
|
+
== Features
|
13
|
+
|
14
|
+
* Connection parameters from hash
|
15
|
+
* Query parameters
|
16
|
+
* Asynchronous queries
|
17
|
+
* Quick query of single lines or values
|
18
|
+
* Full PostgreSQL quoting support
|
19
|
+
* Built-in transactions and savepoints by Ruby blocks
|
20
|
+
|
21
|
+
== Example
|
22
|
+
|
23
|
+
Write something like this:
|
24
|
+
|
25
|
+
require "pgsql"
|
26
|
+
|
27
|
+
Pg::Conn.open :dbname => "test1", :user => "jdoe" do |conn|
|
28
|
+
conn.exec "select * from mytable;" do |result|
|
29
|
+
result.each { |row|
|
30
|
+
l = row.join ", "
|
31
|
+
...
|
32
|
+
}
|
33
|
+
end
|
34
|
+
cmd = <<-ENDSQL
|
35
|
+
select * from mytable where num=$1::integer;
|
36
|
+
ENDSQL
|
37
|
+
conn.query cmd, 42 do |row|
|
38
|
+
l = row.join ", "
|
39
|
+
...
|
40
|
+
end
|
41
|
+
...
|
42
|
+
end
|
43
|
+
|
44
|
+
== Thanks
|
45
|
+
|
46
|
+
In the remembrance of Guy Decoux.
|
47
|
+
|
data/lib/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Rakefile -- build the libraries
|
3
|
+
#
|
4
|
+
|
5
|
+
require "autorake"
|
6
|
+
|
7
|
+
c = compiler "-O2", "-fPIC"
|
8
|
+
l = linker "-shared"
|
9
|
+
|
10
|
+
rule ".o" => ".c" do |t|
|
11
|
+
c.cc t.name, t.source
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
DLs = {
|
16
|
+
"pgsql.so" => %w(module.o conn.o conn_quote.o conn_exec.o result.o ),
|
17
|
+
}
|
18
|
+
|
19
|
+
DLs.each { |k,v|
|
20
|
+
task k => v do |t|
|
21
|
+
l.cc t.name, t.prerequisites
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
task :default => DLs.keys
|
26
|
+
|
27
|
+
task :clean do
|
28
|
+
FileList[ "*.o", "*.so"].each { |f| rm_f f }
|
29
|
+
FileList[ "*.core"].each { |f| rm_f f }
|
30
|
+
end
|
31
|
+
|
data/lib/conn.c
ADDED
@@ -0,0 +1,902 @@
|
|
1
|
+
/*
|
2
|
+
* conn.c -- PostgreSQL connection
|
3
|
+
*/
|
4
|
+
|
5
|
+
|
6
|
+
#include "conn.h"
|
7
|
+
|
8
|
+
|
9
|
+
#if defined( HAVE_HEADER_ST_H)
|
10
|
+
#include <st.h>
|
11
|
+
#endif
|
12
|
+
|
13
|
+
|
14
|
+
extern void pg_check_conninvalid( struct pgconn_data *c);
|
15
|
+
static VALUE pgconnfailederror_new( struct pgconn_data *c, VALUE params);
|
16
|
+
|
17
|
+
static void pgconn_mark( struct pgconn_data *ptr);
|
18
|
+
static void pgconn_free( struct pgconn_data *ptr);
|
19
|
+
extern struct pgconn_data *get_pgconn( VALUE obj);
|
20
|
+
static VALUE pgconn_encode_in4out( struct pgconn_data *ptr, VALUE str);
|
21
|
+
extern const char *pgconn_destring( struct pgconn_data *ptr, VALUE str, int *len);
|
22
|
+
static VALUE pgconn_encode_out4in( struct pgconn_data *ptr, VALUE str);
|
23
|
+
extern VALUE pgconn_mkstring( struct pgconn_data *ptr, const char *str);
|
24
|
+
extern VALUE pgconn_mkstringn( struct pgconn_data *ptr, const char *str, int len);
|
25
|
+
static VALUE pgconn_alloc( VALUE cls);
|
26
|
+
static VALUE pgconn_s_connect( int argc, VALUE *argv, VALUE cls);
|
27
|
+
static VALUE pgconn_s_parse( VALUE cls, VALUE str);
|
28
|
+
static VALUE pgconn_init( int argc, VALUE *argv, VALUE self);
|
29
|
+
static int set_connect_params( st_data_t key, st_data_t val, st_data_t args);
|
30
|
+
static void connstr_to_hash( VALUE params, VALUE str);
|
31
|
+
static void connstr_passwd( VALUE self, VALUE params);
|
32
|
+
static VALUE connstr_getparam( VALUE yielded, VALUE params);
|
33
|
+
|
34
|
+
static VALUE pgconn_close( VALUE self);
|
35
|
+
static VALUE pgconn_reset( VALUE self);
|
36
|
+
|
37
|
+
static VALUE pgconn_client_encoding( VALUE self);
|
38
|
+
static VALUE pgconn_set_client_encoding( VALUE self, VALUE str);
|
39
|
+
#ifdef RUBY_ENCODING
|
40
|
+
static VALUE pgconn_externalenc( VALUE self);
|
41
|
+
static VALUE pgconn_set_externalenc( VALUE self, VALUE enc);
|
42
|
+
static VALUE pgconn_internalenc( VALUE self);
|
43
|
+
static VALUE pgconn_set_internalenc( VALUE self, VALUE enc);
|
44
|
+
#endif
|
45
|
+
|
46
|
+
static VALUE pgconn_protocol_version( VALUE self);
|
47
|
+
static VALUE pgconn_server_version( VALUE self);
|
48
|
+
|
49
|
+
static VALUE pgconn_dbname( VALUE self);
|
50
|
+
static VALUE pgconn_host( VALUE self);
|
51
|
+
static VALUE pgconn_options( VALUE self);
|
52
|
+
static VALUE pgconn_port( VALUE self);
|
53
|
+
static VALUE pgconn_tty( VALUE self);
|
54
|
+
static VALUE pgconn_user( VALUE self);
|
55
|
+
static VALUE pgconn_status( VALUE self);
|
56
|
+
static VALUE pgconn_error( VALUE self);
|
57
|
+
|
58
|
+
static VALUE pgconn_socket( VALUE self);
|
59
|
+
|
60
|
+
static VALUE pgconn_trace( int argc, VALUE *argv, VALUE self);
|
61
|
+
static VALUE pgconn_untrace( VALUE self);
|
62
|
+
|
63
|
+
static VALUE pgconn_on_notice( VALUE self);
|
64
|
+
static void notice_receiver( void *self, const PGresult *result);
|
65
|
+
|
66
|
+
|
67
|
+
VALUE rb_cPgConn;
|
68
|
+
|
69
|
+
static VALUE rb_ePgConnFailed;
|
70
|
+
static VALUE rb_ePgConnInvalid;
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
void
|
75
|
+
pg_check_conninvalid( struct pgconn_data *c)
|
76
|
+
{
|
77
|
+
if (c->conn == NULL)
|
78
|
+
rb_raise( rb_ePgConnInvalid, "Invalid connection (probably closed).");
|
79
|
+
}
|
80
|
+
|
81
|
+
|
82
|
+
VALUE
|
83
|
+
pgconnfailederror_new( struct pgconn_data *c, VALUE params)
|
84
|
+
{
|
85
|
+
VALUE msg, cfe;
|
86
|
+
|
87
|
+
msg = pgconn_mkstring( c, PQerrorMessage( c->conn));
|
88
|
+
cfe = rb_class_new_instance( 1, &msg, rb_ePgConnFailed);
|
89
|
+
rb_ivar_set( cfe, rb_intern( "@parameters"), params);
|
90
|
+
return cfe;
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
void
|
96
|
+
pgconn_mark( struct pgconn_data *ptr)
|
97
|
+
{
|
98
|
+
rb_gc_mark( ptr->notice);
|
99
|
+
#ifdef RUBY_ENCODING
|
100
|
+
rb_gc_mark( ptr->external);
|
101
|
+
rb_gc_mark( ptr->internal);
|
102
|
+
#endif
|
103
|
+
}
|
104
|
+
|
105
|
+
void
|
106
|
+
pgconn_free( struct pgconn_data *ptr)
|
107
|
+
{
|
108
|
+
if (ptr->conn != NULL)
|
109
|
+
PQfinish( ptr->conn);
|
110
|
+
free( ptr);
|
111
|
+
}
|
112
|
+
|
113
|
+
struct pgconn_data *
|
114
|
+
get_pgconn( VALUE obj)
|
115
|
+
{
|
116
|
+
struct pgconn_data *c;
|
117
|
+
|
118
|
+
Data_Get_Struct( obj, struct pgconn_data, c);
|
119
|
+
pg_check_conninvalid( c);
|
120
|
+
return c;
|
121
|
+
}
|
122
|
+
|
123
|
+
|
124
|
+
VALUE pgconn_encode_in4out( struct pgconn_data *ptr, VALUE str)
|
125
|
+
{
|
126
|
+
str = rb_obj_as_string( str);
|
127
|
+
#ifdef RUBY_ENCODING
|
128
|
+
if (rb_enc_compatible( str, ptr->external) == NULL)
|
129
|
+
str = rb_str_conv_enc( str, rb_enc_get( str), rb_to_encoding( ptr->external));
|
130
|
+
#endif
|
131
|
+
return str;
|
132
|
+
}
|
133
|
+
|
134
|
+
const char *pgconn_destring( struct pgconn_data *ptr, VALUE str, int *len)
|
135
|
+
{
|
136
|
+
VALUE s;
|
137
|
+
|
138
|
+
s = pgconn_encode_in4out( ptr, str);
|
139
|
+
if (len != NULL)
|
140
|
+
*len = RSTRING_LEN( s);
|
141
|
+
return RSTRING_PTR( s);
|
142
|
+
}
|
143
|
+
|
144
|
+
|
145
|
+
VALUE
|
146
|
+
pgconn_encode_out4in( struct pgconn_data *ptr, VALUE str)
|
147
|
+
{
|
148
|
+
#ifdef RUBY_ENCODING
|
149
|
+
rb_enc_associate( str, rb_to_encoding( ptr->external));
|
150
|
+
if (!NIL_P( ptr->internal))
|
151
|
+
str = rb_str_conv_enc( str, rb_enc_get( str), rb_to_encoding( ptr->internal));
|
152
|
+
#endif
|
153
|
+
return str;
|
154
|
+
}
|
155
|
+
|
156
|
+
|
157
|
+
VALUE
|
158
|
+
pgconn_mkstring( struct pgconn_data *ptr, const char *str)
|
159
|
+
{
|
160
|
+
VALUE r;
|
161
|
+
|
162
|
+
if (str) {
|
163
|
+
r = rb_tainted_str_new2( str);
|
164
|
+
pgconn_encode_out4in( ptr, r);
|
165
|
+
} else
|
166
|
+
r = Qnil;
|
167
|
+
return r;
|
168
|
+
}
|
169
|
+
|
170
|
+
VALUE
|
171
|
+
pgconn_mkstringn( struct pgconn_data *ptr, const char *str, int len)
|
172
|
+
{
|
173
|
+
VALUE r;
|
174
|
+
|
175
|
+
if (str) {
|
176
|
+
r = rb_tainted_str_new( str, len);
|
177
|
+
pgconn_encode_out4in( ptr, r);
|
178
|
+
} else
|
179
|
+
r = Qnil;
|
180
|
+
return r;
|
181
|
+
}
|
182
|
+
|
183
|
+
VALUE
|
184
|
+
pgconn_alloc( VALUE cls)
|
185
|
+
{
|
186
|
+
struct pgconn_data *c;
|
187
|
+
VALUE r;
|
188
|
+
|
189
|
+
r = Data_Make_Struct( cls, struct pgconn_data,
|
190
|
+
&pgconn_mark, &pgconn_free, c);
|
191
|
+
c->conn = NULL;
|
192
|
+
#ifdef RUBY_ENCODING
|
193
|
+
c->external = rb_enc_from_encoding( rb_default_external_encoding());
|
194
|
+
c->internal = rb_enc_from_encoding( rb_default_internal_encoding());
|
195
|
+
#endif
|
196
|
+
c->notice = Qnil;
|
197
|
+
return r;
|
198
|
+
}
|
199
|
+
|
200
|
+
/*
|
201
|
+
* Document-method: connect
|
202
|
+
*
|
203
|
+
* call-seq:
|
204
|
+
* Pg::Conn.connect( hash) -> conn
|
205
|
+
* Pg::Conn.connect( str, hash) -> conn
|
206
|
+
* Pg::Conn.connect( hash) { |conn| ... } -> obj
|
207
|
+
* Pg::Conn.connect( str, hash) { |conn| ... } -> obj
|
208
|
+
*
|
209
|
+
* Without a block this is the same as +Pg::Conn.new+. If a block is given,
|
210
|
+
* the connection will be closed afterwards.
|
211
|
+
*/
|
212
|
+
VALUE
|
213
|
+
pgconn_s_connect( int argc, VALUE *argv, VALUE cls)
|
214
|
+
{
|
215
|
+
VALUE pgconn;
|
216
|
+
|
217
|
+
pgconn = rb_class_new_instance( argc, argv, cls);
|
218
|
+
return rb_block_given_p() ?
|
219
|
+
rb_ensure( rb_yield, pgconn, pgconn_close, pgconn) : pgconn;
|
220
|
+
}
|
221
|
+
|
222
|
+
/*
|
223
|
+
* call-seq:
|
224
|
+
* Pg::Conn.parse( str) -> hash
|
225
|
+
*
|
226
|
+
* Parse a connection string and return a hash with keys <code>:dbname</code>,
|
227
|
+
* <code>:user</code>, <code>:host</code>, etc.
|
228
|
+
*
|
229
|
+
*/
|
230
|
+
VALUE
|
231
|
+
pgconn_s_parse( VALUE cls, VALUE str)
|
232
|
+
{
|
233
|
+
VALUE params;
|
234
|
+
|
235
|
+
params = rb_hash_new();
|
236
|
+
connstr_to_hash( params, str);
|
237
|
+
return params;
|
238
|
+
}
|
239
|
+
|
240
|
+
|
241
|
+
/*
|
242
|
+
* Document-method: new
|
243
|
+
*
|
244
|
+
* call-seq:
|
245
|
+
* Pg::Conn.new( hash) -> conn
|
246
|
+
* Pg::Conn.new( str, hash) -> conn
|
247
|
+
*
|
248
|
+
* Establish a connection to a PostgreSQL server.
|
249
|
+
* The parameters may be specified as a hash:
|
250
|
+
*
|
251
|
+
* c = Pg::Conn.new :dbname => "movies", :host => "jupiter", ...
|
252
|
+
*
|
253
|
+
* The most common parameters may be given in a URL-like
|
254
|
+
* connection string:
|
255
|
+
*
|
256
|
+
* "user:password@host:port/dbname"
|
257
|
+
*
|
258
|
+
* Any of these parts may be omitted. If there is no slash, the part after the
|
259
|
+
* @ sign will be read as database name.
|
260
|
+
*
|
261
|
+
* If the password is the empty string, and there is either an instance method
|
262
|
+
* or a class method <code>password?</code>, that method will be asked. This
|
263
|
+
* method may ask <code>yield :user</code> or <code>yield :dbname</code> and so
|
264
|
+
* on to get the connection parameters.
|
265
|
+
*
|
266
|
+
* See the PostgreSQL documentation for a full list:
|
267
|
+
* [http://www.postgresql.org/docs/current/interactive/libpq-connect.html#LIBPQ-PQCONNECTDBPARAMS]
|
268
|
+
*
|
269
|
+
* On failure, a +Pg::Error+ exception will be raised.
|
270
|
+
*/
|
271
|
+
VALUE
|
272
|
+
pgconn_init( int argc, VALUE *argv, VALUE self)
|
273
|
+
{
|
274
|
+
VALUE str, params;
|
275
|
+
int l;
|
276
|
+
const char **keywords, **values;
|
277
|
+
const char **ptrs[ 3];
|
278
|
+
struct pgconn_data *c;
|
279
|
+
|
280
|
+
if (rb_scan_args( argc, argv, "02", &str, ¶ms) < 2)
|
281
|
+
if (TYPE( str) != T_STRING) {
|
282
|
+
params = str;
|
283
|
+
str = Qnil;
|
284
|
+
}
|
285
|
+
if (NIL_P( params))
|
286
|
+
params = rb_hash_new();
|
287
|
+
else if (TYPE( params) != T_HASH)
|
288
|
+
params = rb_convert_type( params, T_HASH, "Hash", "to_hash");
|
289
|
+
else
|
290
|
+
params = rb_obj_dup( params);
|
291
|
+
if (!NIL_P( str))
|
292
|
+
connstr_to_hash( params, str);
|
293
|
+
connstr_passwd( self, params);
|
294
|
+
|
295
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
296
|
+
|
297
|
+
l = RHASH_SIZE( params) + 1;
|
298
|
+
keywords = (const char **) ALLOCA_N( char *, l);
|
299
|
+
values = (const char **) ALLOCA_N( char *, l);
|
300
|
+
ptrs[ 0] = keywords;
|
301
|
+
ptrs[ 1] = values;
|
302
|
+
ptrs[ 2] = (const char **) c;
|
303
|
+
st_foreach( RHASH_TBL( params), &set_connect_params, (st_data_t) ptrs);
|
304
|
+
*(ptrs[ 0]) = *(ptrs[ 1]) = NULL;
|
305
|
+
|
306
|
+
c->conn = PQconnectdbParams( keywords, values, 1);
|
307
|
+
if (PQstatus( c->conn) == CONNECTION_BAD)
|
308
|
+
rb_exc_raise( pgconnfailederror_new( c, params));
|
309
|
+
|
310
|
+
return self;
|
311
|
+
}
|
312
|
+
|
313
|
+
int
|
314
|
+
set_connect_params( st_data_t key, st_data_t val, st_data_t args)
|
315
|
+
{
|
316
|
+
const char ***ptrs = (const char ***)args;
|
317
|
+
struct pgconn_data *c;
|
318
|
+
VALUE k, v;
|
319
|
+
|
320
|
+
k = (VALUE) key;
|
321
|
+
v = (VALUE) val;
|
322
|
+
c = (struct pgconn_data *) ptrs[ 2];
|
323
|
+
if (!NIL_P( v)) {
|
324
|
+
*(ptrs[ 0]) = pgconn_destring( c, rb_obj_as_string( k), NULL);
|
325
|
+
*(ptrs[ 1]) = pgconn_destring( c, rb_obj_as_string( v), NULL);
|
326
|
+
ptrs[ 0]++;
|
327
|
+
ptrs[ 1]++;
|
328
|
+
}
|
329
|
+
return ST_CONTINUE;
|
330
|
+
}
|
331
|
+
|
332
|
+
static const char re_connstr[] =
|
333
|
+
"\\A"
|
334
|
+
"(?:(.*?)(?::(.*))?@)?" /* user:passwd@ */
|
335
|
+
"(?:(.*?)(?::(\\d+))?/)?(?:(.+))?" /* host:port/dbname */
|
336
|
+
"\\z"
|
337
|
+
;
|
338
|
+
|
339
|
+
#define KEY_USER "user"
|
340
|
+
#define KEY_PASSWORD "password"
|
341
|
+
#define KEY_HOST "host"
|
342
|
+
#define KEY_PORT "port"
|
343
|
+
#define KEY_DBNAME "dbname"
|
344
|
+
|
345
|
+
void
|
346
|
+
connstr_to_hash( VALUE params, VALUE str)
|
347
|
+
{
|
348
|
+
VALUE re, match, m;
|
349
|
+
|
350
|
+
re = rb_reg_new( re_connstr, sizeof re_connstr - 1, 0);
|
351
|
+
if (RTEST( rb_reg_match( re, str))) {
|
352
|
+
match = rb_backref_get();
|
353
|
+
#define ADD_TO_RES( key, n) \
|
354
|
+
m = rb_reg_nth_match( n, match); \
|
355
|
+
if (!NIL_P( m)) rb_hash_aset( params, ID2SYM( rb_intern( key)), m)
|
356
|
+
ADD_TO_RES( KEY_USER, 1);
|
357
|
+
ADD_TO_RES( KEY_PASSWORD, 2);
|
358
|
+
ADD_TO_RES( KEY_HOST, 3);
|
359
|
+
ADD_TO_RES( KEY_PORT, 4);
|
360
|
+
ADD_TO_RES( KEY_DBNAME, 5);
|
361
|
+
#undef ADD_TO_RES
|
362
|
+
} else
|
363
|
+
rb_raise( rb_eArgError, "Invalid connection: %s", RSTRING_PTR( str));
|
364
|
+
}
|
365
|
+
|
366
|
+
void
|
367
|
+
connstr_passwd( VALUE self, VALUE params)
|
368
|
+
{
|
369
|
+
static VALUE sym_password = Qundef;
|
370
|
+
VALUE pw;
|
371
|
+
|
372
|
+
if (sym_password == Qundef)
|
373
|
+
sym_password = ID2SYM( rb_intern( KEY_PASSWORD));
|
374
|
+
pw = rb_hash_aref( params, sym_password);
|
375
|
+
if (TYPE( pw) == T_STRING && RSTRING_LEN( pw) == 0) {
|
376
|
+
static ID id_password_q = 0;
|
377
|
+
VALUE pwobj;
|
378
|
+
|
379
|
+
if (id_password_q == 0)
|
380
|
+
id_password_q = rb_intern( "password?");
|
381
|
+
pwobj = Qundef;
|
382
|
+
if (rb_respond_to( self, id_password_q))
|
383
|
+
pwobj = self;
|
384
|
+
if (rb_respond_to( CLASS_OF( self), id_password_q))
|
385
|
+
pwobj = CLASS_OF( self);
|
386
|
+
if (pwobj != Qundef)
|
387
|
+
rb_hash_aset( params, sym_password,
|
388
|
+
rb_block_call( pwobj, id_password_q, 0, NULL,
|
389
|
+
&connstr_getparam, params));
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
VALUE connstr_getparam( VALUE yielded, VALUE params)
|
394
|
+
{
|
395
|
+
return rb_hash_aref( params, yielded);
|
396
|
+
}
|
397
|
+
|
398
|
+
/*
|
399
|
+
* call-seq:
|
400
|
+
* conn.close()
|
401
|
+
*
|
402
|
+
* Closes the backend connection.
|
403
|
+
*/
|
404
|
+
VALUE
|
405
|
+
pgconn_close( VALUE self)
|
406
|
+
{
|
407
|
+
struct pgconn_data *c;
|
408
|
+
|
409
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
410
|
+
PQfinish( c->conn);
|
411
|
+
c->conn = NULL;
|
412
|
+
return Qnil;
|
413
|
+
}
|
414
|
+
|
415
|
+
/*
|
416
|
+
* call-seq:
|
417
|
+
* conn.reset()
|
418
|
+
*
|
419
|
+
* Resets the backend connection. This method closes the backend connection
|
420
|
+
* and tries to re-connect.
|
421
|
+
*/
|
422
|
+
VALUE
|
423
|
+
pgconn_reset( VALUE self)
|
424
|
+
{
|
425
|
+
PQreset( get_pgconn( self)->conn);
|
426
|
+
return self;
|
427
|
+
}
|
428
|
+
|
429
|
+
|
430
|
+
|
431
|
+
/*
|
432
|
+
* call-seq:
|
433
|
+
* conn.client_encoding() -> str
|
434
|
+
*
|
435
|
+
* Returns the client encoding as a String.
|
436
|
+
*/
|
437
|
+
VALUE
|
438
|
+
pgconn_client_encoding( VALUE self)
|
439
|
+
{
|
440
|
+
char *encoding = (char *) pg_encoding_to_char(
|
441
|
+
PQclientEncoding( get_pgconn( self)->conn));
|
442
|
+
return rb_tainted_str_new2( encoding);
|
443
|
+
}
|
444
|
+
|
445
|
+
/*
|
446
|
+
* call-seq:
|
447
|
+
* conn.set_client_encoding( encoding) -> nil
|
448
|
+
*
|
449
|
+
* Sets the client encoding to the +encoding+ string.
|
450
|
+
*/
|
451
|
+
VALUE
|
452
|
+
pgconn_set_client_encoding( VALUE self, VALUE str)
|
453
|
+
{
|
454
|
+
StringValue( str);
|
455
|
+
if ((PQsetClientEncoding( get_pgconn( self)->conn, RSTRING_PTR( str))) == -1)
|
456
|
+
rb_raise( rb_ePgError, "Invalid encoding name %s", str);
|
457
|
+
return Qnil;
|
458
|
+
}
|
459
|
+
|
460
|
+
|
461
|
+
#ifdef RUBY_ENCODING
|
462
|
+
|
463
|
+
/*
|
464
|
+
* call-seq:
|
465
|
+
* conn.external_encoding -> enc
|
466
|
+
*
|
467
|
+
* Return the external encoding.
|
468
|
+
*/
|
469
|
+
VALUE
|
470
|
+
pgconn_externalenc( VALUE self)
|
471
|
+
{
|
472
|
+
struct pgconn_data *c;
|
473
|
+
|
474
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
475
|
+
return c->external;
|
476
|
+
}
|
477
|
+
|
478
|
+
/*
|
479
|
+
* call-seq:
|
480
|
+
* conn.external_encoding = enc
|
481
|
+
*
|
482
|
+
* Set the external encoding.
|
483
|
+
*/
|
484
|
+
VALUE
|
485
|
+
pgconn_set_externalenc( VALUE self, VALUE enc)
|
486
|
+
{
|
487
|
+
struct pgconn_data *c;
|
488
|
+
rb_encoding *e;
|
489
|
+
|
490
|
+
e = NIL_P( enc) ? rb_to_encoding( enc) : rb_default_external_encoding();
|
491
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
492
|
+
c->external = rb_enc_from_encoding( e);
|
493
|
+
}
|
494
|
+
|
495
|
+
/*
|
496
|
+
* call-seq:
|
497
|
+
* conn.internal_encoding -> enc
|
498
|
+
*
|
499
|
+
* Return the internal encoding.
|
500
|
+
*/
|
501
|
+
VALUE
|
502
|
+
pgconn_internalenc( VALUE self)
|
503
|
+
{
|
504
|
+
struct pgconn_data *c;
|
505
|
+
|
506
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
507
|
+
return c->internal;
|
508
|
+
}
|
509
|
+
|
510
|
+
/*
|
511
|
+
* call-seq:
|
512
|
+
* conn.internal_encoding = enc
|
513
|
+
*
|
514
|
+
* Set the internal encoding.
|
515
|
+
*/
|
516
|
+
VALUE
|
517
|
+
pgconn_set_internalenc( VALUE self, VALUE enc)
|
518
|
+
{
|
519
|
+
struct pgconn_data *c;
|
520
|
+
rb_encoding *e;
|
521
|
+
|
522
|
+
e = NIL_P( enc) ? rb_to_encoding( enc) : rb_default_internal_encoding();
|
523
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
524
|
+
c->internal = rb_enc_from_encoding( e);
|
525
|
+
}
|
526
|
+
|
527
|
+
#endif
|
528
|
+
|
529
|
+
|
530
|
+
|
531
|
+
/*
|
532
|
+
* call-seq:
|
533
|
+
* conn.protocol_version -> Integer
|
534
|
+
*
|
535
|
+
* The 3.0 protocol will normally be used when communicating with PostgreSQL
|
536
|
+
* 7.4 or later servers; pre-7.4 servers support only protocol 2.0. (Protocol
|
537
|
+
* 1.0 is obsolete and not supported by libpq.)
|
538
|
+
*/
|
539
|
+
VALUE
|
540
|
+
pgconn_protocol_version( VALUE self)
|
541
|
+
{
|
542
|
+
return INT2FIX( PQprotocolVersion( get_pgconn( self)->conn));
|
543
|
+
}
|
544
|
+
|
545
|
+
/*
|
546
|
+
* call-seq:
|
547
|
+
* conn.server_version -> Integer
|
548
|
+
*
|
549
|
+
* The number is formed by converting the major, minor, and revision numbers
|
550
|
+
* into two-decimal-digit numbers and appending them together. For example,
|
551
|
+
* version 7.4.2 will be returned as 70402, and version 8.1 will be returned as
|
552
|
+
* 80100 (leading zeroes are not shown). Zero is returned if the connection is
|
553
|
+
* bad.
|
554
|
+
*/
|
555
|
+
VALUE
|
556
|
+
pgconn_server_version( VALUE self)
|
557
|
+
{
|
558
|
+
return INT2FIX( PQserverVersion( get_pgconn( self)->conn));
|
559
|
+
}
|
560
|
+
|
561
|
+
|
562
|
+
/*
|
563
|
+
* call-seq:
|
564
|
+
* conn.db()
|
565
|
+
*
|
566
|
+
* Returns the connected database name.
|
567
|
+
*/
|
568
|
+
VALUE
|
569
|
+
pgconn_dbname( VALUE self)
|
570
|
+
{
|
571
|
+
struct pgconn_data *c;
|
572
|
+
char *db;
|
573
|
+
|
574
|
+
c = get_pgconn( self);
|
575
|
+
db = PQdb( c->conn);
|
576
|
+
return db == NULL ? Qnil : pgconn_mkstring( c, db);
|
577
|
+
}
|
578
|
+
|
579
|
+
/*
|
580
|
+
* call-seq:
|
581
|
+
* conn.host()
|
582
|
+
*
|
583
|
+
* Returns the connected server name.
|
584
|
+
*/
|
585
|
+
VALUE
|
586
|
+
pgconn_host( VALUE self)
|
587
|
+
{
|
588
|
+
struct pgconn_data *c;
|
589
|
+
char *host;
|
590
|
+
|
591
|
+
c = get_pgconn( self);
|
592
|
+
host = PQhost( c->conn);
|
593
|
+
return host == NULL ? Qnil : pgconn_mkstring( c, host);
|
594
|
+
}
|
595
|
+
|
596
|
+
/*
|
597
|
+
* call-seq:
|
598
|
+
* conn.options()
|
599
|
+
*
|
600
|
+
* Returns backend option string.
|
601
|
+
*/
|
602
|
+
VALUE
|
603
|
+
pgconn_options( VALUE self)
|
604
|
+
{
|
605
|
+
struct pgconn_data *c;
|
606
|
+
char *options;
|
607
|
+
|
608
|
+
c = get_pgconn( self);
|
609
|
+
options = PQoptions( c->conn);
|
610
|
+
return options == NULL ? Qnil : pgconn_mkstring( c, options);
|
611
|
+
}
|
612
|
+
|
613
|
+
/*
|
614
|
+
* call-seq:
|
615
|
+
* conn.port()
|
616
|
+
*
|
617
|
+
* Returns the connected server port number.
|
618
|
+
*/
|
619
|
+
VALUE
|
620
|
+
pgconn_port( VALUE self)
|
621
|
+
{
|
622
|
+
char* port = PQport( get_pgconn( self)->conn);
|
623
|
+
return port == NULL ? Qnil : INT2FIX( atol( port));
|
624
|
+
}
|
625
|
+
|
626
|
+
/*
|
627
|
+
* call-seq:
|
628
|
+
* conn.tty()
|
629
|
+
*
|
630
|
+
* Returns the connected pgtty.
|
631
|
+
*/
|
632
|
+
VALUE
|
633
|
+
pgconn_tty( VALUE self)
|
634
|
+
{
|
635
|
+
struct pgconn_data *c;
|
636
|
+
char *tty;
|
637
|
+
|
638
|
+
c = get_pgconn( self);
|
639
|
+
tty = PQtty( c->conn);
|
640
|
+
return tty == NULL ? Qnil : pgconn_mkstring( c, tty);
|
641
|
+
}
|
642
|
+
|
643
|
+
/*
|
644
|
+
* call-seq:
|
645
|
+
* conn.user()
|
646
|
+
*
|
647
|
+
* Returns the authenticated user name.
|
648
|
+
*/
|
649
|
+
VALUE
|
650
|
+
pgconn_user( VALUE self)
|
651
|
+
{
|
652
|
+
struct pgconn_data *c;
|
653
|
+
char *user;
|
654
|
+
|
655
|
+
c = get_pgconn( self);
|
656
|
+
user = PQuser( c->conn);
|
657
|
+
return user == NULL ? Qnil : pgconn_mkstring( c, user);
|
658
|
+
}
|
659
|
+
|
660
|
+
/*
|
661
|
+
* call-seq:
|
662
|
+
* conn.status()
|
663
|
+
*
|
664
|
+
* This may return the values +CONNECTION_OK+ or +CONNECTION_BAD+.
|
665
|
+
*/
|
666
|
+
VALUE
|
667
|
+
pgconn_status( VALUE self)
|
668
|
+
{
|
669
|
+
return INT2FIX( PQstatus( get_pgconn( self)->conn));
|
670
|
+
}
|
671
|
+
|
672
|
+
/*
|
673
|
+
* call-seq:
|
674
|
+
* conn.error()
|
675
|
+
*
|
676
|
+
* Returns the error message about connection.
|
677
|
+
*/
|
678
|
+
VALUE
|
679
|
+
pgconn_error( VALUE self)
|
680
|
+
{
|
681
|
+
struct pgconn_data *c;
|
682
|
+
char *error;
|
683
|
+
|
684
|
+
c = get_pgconn( self);
|
685
|
+
error = PQerrorMessage( c->conn);
|
686
|
+
return error == NULL ? Qnil : pgconn_mkstring( c, error);
|
687
|
+
}
|
688
|
+
|
689
|
+
|
690
|
+
|
691
|
+
/*
|
692
|
+
* call-seq:
|
693
|
+
* conn.socket() -> io
|
694
|
+
*
|
695
|
+
* Returns the sockets IO object.
|
696
|
+
*/
|
697
|
+
VALUE
|
698
|
+
pgconn_socket( VALUE self)
|
699
|
+
{
|
700
|
+
static ID id_new = 0;
|
701
|
+
int fd;
|
702
|
+
|
703
|
+
if (id_new == 0)
|
704
|
+
id_new = rb_intern( "new");
|
705
|
+
|
706
|
+
fd = PQsocket( get_pgconn( self)->conn);
|
707
|
+
return rb_funcall( rb_cIO, id_new, 1, INT2FIX( fd));
|
708
|
+
}
|
709
|
+
|
710
|
+
|
711
|
+
/*
|
712
|
+
* call-seq:
|
713
|
+
* conn.trace( file)
|
714
|
+
* conn.trace( file) { ... }
|
715
|
+
*
|
716
|
+
* Enables tracing message passing between backend.
|
717
|
+
* The trace message will be written to the _file_ object,
|
718
|
+
* which is an instance of the class +File+ (or at least +IO+).
|
719
|
+
*
|
720
|
+
* In case a block is given +untrace+ will be called automatically.
|
721
|
+
*/
|
722
|
+
VALUE
|
723
|
+
pgconn_trace( int argc, VALUE *argv, VALUE self)
|
724
|
+
{
|
725
|
+
VALUE file;
|
726
|
+
#ifdef HAVE_FUNC_RB_IO_STDIO_FILE
|
727
|
+
rb_io_t *fp;
|
728
|
+
#else
|
729
|
+
OpenFile* fp;
|
730
|
+
#define rb_io_stdio_file GetWriteFile
|
731
|
+
#endif
|
732
|
+
|
733
|
+
if (rb_scan_args( argc, argv, "01", &file) > 0) {
|
734
|
+
if (TYPE( file) != T_FILE)
|
735
|
+
rb_raise( rb_eArgError, "Not an IO object: %s",
|
736
|
+
StringValueCStr( file));
|
737
|
+
} else
|
738
|
+
file = rb_stdout;
|
739
|
+
|
740
|
+
GetOpenFile( file, fp);
|
741
|
+
PQtrace( get_pgconn( self)->conn, rb_io_stdio_file( fp));
|
742
|
+
return rb_block_given_p() ?
|
743
|
+
rb_ensure( rb_yield, Qnil, pgconn_untrace, self) : Qnil;
|
744
|
+
}
|
745
|
+
|
746
|
+
/*
|
747
|
+
* call-seq:
|
748
|
+
* conn.untrace()
|
749
|
+
*
|
750
|
+
* Disables the message tracing.
|
751
|
+
*/
|
752
|
+
VALUE
|
753
|
+
pgconn_untrace( VALUE self)
|
754
|
+
{
|
755
|
+
PQuntrace( get_pgconn( self)->conn);
|
756
|
+
return Qnil;
|
757
|
+
}
|
758
|
+
|
759
|
+
|
760
|
+
|
761
|
+
/*
|
762
|
+
* call-seq:
|
763
|
+
* conn.on_notice { |message| ... }
|
764
|
+
*
|
765
|
+
* This method yields a PG::Result::Error object in case a nonfatal exception
|
766
|
+
* was raised.
|
767
|
+
*
|
768
|
+
* == Example
|
769
|
+
*
|
770
|
+
* conn.exec <<-EOT
|
771
|
+
* create or replace function noise() returns void as $$
|
772
|
+
* begin
|
773
|
+
* raise notice 'Hi!';
|
774
|
+
* end;
|
775
|
+
* $$ language plpgsql;
|
776
|
+
* EOT
|
777
|
+
* conn.on_notice { |e| puts e.inspect }
|
778
|
+
* conn.exec "select noise();"
|
779
|
+
*/
|
780
|
+
VALUE
|
781
|
+
pgconn_on_notice( VALUE self)
|
782
|
+
{
|
783
|
+
struct pgconn_data *c;
|
784
|
+
|
785
|
+
Data_Get_Struct( self, struct pgconn_data, c);
|
786
|
+
if (PQsetNoticeReceiver( c->conn, NULL, NULL) != ¬ice_receiver) {
|
787
|
+
PQsetNoticeReceiver( c->conn, ¬ice_receiver, (void *) c);
|
788
|
+
}
|
789
|
+
c->notice = rb_block_given_p() ? rb_block_proc() : Qnil;
|
790
|
+
return self;
|
791
|
+
}
|
792
|
+
|
793
|
+
void
|
794
|
+
notice_receiver( void *self, const PGresult *result)
|
795
|
+
{
|
796
|
+
struct pgconn_data *c;
|
797
|
+
|
798
|
+
c = (struct pgconn_data *) self;
|
799
|
+
if (c->notice != Qnil) {
|
800
|
+
VALUE err;
|
801
|
+
|
802
|
+
err = pgconn_mkstring( c, PQresultErrorMessage( result));
|
803
|
+
rb_proc_call( c->notice, rb_ary_new3( 1l, err));
|
804
|
+
}
|
805
|
+
}
|
806
|
+
|
807
|
+
|
808
|
+
|
809
|
+
|
810
|
+
/********************************************************************
|
811
|
+
*
|
812
|
+
* Document-class: Pg::Conn::Failed
|
813
|
+
*
|
814
|
+
* Error while establishing a connection to the PostgreSQL server.
|
815
|
+
*/
|
816
|
+
|
817
|
+
/********************************************************************
|
818
|
+
*
|
819
|
+
* Document-class: Pg::Conn::Invalid
|
820
|
+
*
|
821
|
+
* Invalid (closed) connection.
|
822
|
+
*/
|
823
|
+
|
824
|
+
|
825
|
+
/********************************************************************
|
826
|
+
*
|
827
|
+
* Document-class: Pg::Conn
|
828
|
+
*
|
829
|
+
* The class to access a PostgreSQL database.
|
830
|
+
*
|
831
|
+
* == Example
|
832
|
+
*
|
833
|
+
* require "pgsql"
|
834
|
+
* conn = Pg::Conn.open :dbname => "test1"
|
835
|
+
* res = conn.exec "select * from mytable;"
|
836
|
+
*
|
837
|
+
* See the Pg::Result class for information on working with the results of a
|
838
|
+
* query.
|
839
|
+
*/
|
840
|
+
|
841
|
+
void
|
842
|
+
Init_pgsql_conn( void)
|
843
|
+
{
|
844
|
+
#ifdef RDOC_NEEDS_THIS
|
845
|
+
rb_mPg = rb_define_module( "Pg");
|
846
|
+
#endif
|
847
|
+
|
848
|
+
rb_cPgConn = rb_define_class_under( rb_mPg, "Conn", rb_cObject);
|
849
|
+
|
850
|
+
rb_ePgConnFailed = rb_define_class_under( rb_cPgConn, "Failed", rb_ePgError);
|
851
|
+
rb_undef_method( CLASS_OF( rb_ePgConnFailed), "new");
|
852
|
+
rb_define_attr( rb_ePgConnFailed, "parameters", 1, 0);
|
853
|
+
|
854
|
+
rb_ePgConnInvalid = rb_define_class_under( rb_cPgConn, "Invalid", rb_ePgError);
|
855
|
+
|
856
|
+
rb_define_alloc_func( rb_cPgConn, pgconn_alloc);
|
857
|
+
rb_define_singleton_method( rb_cPgConn, "connect", pgconn_s_connect, -1);
|
858
|
+
rb_define_alias( rb_singleton_class( rb_cPgConn), "open", "connect");
|
859
|
+
rb_define_singleton_method( rb_cPgConn, "parse", pgconn_s_parse, 1);
|
860
|
+
rb_define_method( rb_cPgConn, "initialize", &pgconn_init, -1);
|
861
|
+
rb_define_method( rb_cPgConn, "close", &pgconn_close, 0);
|
862
|
+
rb_define_alias( rb_cPgConn, "finish", "close");
|
863
|
+
rb_define_method( rb_cPgConn, "reset", &pgconn_reset, 0);
|
864
|
+
|
865
|
+
rb_define_method( rb_cPgConn, "client_encoding", &pgconn_client_encoding, 0);
|
866
|
+
rb_define_method( rb_cPgConn, "set_client_encoding", &pgconn_set_client_encoding, 1);
|
867
|
+
#ifdef RUBY_ENCODING
|
868
|
+
rb_define_method( rb_cPgConn, "external_encoding", &pgconn_externalenc, 0);
|
869
|
+
rb_define_method( rb_cPgConn, "external_encoding=", &pgconn_set_externalenc, 1);
|
870
|
+
rb_define_method( rb_cPgConn, "internal_encoding", &pgconn_internalenc, 0);
|
871
|
+
rb_define_method( rb_cPgConn, "internal_encoding=", &pgconn_set_internalenc, 1);
|
872
|
+
#endif
|
873
|
+
|
874
|
+
rb_define_method( rb_cPgConn, "protocol_version", &pgconn_protocol_version, 0);
|
875
|
+
rb_define_method( rb_cPgConn, "server_version", &pgconn_server_version, 0);
|
876
|
+
|
877
|
+
rb_define_method( rb_cPgConn, "dbname", &pgconn_dbname, 0);
|
878
|
+
rb_define_alias( rb_cPgConn, "db", "dbname");
|
879
|
+
rb_define_method( rb_cPgConn, "host", &pgconn_host, 0);
|
880
|
+
rb_define_method( rb_cPgConn, "options", &pgconn_options, 0);
|
881
|
+
rb_define_method( rb_cPgConn, "port", &pgconn_port, 0);
|
882
|
+
rb_define_method( rb_cPgConn, "tty", &pgconn_tty, 0);
|
883
|
+
rb_define_method( rb_cPgConn, "user", &pgconn_user, 0);
|
884
|
+
rb_define_method( rb_cPgConn, "status", &pgconn_status, 0);
|
885
|
+
rb_define_method( rb_cPgConn, "error", &pgconn_error, 0);
|
886
|
+
|
887
|
+
#define CONN_DEF( c) rb_define_const( rb_cPgConn, #c, INT2FIX( CONNECTION_ ## c))
|
888
|
+
CONN_DEF( OK);
|
889
|
+
CONN_DEF( BAD);
|
890
|
+
#undef CONN_DEF
|
891
|
+
|
892
|
+
rb_define_method( rb_cPgConn, "socket", &pgconn_socket, 0);
|
893
|
+
|
894
|
+
rb_define_method( rb_cPgConn, "trace", &pgconn_trace, -1);
|
895
|
+
rb_define_method( rb_cPgConn, "untrace", &pgconn_untrace, 0);
|
896
|
+
|
897
|
+
rb_define_method( rb_cPgConn, "on_notice", &pgconn_on_notice, 0);
|
898
|
+
|
899
|
+
Init_pgsql_conn_quote();
|
900
|
+
Init_pgsql_conn_exec();
|
901
|
+
}
|
902
|
+
|