pg 0.15.0.pre.454-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/BSDL +22 -0
- data/ChangeLog +2945 -0
- data/Contributors.rdoc +46 -0
- data/History.rdoc +205 -0
- data/LICENSE +56 -0
- data/Manifest.txt +53 -0
- data/POSTGRES +23 -0
- data/README-OS_X.rdoc +68 -0
- data/README-Windows.rdoc +67 -0
- data/README.ja.rdoc +14 -0
- data/README.rdoc +111 -0
- data/Rakefile +156 -0
- data/Rakefile.cross +271 -0
- data/ext/extconf.rb +91 -0
- data/ext/gvl_wrappers.c +13 -0
- data/ext/gvl_wrappers.h +185 -0
- data/ext/pg.c +525 -0
- data/ext/pg.h +126 -0
- data/ext/pg_connection.c +3600 -0
- data/ext/pg_result.c +939 -0
- data/ext/vc/pg.sln +26 -0
- data/ext/vc/pg_18/pg.vcproj +216 -0
- data/ext/vc/pg_19/pg_19.vcproj +209 -0
- data/lib/2.0/pg_ext.so +0 -0
- data/lib/pg.rb +52 -0
- data/lib/pg/connection.rb +71 -0
- data/lib/pg/constants.rb +11 -0
- data/lib/pg/exceptions.rb +11 -0
- data/lib/pg/result.rb +16 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +106 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +186 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +294 -0
- data/sample/replication_monitor.rb +231 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +320 -0
- data/spec/data/expected_trace.out +26 -0
- data/spec/data/random_binary_data +0 -0
- data/spec/lib/helpers.rb +279 -0
- data/spec/pg/connection_spec.rb +1013 -0
- data/spec/pg/result_spec.rb +278 -0
- data/spec/pg_spec.rb +31 -0
- metadata +275 -0
- metadata.gz.sig +0 -0
data/ext/pg.h
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
#ifndef __pg_h
|
2
|
+
#define __pg_h
|
3
|
+
|
4
|
+
#ifdef RUBY_EXTCONF_H
|
5
|
+
# include RUBY_EXTCONF_H
|
6
|
+
#endif
|
7
|
+
|
8
|
+
/* System headers */
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <sys/types.h>
|
12
|
+
#if defined(HAVE_UNISTD_H) && !defined(_WIN32)
|
13
|
+
# include <unistd.h>
|
14
|
+
#endif /* HAVE_UNISTD_H */
|
15
|
+
|
16
|
+
/* Ruby headers */
|
17
|
+
#include "ruby.h"
|
18
|
+
#ifdef HAVE_RUBY_ST_H
|
19
|
+
# include "ruby/st.h"
|
20
|
+
#elif HAVE_ST_H
|
21
|
+
# include "st.h"
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
|
25
|
+
# include "ruby/encoding.h"
|
26
|
+
# define M17N_SUPPORTED
|
27
|
+
# define ASSOCIATE_INDEX( obj, index_holder ) rb_enc_associate_index((obj), pg_enc_get_index((index_holder)))
|
28
|
+
# ifdef HAVE_RB_ENCDB_ALIAS
|
29
|
+
extern int rb_encdb_alias(const char *, const char *);
|
30
|
+
# define ENC_ALIAS(name, orig) rb_encdb_alias((name), (orig))
|
31
|
+
# elif HAVE_RB_ENC_ALIAS
|
32
|
+
extern int rb_enc_alias(const char *, const char *);
|
33
|
+
# define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
|
34
|
+
# else
|
35
|
+
extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
|
36
|
+
# define ENC_ALIAS(name, orig) rb_enc_alias((name), (orig))
|
37
|
+
# endif
|
38
|
+
#else
|
39
|
+
# define ASSOCIATE_INDEX( obj, index_holder ) /* nothing */
|
40
|
+
#endif
|
41
|
+
|
42
|
+
#if RUBY_VM != 1
|
43
|
+
# define RUBY_18_COMPAT
|
44
|
+
#endif
|
45
|
+
|
46
|
+
#ifndef RARRAY_LEN
|
47
|
+
# define RARRAY_LEN(x) RARRAY((x))->len
|
48
|
+
#endif /* RARRAY_LEN */
|
49
|
+
|
50
|
+
#ifndef RSTRING_LEN
|
51
|
+
# define RSTRING_LEN(x) RSTRING((x))->len
|
52
|
+
#endif /* RSTRING_LEN */
|
53
|
+
|
54
|
+
#ifndef RSTRING_PTR
|
55
|
+
# define RSTRING_PTR(x) RSTRING((x))->ptr
|
56
|
+
#endif /* RSTRING_PTR */
|
57
|
+
|
58
|
+
#ifndef StringValuePtr
|
59
|
+
# define StringValuePtr(x) STR2CSTR(x)
|
60
|
+
#endif /* StringValuePtr */
|
61
|
+
|
62
|
+
#ifdef RUBY_18_COMPAT
|
63
|
+
# define rb_io_stdio_file GetWriteFile
|
64
|
+
# include "rubyio.h"
|
65
|
+
#else
|
66
|
+
# include "ruby/io.h"
|
67
|
+
#endif
|
68
|
+
|
69
|
+
/* PostgreSQL headers */
|
70
|
+
#include "libpq-fe.h"
|
71
|
+
#include "libpq/libpq-fs.h" /* large-object interface */
|
72
|
+
#include "pg_config_manual.h"
|
73
|
+
|
74
|
+
#if defined(_WIN32)
|
75
|
+
# include <fcntl.h>
|
76
|
+
__declspec(dllexport)
|
77
|
+
typedef long suseconds_t;
|
78
|
+
#endif
|
79
|
+
|
80
|
+
#include "gvl_wrappers.h"
|
81
|
+
|
82
|
+
/***************************************************************************
|
83
|
+
* Globals
|
84
|
+
**************************************************************************/
|
85
|
+
|
86
|
+
extern VALUE rb_mPG;
|
87
|
+
extern VALUE rb_ePGerror;
|
88
|
+
extern VALUE rb_mPGconstants;
|
89
|
+
extern VALUE rb_cPGconn;
|
90
|
+
extern VALUE rb_cPGresult;
|
91
|
+
|
92
|
+
|
93
|
+
/***************************************************************************
|
94
|
+
* MACROS
|
95
|
+
**************************************************************************/
|
96
|
+
|
97
|
+
#define UNUSED(x) ((void)(x))
|
98
|
+
#define SINGLETON_ALIAS(klass,new,old) rb_define_alias(rb_singleton_class((klass)),(new),(old))
|
99
|
+
|
100
|
+
|
101
|
+
/***************************************************************************
|
102
|
+
* PROTOTYPES
|
103
|
+
**************************************************************************/
|
104
|
+
void Init_pg_ext _(( void ));
|
105
|
+
|
106
|
+
void init_pg_connection _(( void ));
|
107
|
+
void init_pg_result _(( void ));
|
108
|
+
|
109
|
+
PGconn *pg_get_pgconn _(( VALUE ));
|
110
|
+
|
111
|
+
VALUE pg_new_result _(( PGresult *, VALUE ));
|
112
|
+
VALUE pg_result_check _(( VALUE ));
|
113
|
+
VALUE pg_result_clear _(( VALUE ));
|
114
|
+
|
115
|
+
#ifdef M17N_SUPPORTED
|
116
|
+
rb_encoding * pg_get_pg_encoding_as_rb_encoding _(( int ));
|
117
|
+
rb_encoding * pg_get_pg_encname_as_rb_encoding _(( const char * ));
|
118
|
+
const char * pg_get_rb_encoding_as_pg_encoding _(( rb_encoding * ));
|
119
|
+
int pg_enc_get_index _(( VALUE ));
|
120
|
+
rb_encoding *pg_conn_enc_get _(( PGconn * ));
|
121
|
+
#endif /* M17N_SUPPORTED */
|
122
|
+
|
123
|
+
void notice_receiver_proxy(void *arg, const PGresult *result);
|
124
|
+
void notice_processor_proxy(void *arg, const char *message);
|
125
|
+
|
126
|
+
#endif /* end __pg_h */
|
data/ext/pg_connection.c
ADDED
@@ -0,0 +1,3600 @@
|
|
1
|
+
/*
|
2
|
+
* pg_connection.c - PG::Connection class extension
|
3
|
+
* $Id$
|
4
|
+
*
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "pg.h"
|
8
|
+
|
9
|
+
|
10
|
+
/********************************************************************
|
11
|
+
*
|
12
|
+
* Document-class: PG::Connection
|
13
|
+
*
|
14
|
+
* The class to access PostgreSQL RDBMS, based on the libpq interface,
|
15
|
+
* provides convenient OO methods to interact with PostgreSQL.
|
16
|
+
*
|
17
|
+
* For example, to send query to the database on the localhost:
|
18
|
+
* require 'pg'
|
19
|
+
* conn = PG::Connection.open(:dbname => 'test')
|
20
|
+
* res = conn.exec('SELECT $1 AS a, $2 AS b, $3 AS c',[1, 2, nil])
|
21
|
+
* # Equivalent to:
|
22
|
+
* # res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
23
|
+
*
|
24
|
+
* See the PG::Result class for information on working with the results of a query.
|
25
|
+
*
|
26
|
+
*/
|
27
|
+
VALUE rb_cPGconn;
|
28
|
+
|
29
|
+
static PQnoticeReceiver default_notice_receiver = NULL;
|
30
|
+
static PQnoticeProcessor default_notice_processor = NULL;
|
31
|
+
|
32
|
+
static PGconn *pgconn_check( VALUE );
|
33
|
+
static VALUE pgconn_finish( VALUE );
|
34
|
+
#ifdef M17N_SUPPORTED
|
35
|
+
static VALUE pgconn_set_default_encoding( VALUE self );
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#ifndef HAVE_RB_THREAD_FD_SELECT
|
39
|
+
#define rb_fdset_t fd_set
|
40
|
+
#define rb_fd_init(f)
|
41
|
+
#define rb_fd_zero(f) FD_ZERO(f)
|
42
|
+
#define rb_fd_set(n, f) FD_SET(n, f)
|
43
|
+
#define rb_fd_term(f)
|
44
|
+
#define rb_thread_fd_select rb_thread_select
|
45
|
+
#endif
|
46
|
+
|
47
|
+
/*
|
48
|
+
* Global functions
|
49
|
+
*/
|
50
|
+
|
51
|
+
/*
|
52
|
+
* Fetch the data pointer and check it for sanity.
|
53
|
+
*/
|
54
|
+
PGconn *
|
55
|
+
pg_get_pgconn( VALUE self )
|
56
|
+
{
|
57
|
+
PGconn *conn = pgconn_check( self );
|
58
|
+
|
59
|
+
if ( !conn )
|
60
|
+
rb_raise( rb_ePGerror, "connection is closed" );
|
61
|
+
|
62
|
+
return conn;
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
/*
|
67
|
+
* Close the associated socket IO object if there is one.
|
68
|
+
*/
|
69
|
+
void
|
70
|
+
pgconn_close_socket_io( VALUE self )
|
71
|
+
{
|
72
|
+
VALUE socket_io = rb_iv_get( self, "@socket_io" );
|
73
|
+
int ruby_sd;
|
74
|
+
|
75
|
+
if ( RTEST(socket_io) ) {
|
76
|
+
#if defined(_WIN32) && defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
77
|
+
ruby_sd = NUM2INT(rb_funcall( socket_io, rb_intern("fileno"), 0 ));
|
78
|
+
if( rb_w32_unwrap_io_handle(ruby_sd) ){
|
79
|
+
rb_raise(rb_ePGerror, "Could not unwrap win32 socket handle");
|
80
|
+
}
|
81
|
+
#endif
|
82
|
+
rb_funcall( socket_io, rb_intern("close"), 0 );
|
83
|
+
}
|
84
|
+
|
85
|
+
rb_iv_set( self, "@socket_io", Qnil );
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
/*
|
90
|
+
* Allocation/
|
91
|
+
*/
|
92
|
+
|
93
|
+
/*
|
94
|
+
* Object validity checker. Returns the data pointer.
|
95
|
+
*/
|
96
|
+
static PGconn *
|
97
|
+
pgconn_check( VALUE self ) {
|
98
|
+
|
99
|
+
Check_Type( self, T_DATA );
|
100
|
+
|
101
|
+
if ( !rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
102
|
+
rb_raise( rb_eTypeError, "wrong argument type %s (expected PG::Connection)",
|
103
|
+
rb_obj_classname( self ) );
|
104
|
+
}
|
105
|
+
|
106
|
+
return DATA_PTR( self );
|
107
|
+
}
|
108
|
+
|
109
|
+
|
110
|
+
/*
|
111
|
+
* GC Free function
|
112
|
+
*/
|
113
|
+
static void
|
114
|
+
pgconn_gc_free( PGconn *conn )
|
115
|
+
{
|
116
|
+
if (conn != NULL)
|
117
|
+
PQfinish( conn );
|
118
|
+
}
|
119
|
+
|
120
|
+
|
121
|
+
/**************************************************************************
|
122
|
+
* Class Methods
|
123
|
+
**************************************************************************/
|
124
|
+
|
125
|
+
/*
|
126
|
+
* Document-method: allocate
|
127
|
+
*
|
128
|
+
* call-seq:
|
129
|
+
* PG::Connection.allocate -> conn
|
130
|
+
*/
|
131
|
+
static VALUE
|
132
|
+
pgconn_s_allocate( VALUE klass )
|
133
|
+
{
|
134
|
+
return Data_Wrap_Struct( klass, NULL, pgconn_gc_free, NULL );
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
/*
|
139
|
+
* Document-method: new
|
140
|
+
*
|
141
|
+
* call-seq:
|
142
|
+
* PG::Connection.new -> conn
|
143
|
+
* PG::Connection.new(connection_hash) -> conn
|
144
|
+
* PG::Connection.new(connection_string) -> conn
|
145
|
+
* PG::Connection.new(host, port, options, tty, dbname, user, password) -> conn
|
146
|
+
*
|
147
|
+
* Create a connection to the specified server.
|
148
|
+
*
|
149
|
+
* [+host+]
|
150
|
+
* server hostname
|
151
|
+
* [+hostaddr+]
|
152
|
+
* server address (avoids hostname lookup, overrides +host+)
|
153
|
+
* [+port+]
|
154
|
+
* server port number
|
155
|
+
* [+dbname+]
|
156
|
+
* connecting database name
|
157
|
+
* [+user+]
|
158
|
+
* login user name
|
159
|
+
* [+password+]
|
160
|
+
* login password
|
161
|
+
* [+connect_timeout+]
|
162
|
+
* maximum time to wait for connection to succeed
|
163
|
+
* [+options+]
|
164
|
+
* backend options
|
165
|
+
* [+tty+]
|
166
|
+
* (ignored in newer versions of PostgreSQL)
|
167
|
+
* [+sslmode+]
|
168
|
+
* (disable|allow|prefer|require)
|
169
|
+
* [+krbsrvname+]
|
170
|
+
* kerberos service name
|
171
|
+
* [+gsslib+]
|
172
|
+
* GSS library to use for GSSAPI authentication
|
173
|
+
* [+service+]
|
174
|
+
* service name to use for additional parameters
|
175
|
+
*
|
176
|
+
* Examples:
|
177
|
+
*
|
178
|
+
* # Connect using all defaults
|
179
|
+
* PG::Connection.new
|
180
|
+
*
|
181
|
+
* # As a Hash
|
182
|
+
* PG::Connection.new( :dbname => 'test', :port => 5432 )
|
183
|
+
*
|
184
|
+
* # As a String
|
185
|
+
* PG::Connection.new( "dbname=test port=5432" )
|
186
|
+
*
|
187
|
+
* # As an Array
|
188
|
+
* PG::Connection.new( nil, 5432, nil, nil, 'test', nil, nil )
|
189
|
+
*
|
190
|
+
* If the Ruby default internal encoding is set (i.e., Encoding.default_internal != nil), the
|
191
|
+
* connection will have its +client_encoding+ set accordingly.
|
192
|
+
*
|
193
|
+
* Raises a PG::Error if the connection fails.
|
194
|
+
*/
|
195
|
+
static VALUE
|
196
|
+
pgconn_init(int argc, VALUE *argv, VALUE self)
|
197
|
+
{
|
198
|
+
PGconn *conn = NULL;
|
199
|
+
VALUE conninfo;
|
200
|
+
VALUE error;
|
201
|
+
|
202
|
+
conninfo = rb_funcall2( rb_cPGconn, rb_intern("parse_connect_args"), argc, argv );
|
203
|
+
conn = PQconnectdb(StringValuePtr(conninfo));
|
204
|
+
|
205
|
+
if(conn == NULL)
|
206
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
207
|
+
|
208
|
+
Check_Type(self, T_DATA);
|
209
|
+
DATA_PTR(self) = conn;
|
210
|
+
|
211
|
+
if (PQstatus(conn) == CONNECTION_BAD) {
|
212
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
213
|
+
rb_iv_set(error, "@connection", self);
|
214
|
+
rb_exc_raise(error);
|
215
|
+
}
|
216
|
+
|
217
|
+
#ifdef M17N_SUPPORTED
|
218
|
+
pgconn_set_default_encoding( self );
|
219
|
+
#endif
|
220
|
+
|
221
|
+
if (rb_block_given_p()) {
|
222
|
+
return rb_ensure(rb_yield, self, pgconn_finish, self);
|
223
|
+
}
|
224
|
+
return self;
|
225
|
+
}
|
226
|
+
|
227
|
+
/*
|
228
|
+
* call-seq:
|
229
|
+
* PG::Connection.connect_start(connection_hash) -> conn
|
230
|
+
* PG::Connection.connect_start(connection_string) -> conn
|
231
|
+
* PG::Connection.connect_start(host, port, options, tty, dbname, login, password) -> conn
|
232
|
+
*
|
233
|
+
* This is an asynchronous version of PG::Connection.connect().
|
234
|
+
*
|
235
|
+
* Use #connect_poll to poll the status of the connection.
|
236
|
+
*
|
237
|
+
* NOTE: this does *not* set the connection's +client_encoding+ for you if
|
238
|
+
* Encoding.default_internal is set. To set it after the connection is established,
|
239
|
+
* call #internal_encoding=. You can also set it automatically by setting
|
240
|
+
* ENV['PGCLIENTENCODING'], or include the 'options' connection parameter.
|
241
|
+
*
|
242
|
+
*/
|
243
|
+
static VALUE
|
244
|
+
pgconn_s_connect_start( int argc, VALUE *argv, VALUE klass )
|
245
|
+
{
|
246
|
+
PGconn *conn = NULL;
|
247
|
+
VALUE rb_conn;
|
248
|
+
VALUE conninfo;
|
249
|
+
VALUE error;
|
250
|
+
|
251
|
+
/*
|
252
|
+
* PG::Connection.connect_start must act as both alloc() and initialize()
|
253
|
+
* because it is not invoked by calling new().
|
254
|
+
*/
|
255
|
+
rb_conn = pgconn_s_allocate( klass );
|
256
|
+
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
257
|
+
conn = PQconnectStart( StringValuePtr(conninfo) );
|
258
|
+
|
259
|
+
if( conn == NULL )
|
260
|
+
rb_raise(rb_ePGerror, "PQconnectStart() unable to allocate structure");
|
261
|
+
|
262
|
+
Check_Type(rb_conn, T_DATA);
|
263
|
+
DATA_PTR(rb_conn) = conn;
|
264
|
+
|
265
|
+
if ( PQstatus(conn) == CONNECTION_BAD ) {
|
266
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
267
|
+
rb_iv_set(error, "@connection", rb_conn);
|
268
|
+
rb_exc_raise(error);
|
269
|
+
}
|
270
|
+
|
271
|
+
if ( rb_block_given_p() ) {
|
272
|
+
return rb_ensure( rb_yield, rb_conn, pgconn_finish, rb_conn );
|
273
|
+
}
|
274
|
+
return rb_conn;
|
275
|
+
}
|
276
|
+
|
277
|
+
#ifdef HAVE_PQPING
|
278
|
+
/*
|
279
|
+
* call-seq:
|
280
|
+
* PG::Connection.ping(connection_hash) -> Fixnum
|
281
|
+
* PG::Connection.ping(connection_string) -> Fixnum
|
282
|
+
* PG::Connection.ping(host, port, options, tty, dbname, login, password) -> Fixnum
|
283
|
+
*
|
284
|
+
* Check server status.
|
285
|
+
*
|
286
|
+
* Returns one of:
|
287
|
+
* [+PQPING_OK+]
|
288
|
+
* server is accepting connections
|
289
|
+
* [+PQPING_REJECT+]
|
290
|
+
* server is alive but rejecting connections
|
291
|
+
* [+PQPING_NO_RESPONSE+]
|
292
|
+
* could not establish connection
|
293
|
+
* [+PQPING_NO_ATTEMPT+]
|
294
|
+
* connection not attempted (bad params)
|
295
|
+
*/
|
296
|
+
static VALUE
|
297
|
+
pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
298
|
+
{
|
299
|
+
PGPing ping;
|
300
|
+
VALUE conninfo;
|
301
|
+
|
302
|
+
conninfo = rb_funcall2( klass, rb_intern("parse_connect_args"), argc, argv );
|
303
|
+
ping = PQping( StringValuePtr(conninfo) );
|
304
|
+
|
305
|
+
return INT2FIX((int)ping);
|
306
|
+
}
|
307
|
+
#endif
|
308
|
+
|
309
|
+
/*
|
310
|
+
* call-seq:
|
311
|
+
* PG::Connection.conndefaults() -> Array
|
312
|
+
*
|
313
|
+
* Returns an array of hashes. Each hash has the keys:
|
314
|
+
* [+:keyword+]
|
315
|
+
* the name of the option
|
316
|
+
* [+:envvar+]
|
317
|
+
* the environment variable to fall back to
|
318
|
+
* [+:compiled+]
|
319
|
+
* the compiled in option as a secondary fallback
|
320
|
+
* [+:val+]
|
321
|
+
* the option's current value, or +nil+ if not known
|
322
|
+
* [+:label+]
|
323
|
+
* the label for the field
|
324
|
+
* [+:dispchar+]
|
325
|
+
* "" for normal, "D" for debug, and "*" for password
|
326
|
+
* [+:dispsize+]
|
327
|
+
* field size
|
328
|
+
*/
|
329
|
+
static VALUE
|
330
|
+
pgconn_s_conndefaults(VALUE self)
|
331
|
+
{
|
332
|
+
PQconninfoOption *options = PQconndefaults();
|
333
|
+
VALUE ary = rb_ary_new();
|
334
|
+
VALUE hash;
|
335
|
+
int i = 0;
|
336
|
+
|
337
|
+
UNUSED( self );
|
338
|
+
|
339
|
+
for(i = 0; options[i].keyword != NULL; i++) {
|
340
|
+
hash = rb_hash_new();
|
341
|
+
if(options[i].keyword)
|
342
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("keyword")), rb_str_new2(options[i].keyword));
|
343
|
+
if(options[i].envvar)
|
344
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("envvar")), rb_str_new2(options[i].envvar));
|
345
|
+
if(options[i].compiled)
|
346
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("compiled")), rb_str_new2(options[i].compiled));
|
347
|
+
if(options[i].val)
|
348
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("val")), rb_str_new2(options[i].val));
|
349
|
+
if(options[i].label)
|
350
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("label")), rb_str_new2(options[i].label));
|
351
|
+
if(options[i].dispchar)
|
352
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")), rb_str_new2(options[i].dispchar));
|
353
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")), INT2NUM(options[i].dispsize));
|
354
|
+
rb_ary_push(ary, hash);
|
355
|
+
}
|
356
|
+
PQconninfoFree(options);
|
357
|
+
return ary;
|
358
|
+
}
|
359
|
+
|
360
|
+
|
361
|
+
/*
|
362
|
+
* call-seq:
|
363
|
+
* PG::Connection.encrypt_password( password, username ) -> String
|
364
|
+
*
|
365
|
+
* This function is intended to be used by client applications that
|
366
|
+
* send commands like: +ALTER USER joe PASSWORD 'pwd'+.
|
367
|
+
* The arguments are the cleartext password, and the SQL name
|
368
|
+
* of the user it is for.
|
369
|
+
*
|
370
|
+
* Return value is the encrypted password.
|
371
|
+
*/
|
372
|
+
static VALUE
|
373
|
+
pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
374
|
+
{
|
375
|
+
char *encrypted = NULL;
|
376
|
+
VALUE rval = Qnil;
|
377
|
+
|
378
|
+
UNUSED( self );
|
379
|
+
|
380
|
+
Check_Type(password, T_STRING);
|
381
|
+
Check_Type(username, T_STRING);
|
382
|
+
|
383
|
+
encrypted = PQencryptPassword(StringValuePtr(password), StringValuePtr(username));
|
384
|
+
rval = rb_str_new2( encrypted );
|
385
|
+
PQfreemem( encrypted );
|
386
|
+
|
387
|
+
OBJ_INFECT( rval, password );
|
388
|
+
OBJ_INFECT( rval, username );
|
389
|
+
|
390
|
+
return rval;
|
391
|
+
}
|
392
|
+
|
393
|
+
|
394
|
+
/**************************************************************************
|
395
|
+
* PG::Connection INSTANCE METHODS
|
396
|
+
**************************************************************************/
|
397
|
+
|
398
|
+
/*
|
399
|
+
* call-seq:
|
400
|
+
* conn.connect_poll() -> Fixnum
|
401
|
+
*
|
402
|
+
* Returns one of:
|
403
|
+
* [+PGRES_POLLING_READING+]
|
404
|
+
* wait until the socket is ready to read
|
405
|
+
* [+PGRES_POLLING_WRITING+]
|
406
|
+
* wait until the socket is ready to write
|
407
|
+
* [+PGRES_POLLING_FAILED+]
|
408
|
+
* the asynchronous connection has failed
|
409
|
+
* [+PGRES_POLLING_OK+]
|
410
|
+
* the asynchronous connection is ready
|
411
|
+
*
|
412
|
+
* Example:
|
413
|
+
* conn = PG::Connection.connect_start("dbname=mydatabase")
|
414
|
+
* socket = conn.socket_io
|
415
|
+
* status = conn.connect_poll
|
416
|
+
* while(status != PG::PGRES_POLLING_OK) do
|
417
|
+
* # do some work while waiting for the connection to complete
|
418
|
+
* if(status == PG::PGRES_POLLING_READING)
|
419
|
+
* if(not select([socket], [], [], 10.0))
|
420
|
+
* raise "Asynchronous connection timed out!"
|
421
|
+
* end
|
422
|
+
* elsif(status == PG::PGRES_POLLING_WRITING)
|
423
|
+
* if(not select([], [socket], [], 10.0))
|
424
|
+
* raise "Asynchronous connection timed out!"
|
425
|
+
* end
|
426
|
+
* end
|
427
|
+
* status = conn.connect_poll
|
428
|
+
* end
|
429
|
+
* # now conn.status == CONNECTION_OK, and connection
|
430
|
+
* # is ready.
|
431
|
+
*/
|
432
|
+
static VALUE
|
433
|
+
pgconn_connect_poll(VALUE self)
|
434
|
+
{
|
435
|
+
PostgresPollingStatusType status;
|
436
|
+
status = PQconnectPoll(pg_get_pgconn(self));
|
437
|
+
return INT2FIX((int)status);
|
438
|
+
}
|
439
|
+
|
440
|
+
/*
|
441
|
+
* call-seq:
|
442
|
+
* conn.finish
|
443
|
+
*
|
444
|
+
* Closes the backend connection.
|
445
|
+
*/
|
446
|
+
static VALUE
|
447
|
+
pgconn_finish( VALUE self )
|
448
|
+
{
|
449
|
+
pgconn_close_socket_io( self );
|
450
|
+
PQfinish( pg_get_pgconn(self) );
|
451
|
+
DATA_PTR( self ) = NULL;
|
452
|
+
return Qnil;
|
453
|
+
}
|
454
|
+
|
455
|
+
|
456
|
+
/*
|
457
|
+
* call-seq:
|
458
|
+
* conn.finished? -> boolean
|
459
|
+
*
|
460
|
+
* Returns +true+ if the backend connection has been closed.
|
461
|
+
*/
|
462
|
+
static VALUE
|
463
|
+
pgconn_finished_p( VALUE self )
|
464
|
+
{
|
465
|
+
if ( DATA_PTR(self) ) return Qfalse;
|
466
|
+
return Qtrue;
|
467
|
+
}
|
468
|
+
|
469
|
+
|
470
|
+
/*
|
471
|
+
* call-seq:
|
472
|
+
* conn.reset()
|
473
|
+
*
|
474
|
+
* Resets the backend connection. This method closes the
|
475
|
+
* backend connection and tries to re-connect.
|
476
|
+
*/
|
477
|
+
static VALUE
|
478
|
+
pgconn_reset( VALUE self )
|
479
|
+
{
|
480
|
+
pgconn_close_socket_io( self );
|
481
|
+
PQreset( pg_get_pgconn(self) );
|
482
|
+
return self;
|
483
|
+
}
|
484
|
+
|
485
|
+
/*
|
486
|
+
* call-seq:
|
487
|
+
* conn.reset_start() -> nil
|
488
|
+
*
|
489
|
+
* Initiate a connection reset in a nonblocking manner.
|
490
|
+
* This will close the current connection and attempt to
|
491
|
+
* reconnect using the same connection parameters.
|
492
|
+
* Use #reset_poll to check the status of the
|
493
|
+
* connection reset.
|
494
|
+
*/
|
495
|
+
static VALUE
|
496
|
+
pgconn_reset_start(VALUE self)
|
497
|
+
{
|
498
|
+
pgconn_close_socket_io( self );
|
499
|
+
if(PQresetStart(pg_get_pgconn(self)) == 0)
|
500
|
+
rb_raise(rb_ePGerror, "reset has failed");
|
501
|
+
return Qnil;
|
502
|
+
}
|
503
|
+
|
504
|
+
/*
|
505
|
+
* call-seq:
|
506
|
+
* conn.reset_poll -> Fixnum
|
507
|
+
*
|
508
|
+
* Checks the status of a connection reset operation.
|
509
|
+
* See #connect_start and #connect_poll for
|
510
|
+
* usage information and return values.
|
511
|
+
*/
|
512
|
+
static VALUE
|
513
|
+
pgconn_reset_poll(VALUE self)
|
514
|
+
{
|
515
|
+
PostgresPollingStatusType status;
|
516
|
+
status = PQresetPoll(pg_get_pgconn(self));
|
517
|
+
return INT2FIX((int)status);
|
518
|
+
}
|
519
|
+
|
520
|
+
/*
|
521
|
+
* call-seq:
|
522
|
+
* conn.db()
|
523
|
+
*
|
524
|
+
* Returns the connected database name.
|
525
|
+
*/
|
526
|
+
static VALUE
|
527
|
+
pgconn_db(VALUE self)
|
528
|
+
{
|
529
|
+
char *db = PQdb(pg_get_pgconn(self));
|
530
|
+
if (!db) return Qnil;
|
531
|
+
return rb_tainted_str_new2(db);
|
532
|
+
}
|
533
|
+
|
534
|
+
/*
|
535
|
+
* call-seq:
|
536
|
+
* conn.user()
|
537
|
+
*
|
538
|
+
* Returns the authenticated user name.
|
539
|
+
*/
|
540
|
+
static VALUE
|
541
|
+
pgconn_user(VALUE self)
|
542
|
+
{
|
543
|
+
char *user = PQuser(pg_get_pgconn(self));
|
544
|
+
if (!user) return Qnil;
|
545
|
+
return rb_tainted_str_new2(user);
|
546
|
+
}
|
547
|
+
|
548
|
+
/*
|
549
|
+
* call-seq:
|
550
|
+
* conn.pass()
|
551
|
+
*
|
552
|
+
* Returns the authenticated user name.
|
553
|
+
*/
|
554
|
+
static VALUE
|
555
|
+
pgconn_pass(VALUE self)
|
556
|
+
{
|
557
|
+
char *user = PQpass(pg_get_pgconn(self));
|
558
|
+
if (!user) return Qnil;
|
559
|
+
return rb_tainted_str_new2(user);
|
560
|
+
}
|
561
|
+
|
562
|
+
/*
|
563
|
+
* call-seq:
|
564
|
+
* conn.host()
|
565
|
+
*
|
566
|
+
* Returns the connected server name.
|
567
|
+
*/
|
568
|
+
static VALUE
|
569
|
+
pgconn_host(VALUE self)
|
570
|
+
{
|
571
|
+
char *host = PQhost(pg_get_pgconn(self));
|
572
|
+
if (!host) return Qnil;
|
573
|
+
return rb_tainted_str_new2(host);
|
574
|
+
}
|
575
|
+
|
576
|
+
/*
|
577
|
+
* call-seq:
|
578
|
+
* conn.port()
|
579
|
+
*
|
580
|
+
* Returns the connected server port number.
|
581
|
+
*/
|
582
|
+
static VALUE
|
583
|
+
pgconn_port(VALUE self)
|
584
|
+
{
|
585
|
+
char* port = PQport(pg_get_pgconn(self));
|
586
|
+
return INT2NUM(atol(port));
|
587
|
+
}
|
588
|
+
|
589
|
+
/*
|
590
|
+
* call-seq:
|
591
|
+
* conn.tty()
|
592
|
+
*
|
593
|
+
* Returns the connected pgtty. (Obsolete)
|
594
|
+
*/
|
595
|
+
static VALUE
|
596
|
+
pgconn_tty(VALUE self)
|
597
|
+
{
|
598
|
+
char *tty = PQtty(pg_get_pgconn(self));
|
599
|
+
if (!tty) return Qnil;
|
600
|
+
return rb_tainted_str_new2(tty);
|
601
|
+
}
|
602
|
+
|
603
|
+
/*
|
604
|
+
* call-seq:
|
605
|
+
* conn.options()
|
606
|
+
*
|
607
|
+
* Returns backend option string.
|
608
|
+
*/
|
609
|
+
static VALUE
|
610
|
+
pgconn_options(VALUE self)
|
611
|
+
{
|
612
|
+
char *options = PQoptions(pg_get_pgconn(self));
|
613
|
+
if (!options) return Qnil;
|
614
|
+
return rb_tainted_str_new2(options);
|
615
|
+
}
|
616
|
+
|
617
|
+
/*
|
618
|
+
* call-seq:
|
619
|
+
* conn.status()
|
620
|
+
*
|
621
|
+
* Returns status of connection : CONNECTION_OK or CONNECTION_BAD
|
622
|
+
*/
|
623
|
+
static VALUE
|
624
|
+
pgconn_status(VALUE self)
|
625
|
+
{
|
626
|
+
return INT2NUM(PQstatus(pg_get_pgconn(self)));
|
627
|
+
}
|
628
|
+
|
629
|
+
/*
|
630
|
+
* call-seq:
|
631
|
+
* conn.transaction_status()
|
632
|
+
*
|
633
|
+
* returns one of the following statuses:
|
634
|
+
* PQTRANS_IDLE = 0 (connection idle)
|
635
|
+
* PQTRANS_ACTIVE = 1 (command in progress)
|
636
|
+
* PQTRANS_INTRANS = 2 (idle, within transaction block)
|
637
|
+
* PQTRANS_INERROR = 3 (idle, within failed transaction)
|
638
|
+
* PQTRANS_UNKNOWN = 4 (cannot determine status)
|
639
|
+
*/
|
640
|
+
static VALUE
|
641
|
+
pgconn_transaction_status(VALUE self)
|
642
|
+
{
|
643
|
+
return INT2NUM(PQtransactionStatus(pg_get_pgconn(self)));
|
644
|
+
}
|
645
|
+
|
646
|
+
/*
|
647
|
+
* call-seq:
|
648
|
+
* conn.parameter_status( param_name ) -> String
|
649
|
+
*
|
650
|
+
* Returns the setting of parameter _param_name_, where
|
651
|
+
* _param_name_ is one of
|
652
|
+
* * +server_version+
|
653
|
+
* * +server_encoding+
|
654
|
+
* * +client_encoding+
|
655
|
+
* * +is_superuser+
|
656
|
+
* * +session_authorization+
|
657
|
+
* * +DateStyle+
|
658
|
+
* * +TimeZone+
|
659
|
+
* * +integer_datetimes+
|
660
|
+
* * +standard_conforming_strings+
|
661
|
+
*
|
662
|
+
* Returns nil if the value of the parameter is not known.
|
663
|
+
*/
|
664
|
+
static VALUE
|
665
|
+
pgconn_parameter_status(VALUE self, VALUE param_name)
|
666
|
+
{
|
667
|
+
const char *ret = PQparameterStatus(pg_get_pgconn(self), StringValuePtr(param_name));
|
668
|
+
if(ret == NULL)
|
669
|
+
return Qnil;
|
670
|
+
else
|
671
|
+
return rb_tainted_str_new2(ret);
|
672
|
+
}
|
673
|
+
|
674
|
+
/*
|
675
|
+
* call-seq:
|
676
|
+
* conn.protocol_version -> Integer
|
677
|
+
*
|
678
|
+
* The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
|
679
|
+
* or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
|
680
|
+
* obsolete and not supported by libpq.)
|
681
|
+
*/
|
682
|
+
static VALUE
|
683
|
+
pgconn_protocol_version(VALUE self)
|
684
|
+
{
|
685
|
+
return INT2NUM(PQprotocolVersion(pg_get_pgconn(self)));
|
686
|
+
}
|
687
|
+
|
688
|
+
/*
|
689
|
+
* call-seq:
|
690
|
+
* conn.server_version -> Integer
|
691
|
+
*
|
692
|
+
* The number is formed by converting the major, minor, and revision
|
693
|
+
* numbers into two-decimal-digit numbers and appending them together.
|
694
|
+
* For example, version 7.4.2 will be returned as 70402, and version
|
695
|
+
* 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
|
696
|
+
* is returned if the connection is bad.
|
697
|
+
*
|
698
|
+
*/
|
699
|
+
static VALUE
|
700
|
+
pgconn_server_version(VALUE self)
|
701
|
+
{
|
702
|
+
return INT2NUM(PQserverVersion(pg_get_pgconn(self)));
|
703
|
+
}
|
704
|
+
|
705
|
+
/*
|
706
|
+
* call-seq:
|
707
|
+
* conn.error_message -> String
|
708
|
+
*
|
709
|
+
* Returns the error message about connection.
|
710
|
+
*/
|
711
|
+
static VALUE
|
712
|
+
pgconn_error_message(VALUE self)
|
713
|
+
{
|
714
|
+
char *error = PQerrorMessage(pg_get_pgconn(self));
|
715
|
+
if (!error) return Qnil;
|
716
|
+
return rb_tainted_str_new2(error);
|
717
|
+
}
|
718
|
+
|
719
|
+
/*
|
720
|
+
* call-seq:
|
721
|
+
* conn.socket() -> Fixnum
|
722
|
+
*
|
723
|
+
* Returns the socket's file descriptor for this connection.
|
724
|
+
* <tt>IO.for_fd()</tt> can be used to build a proper IO object to the socket.
|
725
|
+
* If you do so, you will likely also want to set <tt>autoclose=false</tt>
|
726
|
+
* on it to prevent Ruby from closing the socket to PostgreSQL if it
|
727
|
+
* goes out of scope. Alternatively, you can use #socket_io, which
|
728
|
+
* creates an IO that's associated with the connection object itself,
|
729
|
+
* and so won't go out of scope until the connection does.
|
730
|
+
*
|
731
|
+
* *Note:* On Windows the file descriptor is not really usable,
|
732
|
+
* since it can not be used to build a Ruby IO object.
|
733
|
+
*/
|
734
|
+
static VALUE
|
735
|
+
pgconn_socket(VALUE self)
|
736
|
+
{
|
737
|
+
int sd;
|
738
|
+
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
739
|
+
rb_raise(rb_ePGerror, "Can't get socket descriptor");
|
740
|
+
return INT2NUM(sd);
|
741
|
+
}
|
742
|
+
|
743
|
+
|
744
|
+
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
745
|
+
|
746
|
+
/*
|
747
|
+
* call-seq:
|
748
|
+
* conn.socket_io() -> IO
|
749
|
+
*
|
750
|
+
* Fetch a memoized IO object created from the Connection's underlying socket.
|
751
|
+
* This object can be used for IO.select to wait for events while running
|
752
|
+
* asynchronous API calls.
|
753
|
+
*
|
754
|
+
* Using this instead of #socket avoids the problem of the underlying connection
|
755
|
+
* being closed by Ruby when an IO created using <tt>IO.for_fd(conn.socket)</tt>
|
756
|
+
* goes out of scope.
|
757
|
+
*
|
758
|
+
* This method can also be used on Windows but requires Ruby-2.0+.
|
759
|
+
*/
|
760
|
+
static VALUE
|
761
|
+
pgconn_socket_io(VALUE self)
|
762
|
+
{
|
763
|
+
int sd;
|
764
|
+
int ruby_sd;
|
765
|
+
int id_autoclose = rb_intern("autoclose=");
|
766
|
+
VALUE socket_io = rb_iv_get( self, "@socket_io" );
|
767
|
+
|
768
|
+
if ( !RTEST(socket_io) ) {
|
769
|
+
if( (sd = PQsocket(pg_get_pgconn(self))) < 0)
|
770
|
+
rb_raise(rb_ePGerror, "Can't get socket descriptor");
|
771
|
+
|
772
|
+
#ifdef _WIN32
|
773
|
+
ruby_sd = rb_w32_wrap_io_handle((HANDLE)(intptr_t)sd, O_RDWR|O_BINARY|O_NOINHERIT);
|
774
|
+
#else
|
775
|
+
ruby_sd = sd;
|
776
|
+
#endif
|
777
|
+
|
778
|
+
socket_io = rb_funcall( rb_cIO, rb_intern("for_fd"), 1, INT2NUM(ruby_sd) );
|
779
|
+
|
780
|
+
/* Disable autoclose feature, when supported */
|
781
|
+
if( rb_respond_to(socket_io, id_autoclose) ){
|
782
|
+
rb_funcall( socket_io, id_autoclose, 1, Qfalse );
|
783
|
+
}
|
784
|
+
|
785
|
+
rb_iv_set( self, "@socket_io", socket_io );
|
786
|
+
}
|
787
|
+
|
788
|
+
return socket_io;
|
789
|
+
}
|
790
|
+
|
791
|
+
#endif
|
792
|
+
|
793
|
+
/*
|
794
|
+
* call-seq:
|
795
|
+
* conn.backend_pid() -> Fixnum
|
796
|
+
*
|
797
|
+
* Returns the process ID of the backend server
|
798
|
+
* process for this connection.
|
799
|
+
* Note that this is a PID on database server host.
|
800
|
+
*/
|
801
|
+
static VALUE
|
802
|
+
pgconn_backend_pid(VALUE self)
|
803
|
+
{
|
804
|
+
return INT2NUM(PQbackendPID(pg_get_pgconn(self)));
|
805
|
+
}
|
806
|
+
|
807
|
+
/*
|
808
|
+
* call-seq:
|
809
|
+
* conn.connection_needs_password() -> Boolean
|
810
|
+
*
|
811
|
+
* Returns +true+ if the authentication method required a
|
812
|
+
* password, but none was available. +false+ otherwise.
|
813
|
+
*/
|
814
|
+
static VALUE
|
815
|
+
pgconn_connection_needs_password(VALUE self)
|
816
|
+
{
|
817
|
+
return PQconnectionNeedsPassword(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
818
|
+
}
|
819
|
+
|
820
|
+
/*
|
821
|
+
* call-seq:
|
822
|
+
* conn.connection_used_password() -> Boolean
|
823
|
+
*
|
824
|
+
* Returns +true+ if the authentication method used
|
825
|
+
* a caller-supplied password, +false+ otherwise.
|
826
|
+
*/
|
827
|
+
static VALUE
|
828
|
+
pgconn_connection_used_password(VALUE self)
|
829
|
+
{
|
830
|
+
return PQconnectionUsedPassword(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
831
|
+
}
|
832
|
+
|
833
|
+
|
834
|
+
/* :TODO: get_ssl */
|
835
|
+
|
836
|
+
|
837
|
+
static VALUE pgconn_exec_params( int, VALUE *, VALUE );
|
838
|
+
|
839
|
+
/*
|
840
|
+
* call-seq:
|
841
|
+
* conn.exec(sql) -> PG::Result
|
842
|
+
* conn.exec(sql) {|pg_result| block }
|
843
|
+
*
|
844
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
845
|
+
* Returns a PG::Result instance on success.
|
846
|
+
* On failure, it raises a PG::Error.
|
847
|
+
*
|
848
|
+
* For backward compatibility, if you pass more than one parameter to this method,
|
849
|
+
* it will call #exec_params for you. New code should explicitly use #exec_params if
|
850
|
+
* argument placeholders are used.
|
851
|
+
*
|
852
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
853
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
854
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
855
|
+
*/
|
856
|
+
static VALUE
|
857
|
+
pgconn_exec(int argc, VALUE *argv, VALUE self)
|
858
|
+
{
|
859
|
+
PGconn *conn = pg_get_pgconn(self);
|
860
|
+
PGresult *result = NULL;
|
861
|
+
VALUE rb_pgresult;
|
862
|
+
|
863
|
+
/* If called with no parameters, use PQexec */
|
864
|
+
if ( argc == 1 ) {
|
865
|
+
Check_Type(argv[0], T_STRING);
|
866
|
+
|
867
|
+
result = gvl_PQexec(conn, StringValuePtr(argv[0]));
|
868
|
+
rb_pgresult = pg_new_result(result, self);
|
869
|
+
pg_result_check(rb_pgresult);
|
870
|
+
if (rb_block_given_p()) {
|
871
|
+
return rb_ensure(rb_yield, rb_pgresult, pg_result_clear, rb_pgresult);
|
872
|
+
}
|
873
|
+
return rb_pgresult;
|
874
|
+
}
|
875
|
+
|
876
|
+
/* Otherwise, just call #exec_params instead for backward-compatibility */
|
877
|
+
else {
|
878
|
+
return pgconn_exec_params( argc, argv, self );
|
879
|
+
}
|
880
|
+
|
881
|
+
}
|
882
|
+
|
883
|
+
|
884
|
+
/*
|
885
|
+
* call-seq:
|
886
|
+
* conn.exec_params(sql, params[, result_format ] ) -> PG::Result
|
887
|
+
* conn.exec_params(sql, params[, result_format ] ) {|pg_result| block }
|
888
|
+
*
|
889
|
+
* Sends SQL query request specified by +sql+ to PostgreSQL using placeholders
|
890
|
+
* for parameters.
|
891
|
+
*
|
892
|
+
* Returns a PG::Result instance on success. On failure, it raises a PG::Error.
|
893
|
+
*
|
894
|
+
* +params+ is an array of the bind parameters for the SQL query.
|
895
|
+
* Each element of the +params+ array may be either:
|
896
|
+
* a hash of the form:
|
897
|
+
* {:value => String (value of bind parameter)
|
898
|
+
* :type => Fixnum (oid of type of bind parameter)
|
899
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
900
|
+
* }
|
901
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
902
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
903
|
+
*
|
904
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
905
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
906
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
907
|
+
*
|
908
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
909
|
+
* Instead of specifying type oids, it's recommended to simply add
|
910
|
+
* explicit casts in the query to ensure that the right type is used.
|
911
|
+
*
|
912
|
+
* For example: "SELECT $1::int"
|
913
|
+
*
|
914
|
+
* The optional +result_format+ should be 0 for text results, 1
|
915
|
+
* for binary.
|
916
|
+
*
|
917
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
918
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
919
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
920
|
+
*/
|
921
|
+
static VALUE
|
922
|
+
pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
923
|
+
{
|
924
|
+
PGconn *conn = pg_get_pgconn(self);
|
925
|
+
PGresult *result = NULL;
|
926
|
+
VALUE rb_pgresult;
|
927
|
+
VALUE command, params, in_res_fmt;
|
928
|
+
VALUE param, param_type, param_value, param_format;
|
929
|
+
VALUE param_value_tmp;
|
930
|
+
VALUE sym_type, sym_value, sym_format;
|
931
|
+
VALUE gc_array;
|
932
|
+
int i=0;
|
933
|
+
int nParams;
|
934
|
+
Oid *paramTypes;
|
935
|
+
char ** paramValues;
|
936
|
+
int *paramLengths;
|
937
|
+
int *paramFormats;
|
938
|
+
int resultFormat;
|
939
|
+
|
940
|
+
rb_scan_args(argc, argv, "12", &command, ¶ms, &in_res_fmt);
|
941
|
+
|
942
|
+
/*
|
943
|
+
* Handle the edge-case where the caller is coming from #exec, but passed an explict +nil+
|
944
|
+
* for the second parameter.
|
945
|
+
*/
|
946
|
+
if ( NIL_P(params) ) {
|
947
|
+
return pgconn_exec( 1, argv, self );
|
948
|
+
}
|
949
|
+
|
950
|
+
Check_Type(params, T_ARRAY);
|
951
|
+
|
952
|
+
if ( NIL_P(in_res_fmt) ) {
|
953
|
+
resultFormat = 0;
|
954
|
+
}
|
955
|
+
else {
|
956
|
+
resultFormat = NUM2INT(in_res_fmt);
|
957
|
+
}
|
958
|
+
|
959
|
+
gc_array = rb_ary_new();
|
960
|
+
rb_gc_register_address(&gc_array);
|
961
|
+
|
962
|
+
sym_type = ID2SYM(rb_intern("type"));
|
963
|
+
sym_value = ID2SYM(rb_intern("value"));
|
964
|
+
sym_format = ID2SYM(rb_intern("format"));
|
965
|
+
nParams = (int)RARRAY_LEN(params);
|
966
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
967
|
+
paramValues = ALLOC_N(char *, nParams);
|
968
|
+
paramLengths = ALLOC_N(int, nParams);
|
969
|
+
paramFormats = ALLOC_N(int, nParams);
|
970
|
+
|
971
|
+
for ( i = 0; i < nParams; i++ ) {
|
972
|
+
param = rb_ary_entry(params, i);
|
973
|
+
if (TYPE(param) == T_HASH) {
|
974
|
+
param_type = rb_hash_aref(param, sym_type);
|
975
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
976
|
+
if(param_value_tmp == Qnil)
|
977
|
+
param_value = param_value_tmp;
|
978
|
+
else
|
979
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
980
|
+
param_format = rb_hash_aref(param, sym_format);
|
981
|
+
}
|
982
|
+
else {
|
983
|
+
param_type = Qnil;
|
984
|
+
if(param == Qnil)
|
985
|
+
param_value = param;
|
986
|
+
else
|
987
|
+
param_value = rb_obj_as_string(param);
|
988
|
+
param_format = Qnil;
|
989
|
+
}
|
990
|
+
|
991
|
+
if(param_type == Qnil)
|
992
|
+
paramTypes[i] = 0;
|
993
|
+
else
|
994
|
+
paramTypes[i] = NUM2INT(param_type);
|
995
|
+
|
996
|
+
if(param_value == Qnil) {
|
997
|
+
paramValues[i] = NULL;
|
998
|
+
paramLengths[i] = 0;
|
999
|
+
}
|
1000
|
+
else {
|
1001
|
+
Check_Type(param_value, T_STRING);
|
1002
|
+
/* make sure param_value doesn't get freed by the GC */
|
1003
|
+
rb_ary_push(gc_array, param_value);
|
1004
|
+
paramValues[i] = StringValuePtr(param_value);
|
1005
|
+
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
if(param_format == Qnil)
|
1009
|
+
paramFormats[i] = 0;
|
1010
|
+
else
|
1011
|
+
paramFormats[i] = NUM2INT(param_format);
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
result = gvl_PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1015
|
+
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1016
|
+
|
1017
|
+
rb_gc_unregister_address(&gc_array);
|
1018
|
+
|
1019
|
+
xfree(paramTypes);
|
1020
|
+
xfree(paramValues);
|
1021
|
+
xfree(paramLengths);
|
1022
|
+
xfree(paramFormats);
|
1023
|
+
|
1024
|
+
rb_pgresult = pg_new_result(result, self);
|
1025
|
+
pg_result_check(rb_pgresult);
|
1026
|
+
|
1027
|
+
if (rb_block_given_p()) {
|
1028
|
+
return rb_ensure(rb_yield, rb_pgresult, pg_result_clear, rb_pgresult);
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
return rb_pgresult;
|
1032
|
+
}
|
1033
|
+
|
1034
|
+
/*
|
1035
|
+
* call-seq:
|
1036
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PG::Result
|
1037
|
+
*
|
1038
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
1039
|
+
* Returns a PG::Result instance on success.
|
1040
|
+
* On failure, it raises a PG::Error.
|
1041
|
+
*
|
1042
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
1043
|
+
* types of the parameters.
|
1044
|
+
*
|
1045
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
1046
|
+
* Instead of specifying type oids, it's recommended to simply add
|
1047
|
+
* explicit casts in the query to ensure that the right type is used.
|
1048
|
+
*
|
1049
|
+
* For example: "SELECT $1::int"
|
1050
|
+
*
|
1051
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1052
|
+
* inside the SQL query.
|
1053
|
+
*/
|
1054
|
+
static VALUE
|
1055
|
+
pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
1056
|
+
{
|
1057
|
+
PGconn *conn = pg_get_pgconn(self);
|
1058
|
+
PGresult *result = NULL;
|
1059
|
+
VALUE rb_pgresult;
|
1060
|
+
VALUE name, command, in_paramtypes;
|
1061
|
+
VALUE param;
|
1062
|
+
int i = 0;
|
1063
|
+
int nParams = 0;
|
1064
|
+
Oid *paramTypes = NULL;
|
1065
|
+
|
1066
|
+
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1067
|
+
Check_Type(name, T_STRING);
|
1068
|
+
Check_Type(command, T_STRING);
|
1069
|
+
|
1070
|
+
if(! NIL_P(in_paramtypes)) {
|
1071
|
+
Check_Type(in_paramtypes, T_ARRAY);
|
1072
|
+
nParams = (int)RARRAY_LEN(in_paramtypes);
|
1073
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1074
|
+
for(i = 0; i < nParams; i++) {
|
1075
|
+
param = rb_ary_entry(in_paramtypes, i);
|
1076
|
+
Check_Type(param, T_FIXNUM);
|
1077
|
+
if(param == Qnil)
|
1078
|
+
paramTypes[i] = 0;
|
1079
|
+
else
|
1080
|
+
paramTypes[i] = NUM2INT(param);
|
1081
|
+
}
|
1082
|
+
}
|
1083
|
+
result = gvl_PQprepare(conn, StringValuePtr(name), StringValuePtr(command),
|
1084
|
+
nParams, paramTypes);
|
1085
|
+
|
1086
|
+
xfree(paramTypes);
|
1087
|
+
|
1088
|
+
rb_pgresult = pg_new_result(result, self);
|
1089
|
+
pg_result_check(rb_pgresult);
|
1090
|
+
return rb_pgresult;
|
1091
|
+
}
|
1092
|
+
|
1093
|
+
/*
|
1094
|
+
* call-seq:
|
1095
|
+
* conn.exec_prepared(statement_name [, params, result_format ] ) -> PG::Result
|
1096
|
+
* conn.exec_prepared(statement_name [, params, result_format ] ) {|pg_result| block }
|
1097
|
+
*
|
1098
|
+
* Execute prepared named statement specified by _statement_name_.
|
1099
|
+
* Returns a PG::Result instance on success.
|
1100
|
+
* On failure, it raises a PG::Error.
|
1101
|
+
*
|
1102
|
+
* +params+ is an array of the optional bind parameters for the
|
1103
|
+
* SQL query. Each element of the +params+ array may be either:
|
1104
|
+
* a hash of the form:
|
1105
|
+
* {:value => String (value of bind parameter)
|
1106
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
1107
|
+
* }
|
1108
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1109
|
+
* { :value => <string value>, :format => 0 }
|
1110
|
+
*
|
1111
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1112
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
1113
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1114
|
+
*
|
1115
|
+
* The optional +result_format+ should be 0 for text results, 1
|
1116
|
+
* for binary.
|
1117
|
+
*
|
1118
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1119
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
1120
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
1121
|
+
*/
|
1122
|
+
static VALUE
|
1123
|
+
pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1124
|
+
{
|
1125
|
+
PGconn *conn = pg_get_pgconn(self);
|
1126
|
+
PGresult *result = NULL;
|
1127
|
+
VALUE rb_pgresult;
|
1128
|
+
VALUE name, params, in_res_fmt;
|
1129
|
+
VALUE param, param_value, param_format;
|
1130
|
+
VALUE param_value_tmp;
|
1131
|
+
VALUE sym_value, sym_format;
|
1132
|
+
VALUE gc_array;
|
1133
|
+
int i = 0;
|
1134
|
+
int nParams;
|
1135
|
+
char ** paramValues;
|
1136
|
+
int *paramLengths;
|
1137
|
+
int *paramFormats;
|
1138
|
+
int resultFormat;
|
1139
|
+
|
1140
|
+
|
1141
|
+
rb_scan_args(argc, argv, "12", &name, ¶ms, &in_res_fmt);
|
1142
|
+
Check_Type(name, T_STRING);
|
1143
|
+
|
1144
|
+
if(NIL_P(params)) {
|
1145
|
+
params = rb_ary_new2(0);
|
1146
|
+
resultFormat = 0;
|
1147
|
+
}
|
1148
|
+
else {
|
1149
|
+
Check_Type(params, T_ARRAY);
|
1150
|
+
}
|
1151
|
+
|
1152
|
+
if(NIL_P(in_res_fmt)) {
|
1153
|
+
resultFormat = 0;
|
1154
|
+
}
|
1155
|
+
else {
|
1156
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1157
|
+
}
|
1158
|
+
|
1159
|
+
gc_array = rb_ary_new();
|
1160
|
+
rb_gc_register_address(&gc_array);
|
1161
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1162
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1163
|
+
nParams = (int)RARRAY_LEN(params);
|
1164
|
+
paramValues = ALLOC_N(char *, nParams);
|
1165
|
+
paramLengths = ALLOC_N(int, nParams);
|
1166
|
+
paramFormats = ALLOC_N(int, nParams);
|
1167
|
+
for(i = 0; i < nParams; i++) {
|
1168
|
+
param = rb_ary_entry(params, i);
|
1169
|
+
if (TYPE(param) == T_HASH) {
|
1170
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1171
|
+
if(param_value_tmp == Qnil)
|
1172
|
+
param_value = param_value_tmp;
|
1173
|
+
else
|
1174
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1175
|
+
param_format = rb_hash_aref(param, sym_format);
|
1176
|
+
}
|
1177
|
+
else {
|
1178
|
+
if(param == Qnil)
|
1179
|
+
param_value = param;
|
1180
|
+
else
|
1181
|
+
param_value = rb_obj_as_string(param);
|
1182
|
+
param_format = INT2NUM(0);
|
1183
|
+
}
|
1184
|
+
if(param_value == Qnil) {
|
1185
|
+
paramValues[i] = NULL;
|
1186
|
+
paramLengths[i] = 0;
|
1187
|
+
}
|
1188
|
+
else {
|
1189
|
+
Check_Type(param_value, T_STRING);
|
1190
|
+
/* make sure param_value doesn't get freed by the GC */
|
1191
|
+
rb_ary_push(gc_array, param_value);
|
1192
|
+
paramValues[i] = StringValuePtr(param_value);
|
1193
|
+
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1194
|
+
}
|
1195
|
+
|
1196
|
+
if(param_format == Qnil)
|
1197
|
+
paramFormats[i] = 0;
|
1198
|
+
else
|
1199
|
+
paramFormats[i] = NUM2INT(param_format);
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
result = gvl_PQexecPrepared(conn, StringValuePtr(name), nParams,
|
1203
|
+
(const char * const *)paramValues, paramLengths, paramFormats,
|
1204
|
+
resultFormat);
|
1205
|
+
|
1206
|
+
rb_gc_unregister_address(&gc_array);
|
1207
|
+
|
1208
|
+
xfree(paramValues);
|
1209
|
+
xfree(paramLengths);
|
1210
|
+
xfree(paramFormats);
|
1211
|
+
|
1212
|
+
rb_pgresult = pg_new_result(result, self);
|
1213
|
+
pg_result_check(rb_pgresult);
|
1214
|
+
if (rb_block_given_p()) {
|
1215
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1216
|
+
pg_result_clear, rb_pgresult);
|
1217
|
+
}
|
1218
|
+
return rb_pgresult;
|
1219
|
+
}
|
1220
|
+
|
1221
|
+
/*
|
1222
|
+
* call-seq:
|
1223
|
+
* conn.describe_prepared( statement_name ) -> PG::Result
|
1224
|
+
*
|
1225
|
+
* Retrieve information about the prepared statement
|
1226
|
+
* _statement_name_.
|
1227
|
+
*/
|
1228
|
+
static VALUE
|
1229
|
+
pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
1230
|
+
{
|
1231
|
+
PGresult *result;
|
1232
|
+
VALUE rb_pgresult;
|
1233
|
+
PGconn *conn = pg_get_pgconn(self);
|
1234
|
+
char *stmt;
|
1235
|
+
if(stmt_name == Qnil) {
|
1236
|
+
stmt = NULL;
|
1237
|
+
}
|
1238
|
+
else {
|
1239
|
+
Check_Type(stmt_name, T_STRING);
|
1240
|
+
stmt = StringValuePtr(stmt_name);
|
1241
|
+
}
|
1242
|
+
result = gvl_PQdescribePrepared(conn, stmt);
|
1243
|
+
rb_pgresult = pg_new_result(result, self);
|
1244
|
+
pg_result_check(rb_pgresult);
|
1245
|
+
return rb_pgresult;
|
1246
|
+
}
|
1247
|
+
|
1248
|
+
|
1249
|
+
/*
|
1250
|
+
* call-seq:
|
1251
|
+
* conn.describe_portal( portal_name ) -> PG::Result
|
1252
|
+
*
|
1253
|
+
* Retrieve information about the portal _portal_name_.
|
1254
|
+
*/
|
1255
|
+
static VALUE
|
1256
|
+
pgconn_describe_portal(self, stmt_name)
|
1257
|
+
VALUE self, stmt_name;
|
1258
|
+
{
|
1259
|
+
PGresult *result;
|
1260
|
+
VALUE rb_pgresult;
|
1261
|
+
PGconn *conn = pg_get_pgconn(self);
|
1262
|
+
char *stmt;
|
1263
|
+
if(stmt_name == Qnil) {
|
1264
|
+
stmt = NULL;
|
1265
|
+
}
|
1266
|
+
else {
|
1267
|
+
Check_Type(stmt_name, T_STRING);
|
1268
|
+
stmt = StringValuePtr(stmt_name);
|
1269
|
+
}
|
1270
|
+
result = gvl_PQdescribePortal(conn, stmt);
|
1271
|
+
rb_pgresult = pg_new_result(result, self);
|
1272
|
+
pg_result_check(rb_pgresult);
|
1273
|
+
return rb_pgresult;
|
1274
|
+
}
|
1275
|
+
|
1276
|
+
|
1277
|
+
/*
|
1278
|
+
* call-seq:
|
1279
|
+
* conn.make_empty_pgresult( status ) -> PG::Result
|
1280
|
+
*
|
1281
|
+
* Constructs and empty PG::Result with status _status_.
|
1282
|
+
* _status_ may be one of:
|
1283
|
+
* * +PGRES_EMPTY_QUERY+
|
1284
|
+
* * +PGRES_COMMAND_OK+
|
1285
|
+
* * +PGRES_TUPLES_OK+
|
1286
|
+
* * +PGRES_COPY_OUT+
|
1287
|
+
* * +PGRES_COPY_IN+
|
1288
|
+
* * +PGRES_BAD_RESPONSE+
|
1289
|
+
* * +PGRES_NONFATAL_ERROR+
|
1290
|
+
* * +PGRES_FATAL_ERROR+
|
1291
|
+
* * +PGRES_COPY_BOTH+
|
1292
|
+
*/
|
1293
|
+
static VALUE
|
1294
|
+
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
1295
|
+
{
|
1296
|
+
PGresult *result;
|
1297
|
+
VALUE rb_pgresult;
|
1298
|
+
PGconn *conn = pg_get_pgconn(self);
|
1299
|
+
result = PQmakeEmptyPGresult(conn, NUM2INT(status));
|
1300
|
+
rb_pgresult = pg_new_result(result, self);
|
1301
|
+
pg_result_check(rb_pgresult);
|
1302
|
+
return rb_pgresult;
|
1303
|
+
}
|
1304
|
+
|
1305
|
+
|
1306
|
+
/*
|
1307
|
+
* call-seq:
|
1308
|
+
* conn.escape_string( str ) -> String
|
1309
|
+
*
|
1310
|
+
* Connection instance method for versions of 8.1 and higher of libpq
|
1311
|
+
* uses PQescapeStringConn, which is safer. Avoid calling as a class method,
|
1312
|
+
* the class method uses the deprecated PQescapeString() API function.
|
1313
|
+
*
|
1314
|
+
* Returns a SQL-safe version of the String _str_.
|
1315
|
+
* This is the preferred way to make strings safe for inclusion in
|
1316
|
+
* SQL queries.
|
1317
|
+
*
|
1318
|
+
* Consider using exec_params, which avoids the need for passing values
|
1319
|
+
* inside of SQL commands.
|
1320
|
+
*
|
1321
|
+
* Encoding of escaped string will be equal to client encoding of connection.
|
1322
|
+
*/
|
1323
|
+
static VALUE
|
1324
|
+
pgconn_s_escape(VALUE self, VALUE string)
|
1325
|
+
{
|
1326
|
+
char *escaped;
|
1327
|
+
size_t size;
|
1328
|
+
int error;
|
1329
|
+
VALUE result;
|
1330
|
+
#ifdef M17N_SUPPORTED
|
1331
|
+
rb_encoding* enc;
|
1332
|
+
#endif
|
1333
|
+
|
1334
|
+
Check_Type(string, T_STRING);
|
1335
|
+
|
1336
|
+
escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
|
1337
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1338
|
+
size = PQescapeStringConn(pg_get_pgconn(self), escaped,
|
1339
|
+
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1340
|
+
if(error) {
|
1341
|
+
xfree(escaped);
|
1342
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1343
|
+
}
|
1344
|
+
} else {
|
1345
|
+
size = PQescapeString(escaped, RSTRING_PTR(string), (int)RSTRING_LEN(string));
|
1346
|
+
}
|
1347
|
+
result = rb_str_new(escaped, size);
|
1348
|
+
xfree(escaped);
|
1349
|
+
OBJ_INFECT(result, string);
|
1350
|
+
|
1351
|
+
#ifdef M17N_SUPPORTED
|
1352
|
+
if ( rb_obj_class(self) == rb_cPGconn ) {
|
1353
|
+
enc = pg_conn_enc_get( pg_get_pgconn(self) );
|
1354
|
+
} else {
|
1355
|
+
enc = rb_enc_get(string);
|
1356
|
+
}
|
1357
|
+
rb_enc_associate(result, enc);
|
1358
|
+
#endif
|
1359
|
+
|
1360
|
+
return result;
|
1361
|
+
}
|
1362
|
+
|
1363
|
+
/*
|
1364
|
+
* call-seq:
|
1365
|
+
* conn.escape_bytea( string ) -> String
|
1366
|
+
*
|
1367
|
+
* Connection instance method for versions of 8.1 and higher of libpq
|
1368
|
+
* uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
|
1369
|
+
* the class method uses the deprecated PQescapeBytea() API function.
|
1370
|
+
*
|
1371
|
+
* Use the instance method version of this function, it is safer than the
|
1372
|
+
* class method.
|
1373
|
+
*
|
1374
|
+
* Escapes binary data for use within an SQL command with the type +bytea+.
|
1375
|
+
*
|
1376
|
+
* Certain byte values must be escaped (but all byte values may be escaped)
|
1377
|
+
* when used as part of a +bytea+ literal in an SQL statement. In general, to
|
1378
|
+
* escape a byte, it is converted into the three digit octal number equal to
|
1379
|
+
* the octet value, and preceded by two backslashes. The single quote (') and
|
1380
|
+
* backslash (\) characters have special alternative escape sequences.
|
1381
|
+
* #escape_bytea performs this operation, escaping only the minimally required
|
1382
|
+
* bytes.
|
1383
|
+
*
|
1384
|
+
* Consider using exec_params, which avoids the need for passing values inside of
|
1385
|
+
* SQL commands.
|
1386
|
+
*/
|
1387
|
+
static VALUE
|
1388
|
+
pgconn_s_escape_bytea(VALUE self, VALUE str)
|
1389
|
+
{
|
1390
|
+
unsigned char *from, *to;
|
1391
|
+
size_t from_len, to_len;
|
1392
|
+
VALUE ret;
|
1393
|
+
|
1394
|
+
Check_Type(str, T_STRING);
|
1395
|
+
from = (unsigned char*)RSTRING_PTR(str);
|
1396
|
+
from_len = RSTRING_LEN(str);
|
1397
|
+
|
1398
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1399
|
+
to = PQescapeByteaConn(pg_get_pgconn(self), from, from_len, &to_len);
|
1400
|
+
} else {
|
1401
|
+
to = PQescapeBytea( from, from_len, &to_len);
|
1402
|
+
}
|
1403
|
+
|
1404
|
+
ret = rb_str_new((char*)to, to_len - 1);
|
1405
|
+
OBJ_INFECT(ret, str);
|
1406
|
+
PQfreemem(to);
|
1407
|
+
return ret;
|
1408
|
+
}
|
1409
|
+
|
1410
|
+
|
1411
|
+
/*
|
1412
|
+
* call-seq:
|
1413
|
+
* PG::Connection.unescape_bytea( string )
|
1414
|
+
*
|
1415
|
+
* Converts an escaped string representation of binary data into binary data --- the
|
1416
|
+
* reverse of #escape_bytea. This is needed when retrieving +bytea+ data in text format,
|
1417
|
+
* but not when retrieving it in binary format.
|
1418
|
+
*
|
1419
|
+
*/
|
1420
|
+
static VALUE
|
1421
|
+
pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
1422
|
+
{
|
1423
|
+
unsigned char *from, *to;
|
1424
|
+
size_t to_len;
|
1425
|
+
VALUE ret;
|
1426
|
+
|
1427
|
+
UNUSED( self );
|
1428
|
+
|
1429
|
+
Check_Type(str, T_STRING);
|
1430
|
+
from = (unsigned char*)StringValuePtr(str);
|
1431
|
+
|
1432
|
+
to = PQunescapeBytea(from, &to_len);
|
1433
|
+
|
1434
|
+
ret = rb_str_new((char*)to, to_len);
|
1435
|
+
OBJ_INFECT(ret, str);
|
1436
|
+
PQfreemem(to);
|
1437
|
+
return ret;
|
1438
|
+
}
|
1439
|
+
|
1440
|
+
#ifdef HAVE_PQESCAPELITERAL
|
1441
|
+
/*
|
1442
|
+
* call-seq:
|
1443
|
+
* conn.escape_literal( str ) -> String
|
1444
|
+
*
|
1445
|
+
* Escape an arbitrary String +str+ as a literal.
|
1446
|
+
*/
|
1447
|
+
static VALUE
|
1448
|
+
pgconn_escape_literal(VALUE self, VALUE string)
|
1449
|
+
{
|
1450
|
+
PGconn *conn = pg_get_pgconn(self);
|
1451
|
+
char *escaped = NULL;
|
1452
|
+
VALUE error;
|
1453
|
+
VALUE result = Qnil;
|
1454
|
+
|
1455
|
+
Check_Type(string, T_STRING);
|
1456
|
+
|
1457
|
+
escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1458
|
+
if (escaped == NULL)
|
1459
|
+
{
|
1460
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1461
|
+
rb_iv_set(error, "@connection", self);
|
1462
|
+
rb_exc_raise(error);
|
1463
|
+
return Qnil;
|
1464
|
+
}
|
1465
|
+
result = rb_str_new2(escaped);
|
1466
|
+
PQfreemem(escaped);
|
1467
|
+
OBJ_INFECT(result, string);
|
1468
|
+
|
1469
|
+
return result;
|
1470
|
+
}
|
1471
|
+
#endif
|
1472
|
+
|
1473
|
+
#ifdef HAVE_PQESCAPEIDENTIFIER
|
1474
|
+
/*
|
1475
|
+
* call-seq:
|
1476
|
+
* conn.escape_identifier( str ) -> String
|
1477
|
+
*
|
1478
|
+
* Escape an arbitrary String +str+ as an identifier.
|
1479
|
+
*/
|
1480
|
+
static VALUE
|
1481
|
+
pgconn_escape_identifier(VALUE self, VALUE string)
|
1482
|
+
{
|
1483
|
+
PGconn *conn = pg_get_pgconn(self);
|
1484
|
+
char *escaped = NULL;
|
1485
|
+
VALUE error;
|
1486
|
+
VALUE result = Qnil;
|
1487
|
+
|
1488
|
+
Check_Type(string, T_STRING);
|
1489
|
+
|
1490
|
+
escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1491
|
+
if (escaped == NULL)
|
1492
|
+
{
|
1493
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1494
|
+
rb_iv_set(error, "@connection", self);
|
1495
|
+
rb_exc_raise(error);
|
1496
|
+
return Qnil;
|
1497
|
+
}
|
1498
|
+
result = rb_str_new2(escaped);
|
1499
|
+
PQfreemem(escaped);
|
1500
|
+
OBJ_INFECT(result, string);
|
1501
|
+
|
1502
|
+
return result;
|
1503
|
+
}
|
1504
|
+
#endif
|
1505
|
+
|
1506
|
+
#ifdef HAVE_PQSETSINGLEROWMODE
|
1507
|
+
/*
|
1508
|
+
* call-seq:
|
1509
|
+
* conn.set_single_row_mode -> self
|
1510
|
+
*
|
1511
|
+
* To enter single-row mode, call this method immediately after a successful
|
1512
|
+
* call of send_query (or a sibling function). This mode selection is effective
|
1513
|
+
* only for the currently executing query.
|
1514
|
+
* Then call Connection#get_result repeatedly, until it returns nil.
|
1515
|
+
*
|
1516
|
+
* Each (but the last) received Result has exactly one row and a
|
1517
|
+
* Result#result_status of PGRES_SINGLE_TUPLE. The last row has
|
1518
|
+
* zero rows and is used to indicate a successful execution of the query.
|
1519
|
+
* All of these Result objects will contain the same row description data
|
1520
|
+
* (column names, types, etc) that an ordinary Result object for the query
|
1521
|
+
* would have.
|
1522
|
+
*
|
1523
|
+
* *Caution:* While processing a query, the server may return some rows and
|
1524
|
+
* then encounter an error, causing the query to be aborted. Ordinarily, pg
|
1525
|
+
* discards any such rows and reports only the error. But in single-row mode,
|
1526
|
+
* those rows will have already been returned to the application. Hence, the
|
1527
|
+
* application will see some Result objects followed by an Error raised in get_result.
|
1528
|
+
* For proper transactional behavior, the application must be designed to discard
|
1529
|
+
* or undo whatever has been done with the previously-processed rows, if the query
|
1530
|
+
* ultimately fails.
|
1531
|
+
*
|
1532
|
+
* Example:
|
1533
|
+
* conn.send_query( "your SQL command" )
|
1534
|
+
* conn.set_single_row_mode
|
1535
|
+
* loop do
|
1536
|
+
* res = conn.get_result or break
|
1537
|
+
* res.check
|
1538
|
+
* res.each do |row|
|
1539
|
+
* # do something with the received row
|
1540
|
+
* end
|
1541
|
+
* end
|
1542
|
+
*
|
1543
|
+
*/
|
1544
|
+
static VALUE
|
1545
|
+
pgconn_set_single_row_mode(VALUE self)
|
1546
|
+
{
|
1547
|
+
PGconn *conn = pg_get_pgconn(self);
|
1548
|
+
VALUE error;
|
1549
|
+
|
1550
|
+
if( PQsetSingleRowMode(conn) == 0 )
|
1551
|
+
{
|
1552
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1553
|
+
rb_iv_set(error, "@connection", self);
|
1554
|
+
rb_exc_raise(error);
|
1555
|
+
}
|
1556
|
+
|
1557
|
+
return self;
|
1558
|
+
}
|
1559
|
+
#endif
|
1560
|
+
|
1561
|
+
/*
|
1562
|
+
* call-seq:
|
1563
|
+
* conn.send_query(sql [, params, result_format ] ) -> nil
|
1564
|
+
*
|
1565
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1566
|
+
* asynchronous processing, and immediately returns.
|
1567
|
+
* On failure, it raises a PG::Error.
|
1568
|
+
*
|
1569
|
+
* +params+ is an optional array of the bind parameters for the SQL query.
|
1570
|
+
* Each element of the +params+ array may be either:
|
1571
|
+
* a hash of the form:
|
1572
|
+
* {:value => String (value of bind parameter)
|
1573
|
+
* :type => Fixnum (oid of type of bind parameter)
|
1574
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
1575
|
+
* }
|
1576
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1577
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
1578
|
+
*
|
1579
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1580
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
1581
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1582
|
+
*
|
1583
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
1584
|
+
* Instead of specifying type oids, it's recommended to simply add
|
1585
|
+
* explicit casts in the query to ensure that the right type is used.
|
1586
|
+
*
|
1587
|
+
* For example: "SELECT $1::int"
|
1588
|
+
*
|
1589
|
+
* The optional +result_format+ should be 0 for text results, 1
|
1590
|
+
* for binary.
|
1591
|
+
*/
|
1592
|
+
static VALUE
|
1593
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1594
|
+
{
|
1595
|
+
PGconn *conn = pg_get_pgconn(self);
|
1596
|
+
int result;
|
1597
|
+
VALUE command, params, in_res_fmt;
|
1598
|
+
VALUE param, param_type, param_value, param_format;
|
1599
|
+
VALUE param_value_tmp;
|
1600
|
+
VALUE sym_type, sym_value, sym_format;
|
1601
|
+
VALUE gc_array;
|
1602
|
+
VALUE error;
|
1603
|
+
int i=0;
|
1604
|
+
int nParams;
|
1605
|
+
Oid *paramTypes;
|
1606
|
+
char ** paramValues;
|
1607
|
+
int *paramLengths;
|
1608
|
+
int *paramFormats;
|
1609
|
+
int resultFormat;
|
1610
|
+
|
1611
|
+
rb_scan_args(argc, argv, "12", &command, ¶ms, &in_res_fmt);
|
1612
|
+
Check_Type(command, T_STRING);
|
1613
|
+
|
1614
|
+
/* If called with no parameters, use PQsendQuery */
|
1615
|
+
if(NIL_P(params)) {
|
1616
|
+
if(PQsendQuery(conn,StringValuePtr(command)) == 0) {
|
1617
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1618
|
+
rb_iv_set(error, "@connection", self);
|
1619
|
+
rb_exc_raise(error);
|
1620
|
+
}
|
1621
|
+
return Qnil;
|
1622
|
+
}
|
1623
|
+
|
1624
|
+
/* If called with parameters, and optionally result_format,
|
1625
|
+
* use PQsendQueryParams
|
1626
|
+
*/
|
1627
|
+
Check_Type(params, T_ARRAY);
|
1628
|
+
|
1629
|
+
if(NIL_P(in_res_fmt)) {
|
1630
|
+
resultFormat = 0;
|
1631
|
+
}
|
1632
|
+
else {
|
1633
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
gc_array = rb_ary_new();
|
1637
|
+
rb_gc_register_address(&gc_array);
|
1638
|
+
sym_type = ID2SYM(rb_intern("type"));
|
1639
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1640
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1641
|
+
nParams = (int)RARRAY_LEN(params);
|
1642
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1643
|
+
paramValues = ALLOC_N(char *, nParams);
|
1644
|
+
paramLengths = ALLOC_N(int, nParams);
|
1645
|
+
paramFormats = ALLOC_N(int, nParams);
|
1646
|
+
for(i = 0; i < nParams; i++) {
|
1647
|
+
param = rb_ary_entry(params, i);
|
1648
|
+
if (TYPE(param) == T_HASH) {
|
1649
|
+
param_type = rb_hash_aref(param, sym_type);
|
1650
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1651
|
+
if(param_value_tmp == Qnil)
|
1652
|
+
param_value = param_value_tmp;
|
1653
|
+
else
|
1654
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1655
|
+
param_format = rb_hash_aref(param, sym_format);
|
1656
|
+
}
|
1657
|
+
else {
|
1658
|
+
param_type = INT2NUM(0);
|
1659
|
+
if(param == Qnil)
|
1660
|
+
param_value = param;
|
1661
|
+
else
|
1662
|
+
param_value = rb_obj_as_string(param);
|
1663
|
+
param_format = INT2NUM(0);
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
if(param_type == Qnil)
|
1667
|
+
paramTypes[i] = 0;
|
1668
|
+
else
|
1669
|
+
paramTypes[i] = NUM2INT(param_type);
|
1670
|
+
|
1671
|
+
if(param_value == Qnil) {
|
1672
|
+
paramValues[i] = NULL;
|
1673
|
+
paramLengths[i] = 0;
|
1674
|
+
}
|
1675
|
+
else {
|
1676
|
+
Check_Type(param_value, T_STRING);
|
1677
|
+
/* make sure param_value doesn't get freed by the GC */
|
1678
|
+
rb_ary_push(gc_array, param_value);
|
1679
|
+
paramValues[i] = StringValuePtr(param_value);
|
1680
|
+
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1681
|
+
}
|
1682
|
+
|
1683
|
+
if(param_format == Qnil)
|
1684
|
+
paramFormats[i] = 0;
|
1685
|
+
else
|
1686
|
+
paramFormats[i] = NUM2INT(param_format);
|
1687
|
+
}
|
1688
|
+
|
1689
|
+
result = PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1690
|
+
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1691
|
+
|
1692
|
+
rb_gc_unregister_address(&gc_array);
|
1693
|
+
|
1694
|
+
xfree(paramTypes);
|
1695
|
+
xfree(paramValues);
|
1696
|
+
xfree(paramLengths);
|
1697
|
+
xfree(paramFormats);
|
1698
|
+
|
1699
|
+
if(result == 0) {
|
1700
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1701
|
+
rb_iv_set(error, "@connection", self);
|
1702
|
+
rb_exc_raise(error);
|
1703
|
+
}
|
1704
|
+
return Qnil;
|
1705
|
+
}
|
1706
|
+
|
1707
|
+
/*
|
1708
|
+
* call-seq:
|
1709
|
+
* conn.send_prepare( stmt_name, sql [, param_types ] ) -> nil
|
1710
|
+
*
|
1711
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
1712
|
+
* Sends prepare command asynchronously, and returns immediately.
|
1713
|
+
* On failure, it raises a PG::Error.
|
1714
|
+
*
|
1715
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
1716
|
+
* types of the parameters.
|
1717
|
+
*
|
1718
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
1719
|
+
* Instead of specifying type oids, it's recommended to simply add
|
1720
|
+
* explicit casts in the query to ensure that the right type is used.
|
1721
|
+
*
|
1722
|
+
* For example: "SELECT $1::int"
|
1723
|
+
*
|
1724
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1725
|
+
* inside the SQL query.
|
1726
|
+
*/
|
1727
|
+
static VALUE
|
1728
|
+
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1729
|
+
{
|
1730
|
+
PGconn *conn = pg_get_pgconn(self);
|
1731
|
+
int result;
|
1732
|
+
VALUE name, command, in_paramtypes;
|
1733
|
+
VALUE param;
|
1734
|
+
VALUE error;
|
1735
|
+
int i = 0;
|
1736
|
+
int nParams = 0;
|
1737
|
+
Oid *paramTypes = NULL;
|
1738
|
+
|
1739
|
+
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1740
|
+
Check_Type(name, T_STRING);
|
1741
|
+
Check_Type(command, T_STRING);
|
1742
|
+
|
1743
|
+
if(! NIL_P(in_paramtypes)) {
|
1744
|
+
Check_Type(in_paramtypes, T_ARRAY);
|
1745
|
+
nParams = (int)RARRAY_LEN(in_paramtypes);
|
1746
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1747
|
+
for(i = 0; i < nParams; i++) {
|
1748
|
+
param = rb_ary_entry(in_paramtypes, i);
|
1749
|
+
Check_Type(param, T_FIXNUM);
|
1750
|
+
if(param == Qnil)
|
1751
|
+
paramTypes[i] = 0;
|
1752
|
+
else
|
1753
|
+
paramTypes[i] = NUM2INT(param);
|
1754
|
+
}
|
1755
|
+
}
|
1756
|
+
result = PQsendPrepare(conn, StringValuePtr(name), StringValuePtr(command),
|
1757
|
+
nParams, paramTypes);
|
1758
|
+
|
1759
|
+
xfree(paramTypes);
|
1760
|
+
|
1761
|
+
if(result == 0) {
|
1762
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1763
|
+
rb_iv_set(error, "@connection", self);
|
1764
|
+
rb_exc_raise(error);
|
1765
|
+
}
|
1766
|
+
return Qnil;
|
1767
|
+
}
|
1768
|
+
|
1769
|
+
/*
|
1770
|
+
* call-seq:
|
1771
|
+
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1772
|
+
* -> nil
|
1773
|
+
*
|
1774
|
+
* Execute prepared named statement specified by _statement_name_
|
1775
|
+
* asynchronously, and returns immediately.
|
1776
|
+
* On failure, it raises a PG::Error.
|
1777
|
+
*
|
1778
|
+
* +params+ is an array of the optional bind parameters for the
|
1779
|
+
* SQL query. Each element of the +params+ array may be either:
|
1780
|
+
* a hash of the form:
|
1781
|
+
* {:value => String (value of bind parameter)
|
1782
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
1783
|
+
* }
|
1784
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1785
|
+
* { :value => <string value>, :format => 0 }
|
1786
|
+
*
|
1787
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1788
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
1789
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1790
|
+
*
|
1791
|
+
* The optional +result_format+ should be 0 for text results, 1
|
1792
|
+
* for binary.
|
1793
|
+
*/
|
1794
|
+
static VALUE
|
1795
|
+
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1796
|
+
{
|
1797
|
+
PGconn *conn = pg_get_pgconn(self);
|
1798
|
+
int result;
|
1799
|
+
VALUE name, params, in_res_fmt;
|
1800
|
+
VALUE param, param_value, param_format;
|
1801
|
+
VALUE param_value_tmp;
|
1802
|
+
VALUE sym_value, sym_format;
|
1803
|
+
VALUE gc_array;
|
1804
|
+
VALUE error;
|
1805
|
+
int i = 0;
|
1806
|
+
int nParams;
|
1807
|
+
char ** paramValues;
|
1808
|
+
int *paramLengths;
|
1809
|
+
int *paramFormats;
|
1810
|
+
int resultFormat;
|
1811
|
+
|
1812
|
+
rb_scan_args(argc, argv, "12", &name, ¶ms, &in_res_fmt);
|
1813
|
+
Check_Type(name, T_STRING);
|
1814
|
+
|
1815
|
+
if(NIL_P(params)) {
|
1816
|
+
params = rb_ary_new2(0);
|
1817
|
+
resultFormat = 0;
|
1818
|
+
}
|
1819
|
+
else {
|
1820
|
+
Check_Type(params, T_ARRAY);
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
if(NIL_P(in_res_fmt)) {
|
1824
|
+
resultFormat = 0;
|
1825
|
+
}
|
1826
|
+
else {
|
1827
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1828
|
+
}
|
1829
|
+
|
1830
|
+
gc_array = rb_ary_new();
|
1831
|
+
rb_gc_register_address(&gc_array);
|
1832
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1833
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1834
|
+
nParams = (int)RARRAY_LEN(params);
|
1835
|
+
paramValues = ALLOC_N(char *, nParams);
|
1836
|
+
paramLengths = ALLOC_N(int, nParams);
|
1837
|
+
paramFormats = ALLOC_N(int, nParams);
|
1838
|
+
for(i = 0; i < nParams; i++) {
|
1839
|
+
param = rb_ary_entry(params, i);
|
1840
|
+
if (TYPE(param) == T_HASH) {
|
1841
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1842
|
+
if(param_value_tmp == Qnil)
|
1843
|
+
param_value = param_value_tmp;
|
1844
|
+
else
|
1845
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1846
|
+
param_format = rb_hash_aref(param, sym_format);
|
1847
|
+
}
|
1848
|
+
else {
|
1849
|
+
if(param == Qnil)
|
1850
|
+
param_value = param;
|
1851
|
+
else
|
1852
|
+
param_value = rb_obj_as_string(param);
|
1853
|
+
param_format = INT2NUM(0);
|
1854
|
+
}
|
1855
|
+
|
1856
|
+
if(param_value == Qnil) {
|
1857
|
+
paramValues[i] = NULL;
|
1858
|
+
paramLengths[i] = 0;
|
1859
|
+
}
|
1860
|
+
else {
|
1861
|
+
Check_Type(param_value, T_STRING);
|
1862
|
+
/* make sure param_value doesn't get freed by the GC */
|
1863
|
+
rb_ary_push(gc_array, param_value);
|
1864
|
+
paramValues[i] = StringValuePtr(param_value);
|
1865
|
+
paramLengths[i] = (int)RSTRING_LEN(param_value);
|
1866
|
+
}
|
1867
|
+
|
1868
|
+
if(param_format == Qnil)
|
1869
|
+
paramFormats[i] = 0;
|
1870
|
+
else
|
1871
|
+
paramFormats[i] = NUM2INT(param_format);
|
1872
|
+
}
|
1873
|
+
|
1874
|
+
result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
|
1875
|
+
(const char * const *)paramValues, paramLengths, paramFormats,
|
1876
|
+
resultFormat);
|
1877
|
+
|
1878
|
+
rb_gc_unregister_address(&gc_array);
|
1879
|
+
|
1880
|
+
xfree(paramValues);
|
1881
|
+
xfree(paramLengths);
|
1882
|
+
xfree(paramFormats);
|
1883
|
+
|
1884
|
+
if(result == 0) {
|
1885
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1886
|
+
rb_iv_set(error, "@connection", self);
|
1887
|
+
rb_exc_raise(error);
|
1888
|
+
}
|
1889
|
+
return Qnil;
|
1890
|
+
}
|
1891
|
+
|
1892
|
+
/*
|
1893
|
+
* call-seq:
|
1894
|
+
* conn.send_describe_prepared( statement_name ) -> nil
|
1895
|
+
*
|
1896
|
+
* Asynchronously send _command_ to the server. Does not block.
|
1897
|
+
* Use in combination with +conn.get_result+.
|
1898
|
+
*/
|
1899
|
+
static VALUE
|
1900
|
+
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
1901
|
+
{
|
1902
|
+
VALUE error;
|
1903
|
+
PGconn *conn = pg_get_pgconn(self);
|
1904
|
+
/* returns 0 on failure */
|
1905
|
+
if(PQsendDescribePrepared(conn,StringValuePtr(stmt_name)) == 0) {
|
1906
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1907
|
+
rb_iv_set(error, "@connection", self);
|
1908
|
+
rb_exc_raise(error);
|
1909
|
+
}
|
1910
|
+
return Qnil;
|
1911
|
+
}
|
1912
|
+
|
1913
|
+
|
1914
|
+
/*
|
1915
|
+
* call-seq:
|
1916
|
+
* conn.send_describe_portal( portal_name ) -> nil
|
1917
|
+
*
|
1918
|
+
* Asynchronously send _command_ to the server. Does not block.
|
1919
|
+
* Use in combination with +conn.get_result+.
|
1920
|
+
*/
|
1921
|
+
static VALUE
|
1922
|
+
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
1923
|
+
{
|
1924
|
+
VALUE error;
|
1925
|
+
PGconn *conn = pg_get_pgconn(self);
|
1926
|
+
/* returns 0 on failure */
|
1927
|
+
if(PQsendDescribePortal(conn,StringValuePtr(portal)) == 0) {
|
1928
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1929
|
+
rb_iv_set(error, "@connection", self);
|
1930
|
+
rb_exc_raise(error);
|
1931
|
+
}
|
1932
|
+
return Qnil;
|
1933
|
+
}
|
1934
|
+
|
1935
|
+
|
1936
|
+
/*
|
1937
|
+
* call-seq:
|
1938
|
+
* conn.get_result() -> PG::Result
|
1939
|
+
* conn.get_result() {|pg_result| block }
|
1940
|
+
*
|
1941
|
+
* Blocks waiting for the next result from a call to
|
1942
|
+
* #send_query (or another asynchronous command), and returns
|
1943
|
+
* it. Returns +nil+ if no more results are available.
|
1944
|
+
*
|
1945
|
+
* Note: call this function repeatedly until it returns +nil+, or else
|
1946
|
+
* you will not be able to issue further commands.
|
1947
|
+
*
|
1948
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1949
|
+
* and the PG::Result object will automatically be cleared when the block terminates.
|
1950
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1951
|
+
*/
|
1952
|
+
static VALUE
|
1953
|
+
pgconn_get_result(VALUE self)
|
1954
|
+
{
|
1955
|
+
PGconn *conn = pg_get_pgconn(self);
|
1956
|
+
PGresult *result;
|
1957
|
+
VALUE rb_pgresult;
|
1958
|
+
|
1959
|
+
result = gvl_PQgetResult(conn);
|
1960
|
+
if(result == NULL)
|
1961
|
+
return Qnil;
|
1962
|
+
rb_pgresult = pg_new_result(result, self);
|
1963
|
+
if (rb_block_given_p()) {
|
1964
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1965
|
+
pg_result_clear, rb_pgresult);
|
1966
|
+
}
|
1967
|
+
return rb_pgresult;
|
1968
|
+
}
|
1969
|
+
|
1970
|
+
/*
|
1971
|
+
* call-seq:
|
1972
|
+
* conn.consume_input()
|
1973
|
+
*
|
1974
|
+
* If input is available from the server, consume it.
|
1975
|
+
* After calling +consume_input+, you can check +is_busy+
|
1976
|
+
* or *notifies* to see if the state has changed.
|
1977
|
+
*/
|
1978
|
+
static VALUE
|
1979
|
+
pgconn_consume_input(self)
|
1980
|
+
VALUE self;
|
1981
|
+
{
|
1982
|
+
VALUE error;
|
1983
|
+
PGconn *conn = pg_get_pgconn(self);
|
1984
|
+
/* returns 0 on error */
|
1985
|
+
if(PQconsumeInput(conn) == 0) {
|
1986
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
1987
|
+
rb_iv_set(error, "@connection", self);
|
1988
|
+
rb_exc_raise(error);
|
1989
|
+
}
|
1990
|
+
return Qnil;
|
1991
|
+
}
|
1992
|
+
|
1993
|
+
/*
|
1994
|
+
* call-seq:
|
1995
|
+
* conn.is_busy() -> Boolean
|
1996
|
+
*
|
1997
|
+
* Returns +true+ if a command is busy, that is, if
|
1998
|
+
* PQgetResult would block. Otherwise returns +false+.
|
1999
|
+
*/
|
2000
|
+
static VALUE
|
2001
|
+
pgconn_is_busy(self)
|
2002
|
+
VALUE self;
|
2003
|
+
{
|
2004
|
+
return PQisBusy(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2005
|
+
}
|
2006
|
+
|
2007
|
+
/*
|
2008
|
+
* call-seq:
|
2009
|
+
* conn.setnonblocking(Boolean) -> nil
|
2010
|
+
*
|
2011
|
+
* Sets the nonblocking status of the connection.
|
2012
|
+
* In the blocking state, calls to #send_query
|
2013
|
+
* will block until the message is sent to the server,
|
2014
|
+
* but will not wait for the query results.
|
2015
|
+
* In the nonblocking state, calls to #send_query
|
2016
|
+
* will return an error if the socket is not ready for
|
2017
|
+
* writing.
|
2018
|
+
* Note: This function does not affect #exec, because
|
2019
|
+
* that function doesn't return until the server has
|
2020
|
+
* processed the query and returned the results.
|
2021
|
+
* Returns +nil+.
|
2022
|
+
*/
|
2023
|
+
static VALUE
|
2024
|
+
pgconn_setnonblocking(self, state)
|
2025
|
+
VALUE self, state;
|
2026
|
+
{
|
2027
|
+
int arg;
|
2028
|
+
VALUE error;
|
2029
|
+
PGconn *conn = pg_get_pgconn(self);
|
2030
|
+
if(state == Qtrue)
|
2031
|
+
arg = 1;
|
2032
|
+
else if (state == Qfalse)
|
2033
|
+
arg = 0;
|
2034
|
+
else
|
2035
|
+
rb_raise(rb_eArgError, "Boolean value expected");
|
2036
|
+
|
2037
|
+
if(PQsetnonblocking(conn, arg) == -1) {
|
2038
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2039
|
+
rb_iv_set(error, "@connection", self);
|
2040
|
+
rb_exc_raise(error);
|
2041
|
+
}
|
2042
|
+
return Qnil;
|
2043
|
+
}
|
2044
|
+
|
2045
|
+
|
2046
|
+
/*
|
2047
|
+
* call-seq:
|
2048
|
+
* conn.isnonblocking() -> Boolean
|
2049
|
+
*
|
2050
|
+
* Returns +true+ if a command is busy, that is, if
|
2051
|
+
* PQgetResult would block. Otherwise returns +false+.
|
2052
|
+
*/
|
2053
|
+
static VALUE
|
2054
|
+
pgconn_isnonblocking(self)
|
2055
|
+
VALUE self;
|
2056
|
+
{
|
2057
|
+
return PQisnonblocking(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
2058
|
+
}
|
2059
|
+
|
2060
|
+
/*
|
2061
|
+
* call-seq:
|
2062
|
+
* conn.flush() -> Boolean
|
2063
|
+
*
|
2064
|
+
* Attempts to flush any queued output data to the server.
|
2065
|
+
* Returns +true+ if data is successfully flushed, +false+
|
2066
|
+
* if not (can only return +false+ if connection is
|
2067
|
+
* nonblocking.
|
2068
|
+
* Raises PG::Error if some other failure occurred.
|
2069
|
+
*/
|
2070
|
+
static VALUE
|
2071
|
+
pgconn_flush(self)
|
2072
|
+
VALUE self;
|
2073
|
+
{
|
2074
|
+
PGconn *conn = pg_get_pgconn(self);
|
2075
|
+
int ret;
|
2076
|
+
VALUE error;
|
2077
|
+
ret = PQflush(conn);
|
2078
|
+
if(ret == -1) {
|
2079
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2080
|
+
rb_iv_set(error, "@connection", self);
|
2081
|
+
rb_exc_raise(error);
|
2082
|
+
}
|
2083
|
+
return (ret) ? Qfalse : Qtrue;
|
2084
|
+
}
|
2085
|
+
|
2086
|
+
/*
|
2087
|
+
* call-seq:
|
2088
|
+
* conn.cancel() -> String
|
2089
|
+
*
|
2090
|
+
* Requests cancellation of the command currently being
|
2091
|
+
* processed. (Only implemented in PostgreSQL >= 8.0)
|
2092
|
+
*
|
2093
|
+
* Returns +nil+ on success, or a string containing the
|
2094
|
+
* error message if a failure occurs.
|
2095
|
+
*/
|
2096
|
+
static VALUE
|
2097
|
+
pgconn_cancel(VALUE self)
|
2098
|
+
{
|
2099
|
+
#ifdef HAVE_PQGETCANCEL
|
2100
|
+
char errbuf[256];
|
2101
|
+
PGcancel *cancel;
|
2102
|
+
VALUE retval;
|
2103
|
+
int ret;
|
2104
|
+
|
2105
|
+
cancel = PQgetCancel(pg_get_pgconn(self));
|
2106
|
+
if(cancel == NULL)
|
2107
|
+
rb_raise(rb_ePGerror,"Invalid connection!");
|
2108
|
+
|
2109
|
+
ret = PQcancel(cancel, errbuf, 256);
|
2110
|
+
if(ret == 1)
|
2111
|
+
retval = Qnil;
|
2112
|
+
else
|
2113
|
+
retval = rb_str_new2(errbuf);
|
2114
|
+
|
2115
|
+
PQfreeCancel(cancel);
|
2116
|
+
return retval;
|
2117
|
+
#else
|
2118
|
+
rb_notimplement();
|
2119
|
+
#endif
|
2120
|
+
}
|
2121
|
+
|
2122
|
+
|
2123
|
+
/*
|
2124
|
+
* call-seq:
|
2125
|
+
* conn.notifies()
|
2126
|
+
*
|
2127
|
+
* Returns a hash of the unprocessed notifications.
|
2128
|
+
* If there is no unprocessed notifier, it returns +nil+.
|
2129
|
+
*/
|
2130
|
+
static VALUE
|
2131
|
+
pgconn_notifies(VALUE self)
|
2132
|
+
{
|
2133
|
+
PGconn* conn = pg_get_pgconn(self);
|
2134
|
+
PGnotify *notification;
|
2135
|
+
VALUE hash;
|
2136
|
+
VALUE sym_relname, sym_be_pid, sym_extra;
|
2137
|
+
VALUE relname, be_pid, extra;
|
2138
|
+
|
2139
|
+
sym_relname = ID2SYM(rb_intern("relname"));
|
2140
|
+
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2141
|
+
sym_extra = ID2SYM(rb_intern("extra"));
|
2142
|
+
|
2143
|
+
notification = PQnotifies(conn);
|
2144
|
+
if (notification == NULL) {
|
2145
|
+
return Qnil;
|
2146
|
+
}
|
2147
|
+
|
2148
|
+
hash = rb_hash_new();
|
2149
|
+
relname = rb_tainted_str_new2(notification->relname);
|
2150
|
+
be_pid = INT2NUM(notification->be_pid);
|
2151
|
+
extra = rb_tainted_str_new2(notification->extra);
|
2152
|
+
#ifdef M17N_SUPPORTED
|
2153
|
+
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2154
|
+
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2155
|
+
#endif
|
2156
|
+
|
2157
|
+
rb_hash_aset(hash, sym_relname, relname);
|
2158
|
+
rb_hash_aset(hash, sym_be_pid, be_pid);
|
2159
|
+
rb_hash_aset(hash, sym_extra, extra);
|
2160
|
+
|
2161
|
+
PQfreemem(notification);
|
2162
|
+
return hash;
|
2163
|
+
}
|
2164
|
+
|
2165
|
+
/* Win32 + Ruby 1.8 */
|
2166
|
+
#if !defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
|
2167
|
+
|
2168
|
+
/*
|
2169
|
+
* Duplicate the sockets from libpq and create temporary CRT FDs
|
2170
|
+
*/
|
2171
|
+
void create_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2172
|
+
{
|
2173
|
+
int i;
|
2174
|
+
crt_set->fd_count = os_set->fd_count;
|
2175
|
+
for (i = 0; i < os_set->fd_count; i++) {
|
2176
|
+
WSAPROTOCOL_INFO wsa_pi;
|
2177
|
+
/* dupicate the SOCKET */
|
2178
|
+
int r = WSADuplicateSocket(os_set->fd_array[i], GetCurrentProcessId(), &wsa_pi);
|
2179
|
+
SOCKET s = WSASocket(wsa_pi.iAddressFamily, wsa_pi.iSocketType, wsa_pi.iProtocol, &wsa_pi, 0, 0);
|
2180
|
+
/* create the CRT fd so ruby can get back to the SOCKET */
|
2181
|
+
int fd = _open_osfhandle(s, O_RDWR|O_BINARY);
|
2182
|
+
os_set->fd_array[i] = s;
|
2183
|
+
crt_set->fd_array[i] = fd;
|
2184
|
+
}
|
2185
|
+
}
|
2186
|
+
|
2187
|
+
/*
|
2188
|
+
* Clean up the CRT FDs from create_crt_fd()
|
2189
|
+
*/
|
2190
|
+
void cleanup_crt_fd(fd_set *os_set, fd_set *crt_set)
|
2191
|
+
{
|
2192
|
+
int i;
|
2193
|
+
for (i = 0; i < os_set->fd_count; i++) {
|
2194
|
+
/* cleanup the CRT fd */
|
2195
|
+
_close(crt_set->fd_array[i]);
|
2196
|
+
/* cleanup the duplicated SOCKET */
|
2197
|
+
closesocket(os_set->fd_array[i]);
|
2198
|
+
}
|
2199
|
+
}
|
2200
|
+
#endif
|
2201
|
+
|
2202
|
+
/* Win32 + Ruby 1.9+ */
|
2203
|
+
#if defined( HAVE_RUBY_VM_H ) && defined( _WIN32 )
|
2204
|
+
/*
|
2205
|
+
* On Windows, use platform-specific strategies to wait for the socket
|
2206
|
+
* instead of rb_thread_select().
|
2207
|
+
*/
|
2208
|
+
|
2209
|
+
int rb_w32_wait_events( HANDLE *events, int num, DWORD timeout );
|
2210
|
+
|
2211
|
+
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2212
|
+
* and does not wait (nor sleep) any time even if timeout is given.
|
2213
|
+
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2214
|
+
|
2215
|
+
static void *
|
2216
|
+
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *) )
|
2217
|
+
{
|
2218
|
+
int sd = PQsocket( conn );
|
2219
|
+
void *retval;
|
2220
|
+
DWORD timeout_milisec = INFINITE;
|
2221
|
+
DWORD wait_ret;
|
2222
|
+
WSAEVENT hEvent;
|
2223
|
+
|
2224
|
+
if ( sd < 0 )
|
2225
|
+
rb_bug( "PQsocket(conn): couldn't fetch the connection's socket!" );
|
2226
|
+
|
2227
|
+
hEvent = WSACreateEvent();
|
2228
|
+
|
2229
|
+
if ( ptimeout ) {
|
2230
|
+
timeout_milisec = (DWORD)( ptimeout->tv_sec * 1e3 + ptimeout->tv_usec / 1e3 );
|
2231
|
+
}
|
2232
|
+
|
2233
|
+
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2234
|
+
if( PQconsumeInput(conn) == 0 ) {
|
2235
|
+
WSACloseEvent( hEvent );
|
2236
|
+
rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
|
2237
|
+
}
|
2238
|
+
|
2239
|
+
while ( !(retval=is_readable(conn)) ) {
|
2240
|
+
if ( WSAEventSelect(sd, hEvent, FD_READ|FD_CLOSE) == SOCKET_ERROR ) {
|
2241
|
+
WSACloseEvent( hEvent );
|
2242
|
+
rb_raise( rb_ePGerror, "WSAEventSelect socket error: %d", WSAGetLastError() );
|
2243
|
+
}
|
2244
|
+
|
2245
|
+
wait_ret = rb_w32_wait_events( &hEvent, 1, timeout_milisec );
|
2246
|
+
|
2247
|
+
if ( wait_ret == WAIT_TIMEOUT ) {
|
2248
|
+
WSACloseEvent( hEvent );
|
2249
|
+
return NULL;
|
2250
|
+
} else if ( wait_ret == WAIT_OBJECT_0 ) {
|
2251
|
+
/* The event we were waiting for. */
|
2252
|
+
} else if ( wait_ret == WAIT_OBJECT_0 + 1) {
|
2253
|
+
/* This indicates interruption from timer thread, GC, exception
|
2254
|
+
* from other threads etc... */
|
2255
|
+
rb_thread_check_ints();
|
2256
|
+
} else if ( wait_ret == WAIT_FAILED ) {
|
2257
|
+
WSACloseEvent( hEvent );
|
2258
|
+
rb_raise( rb_ePGerror, "Wait on socket error (WaitForMultipleObjects): %lu", GetLastError() );
|
2259
|
+
} else {
|
2260
|
+
WSACloseEvent( hEvent );
|
2261
|
+
rb_raise( rb_ePGerror, "Wait on socket abandoned (WaitForMultipleObjects)" );
|
2262
|
+
}
|
2263
|
+
|
2264
|
+
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2265
|
+
if ( PQconsumeInput(conn) == 0 ) {
|
2266
|
+
WSACloseEvent( hEvent );
|
2267
|
+
rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
|
2268
|
+
}
|
2269
|
+
}
|
2270
|
+
|
2271
|
+
WSACloseEvent( hEvent );
|
2272
|
+
return retval;
|
2273
|
+
}
|
2274
|
+
|
2275
|
+
#else
|
2276
|
+
|
2277
|
+
/* non Win32 or Win32+Ruby-1.8 */
|
2278
|
+
|
2279
|
+
static void *
|
2280
|
+
wait_socket_readable( PGconn *conn, struct timeval *ptimeout, void *(*is_readable)(PGconn *))
|
2281
|
+
{
|
2282
|
+
int sd = PQsocket( conn );
|
2283
|
+
int ret;
|
2284
|
+
void *retval;
|
2285
|
+
rb_fdset_t sd_rset;
|
2286
|
+
#ifdef _WIN32
|
2287
|
+
rb_fdset_t crt_sd_rset;
|
2288
|
+
#endif
|
2289
|
+
|
2290
|
+
if ( sd < 0 )
|
2291
|
+
rb_bug( "PQsocket(conn): couldn't fetch the connection's socket!" );
|
2292
|
+
|
2293
|
+
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2294
|
+
if ( PQconsumeInput(conn) == 0 )
|
2295
|
+
rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
|
2296
|
+
|
2297
|
+
rb_fd_init( &sd_rset );
|
2298
|
+
|
2299
|
+
while ( !(retval=is_readable(conn)) ) {
|
2300
|
+
rb_fd_zero( &sd_rset );
|
2301
|
+
rb_fd_set( sd, &sd_rset );
|
2302
|
+
|
2303
|
+
#ifdef _WIN32
|
2304
|
+
/* Ruby's FD_SET is modified on win32 to convert a file descriptor
|
2305
|
+
* to osfhandle, but we already get a osfhandle from PQsocket().
|
2306
|
+
* Therefore it's overwritten here. */
|
2307
|
+
sd_rset.fd_array[0] = sd;
|
2308
|
+
create_crt_fd(&sd_rset, &crt_sd_rset);
|
2309
|
+
#endif
|
2310
|
+
|
2311
|
+
/* Wait for the socket to become readable before checking again */
|
2312
|
+
ret = rb_thread_fd_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
|
2313
|
+
|
2314
|
+
#ifdef _WIN32
|
2315
|
+
cleanup_crt_fd(&sd_rset, &crt_sd_rset);
|
2316
|
+
#endif
|
2317
|
+
|
2318
|
+
if ( ret < 0 ){
|
2319
|
+
rb_fd_term( &sd_rset );
|
2320
|
+
rb_sys_fail( "rb_thread_select()" );
|
2321
|
+
}
|
2322
|
+
|
2323
|
+
/* Return false if the select() timed out */
|
2324
|
+
if ( ret == 0 ){
|
2325
|
+
rb_fd_term( &sd_rset );
|
2326
|
+
return NULL;
|
2327
|
+
}
|
2328
|
+
|
2329
|
+
/* Check for connection errors (PQisBusy is true on connection errors) */
|
2330
|
+
if ( PQconsumeInput(conn) == 0 ){
|
2331
|
+
rb_fd_term( &sd_rset );
|
2332
|
+
rb_raise( rb_ePGerror, "%s", PQerrorMessage(conn) );
|
2333
|
+
}
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
rb_fd_term( &sd_rset );
|
2337
|
+
return retval;
|
2338
|
+
}
|
2339
|
+
|
2340
|
+
|
2341
|
+
#endif
|
2342
|
+
|
2343
|
+
static void *
|
2344
|
+
notify_readable(PGconn *conn)
|
2345
|
+
{
|
2346
|
+
return (void*)PQnotifies(conn);
|
2347
|
+
}
|
2348
|
+
|
2349
|
+
/*
|
2350
|
+
* call-seq:
|
2351
|
+
* conn.wait_for_notify( [ timeout ] ) -> String
|
2352
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2353
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid, payload| block } # PostgreSQL 9.0
|
2354
|
+
*
|
2355
|
+
* Blocks while waiting for notification(s), or until the optional
|
2356
|
+
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2357
|
+
* measured in seconds and can be fractional.
|
2358
|
+
*
|
2359
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2360
|
+
* event otherwise. If used in block form, passes the name of the
|
2361
|
+
* NOTIFY +event+ and the generating +pid+ into the block.
|
2362
|
+
*
|
2363
|
+
* Under PostgreSQL 9.0 and later, if the notification is sent with
|
2364
|
+
* the optional +payload+ string, it will be given to the block as the
|
2365
|
+
* third argument.
|
2366
|
+
*
|
2367
|
+
*/
|
2368
|
+
static VALUE
|
2369
|
+
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2370
|
+
{
|
2371
|
+
PGconn *conn = pg_get_pgconn( self );
|
2372
|
+
PGnotify *pnotification;
|
2373
|
+
struct timeval timeout;
|
2374
|
+
struct timeval *ptimeout = NULL;
|
2375
|
+
VALUE timeout_in = Qnil, relname = Qnil, be_pid = Qnil, extra = Qnil;
|
2376
|
+
double timeout_sec;
|
2377
|
+
|
2378
|
+
rb_scan_args( argc, argv, "01", &timeout_in );
|
2379
|
+
|
2380
|
+
if ( RTEST(timeout_in) ) {
|
2381
|
+
timeout_sec = NUM2DBL( timeout_in );
|
2382
|
+
timeout.tv_sec = (time_t)timeout_sec;
|
2383
|
+
timeout.tv_usec = (suseconds_t)( (timeout_sec - (long)timeout_sec) * 1e6 );
|
2384
|
+
ptimeout = &timeout;
|
2385
|
+
}
|
2386
|
+
|
2387
|
+
pnotification = (PGnotify*) wait_socket_readable( conn, ptimeout, notify_readable);
|
2388
|
+
|
2389
|
+
/* Return nil if the select timed out */
|
2390
|
+
if ( !pnotification ) return Qnil;
|
2391
|
+
|
2392
|
+
relname = rb_tainted_str_new2( pnotification->relname );
|
2393
|
+
#ifdef M17N_SUPPORTED
|
2394
|
+
ENCODING_SET( relname, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2395
|
+
#endif
|
2396
|
+
be_pid = INT2NUM( pnotification->be_pid );
|
2397
|
+
#ifdef HAVE_ST_NOTIFY_EXTRA
|
2398
|
+
if ( *pnotification->extra ) {
|
2399
|
+
extra = rb_tainted_str_new2( pnotification->extra );
|
2400
|
+
#ifdef M17N_SUPPORTED
|
2401
|
+
ENCODING_SET( extra, rb_enc_to_index(pg_conn_enc_get( conn )) );
|
2402
|
+
#endif
|
2403
|
+
}
|
2404
|
+
#endif
|
2405
|
+
PQfreemem( pnotification );
|
2406
|
+
|
2407
|
+
if ( rb_block_given_p() )
|
2408
|
+
rb_yield_values( 3, relname, be_pid, extra );
|
2409
|
+
|
2410
|
+
return relname;
|
2411
|
+
}
|
2412
|
+
|
2413
|
+
|
2414
|
+
/*
|
2415
|
+
* call-seq:
|
2416
|
+
* conn.put_copy_data( buffer ) -> Boolean
|
2417
|
+
*
|
2418
|
+
* Transmits _buffer_ as copy data to the server.
|
2419
|
+
* Returns true if the data was sent, false if it was
|
2420
|
+
* not sent (false is only possible if the connection
|
2421
|
+
* is in nonblocking mode, and this command would block).
|
2422
|
+
*
|
2423
|
+
* Raises an exception if an error occurs.
|
2424
|
+
*/
|
2425
|
+
static VALUE
|
2426
|
+
pgconn_put_copy_data(self, buffer)
|
2427
|
+
VALUE self, buffer;
|
2428
|
+
{
|
2429
|
+
int ret;
|
2430
|
+
VALUE error;
|
2431
|
+
PGconn *conn = pg_get_pgconn(self);
|
2432
|
+
Check_Type(buffer, T_STRING);
|
2433
|
+
|
2434
|
+
ret = gvl_PQputCopyData(conn, RSTRING_PTR(buffer), (int)RSTRING_LEN(buffer));
|
2435
|
+
if(ret == -1) {
|
2436
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2437
|
+
rb_iv_set(error, "@connection", self);
|
2438
|
+
rb_exc_raise(error);
|
2439
|
+
}
|
2440
|
+
return (ret) ? Qtrue : Qfalse;
|
2441
|
+
}
|
2442
|
+
|
2443
|
+
/*
|
2444
|
+
* call-seq:
|
2445
|
+
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2446
|
+
*
|
2447
|
+
* Sends end-of-data indication to the server.
|
2448
|
+
*
|
2449
|
+
* _error_message_ is an optional parameter, and if set,
|
2450
|
+
* forces the COPY command to fail with the string
|
2451
|
+
* _error_message_.
|
2452
|
+
*
|
2453
|
+
* Returns true if the end-of-data was sent, false if it was
|
2454
|
+
* not sent (false is only possible if the connection
|
2455
|
+
* is in nonblocking mode, and this command would block).
|
2456
|
+
*/
|
2457
|
+
static VALUE
|
2458
|
+
pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2459
|
+
{
|
2460
|
+
VALUE str;
|
2461
|
+
VALUE error;
|
2462
|
+
int ret;
|
2463
|
+
char *error_message = NULL;
|
2464
|
+
PGconn *conn = pg_get_pgconn(self);
|
2465
|
+
|
2466
|
+
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2467
|
+
error_message = NULL;
|
2468
|
+
else
|
2469
|
+
error_message = StringValuePtr(str);
|
2470
|
+
|
2471
|
+
ret = gvl_PQputCopyEnd(conn, error_message);
|
2472
|
+
if(ret == -1) {
|
2473
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2474
|
+
rb_iv_set(error, "@connection", self);
|
2475
|
+
rb_exc_raise(error);
|
2476
|
+
}
|
2477
|
+
return (ret) ? Qtrue : Qfalse;
|
2478
|
+
}
|
2479
|
+
|
2480
|
+
/*
|
2481
|
+
* call-seq:
|
2482
|
+
* conn.get_copy_data( [ async = false ] ) -> String
|
2483
|
+
*
|
2484
|
+
* Return a string containing one row of data, +nil+
|
2485
|
+
* if the copy is done, or +false+ if the call would
|
2486
|
+
* block (only possible if _async_ is true).
|
2487
|
+
*
|
2488
|
+
*/
|
2489
|
+
static VALUE
|
2490
|
+
pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2491
|
+
{
|
2492
|
+
VALUE async_in;
|
2493
|
+
VALUE error;
|
2494
|
+
VALUE result_str;
|
2495
|
+
int ret;
|
2496
|
+
int async;
|
2497
|
+
char *buffer;
|
2498
|
+
PGconn *conn = pg_get_pgconn(self);
|
2499
|
+
|
2500
|
+
if (rb_scan_args(argc, argv, "01", &async_in) == 0)
|
2501
|
+
async = 0;
|
2502
|
+
else
|
2503
|
+
async = (async_in == Qfalse || async_in == Qnil) ? 0 : 1;
|
2504
|
+
|
2505
|
+
ret = gvl_PQgetCopyData(conn, &buffer, async);
|
2506
|
+
if(ret == -2) { /* error */
|
2507
|
+
error = rb_exc_new2(rb_ePGerror, PQerrorMessage(conn));
|
2508
|
+
rb_iv_set(error, "@connection", self);
|
2509
|
+
rb_exc_raise(error);
|
2510
|
+
}
|
2511
|
+
if(ret == -1) { /* No data left */
|
2512
|
+
return Qnil;
|
2513
|
+
}
|
2514
|
+
if(ret == 0) { /* would block */
|
2515
|
+
return Qfalse;
|
2516
|
+
}
|
2517
|
+
result_str = rb_tainted_str_new(buffer, ret);
|
2518
|
+
PQfreemem(buffer);
|
2519
|
+
return result_str;
|
2520
|
+
}
|
2521
|
+
|
2522
|
+
/*
|
2523
|
+
* call-seq:
|
2524
|
+
* conn.set_error_verbosity( verbosity ) -> Fixnum
|
2525
|
+
*
|
2526
|
+
* Sets connection's verbosity to _verbosity_ and returns
|
2527
|
+
* the previous setting. Available settings are:
|
2528
|
+
* * PQERRORS_TERSE
|
2529
|
+
* * PQERRORS_DEFAULT
|
2530
|
+
* * PQERRORS_VERBOSE
|
2531
|
+
*/
|
2532
|
+
static VALUE
|
2533
|
+
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
2534
|
+
{
|
2535
|
+
PGconn *conn = pg_get_pgconn(self);
|
2536
|
+
PGVerbosity verbosity = NUM2INT(in_verbosity);
|
2537
|
+
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2538
|
+
}
|
2539
|
+
|
2540
|
+
/*
|
2541
|
+
* call-seq:
|
2542
|
+
* conn.trace( stream ) -> nil
|
2543
|
+
*
|
2544
|
+
* Enables tracing message passing between backend. The
|
2545
|
+
* trace message will be written to the stream _stream_,
|
2546
|
+
* which must implement a method +fileno+ that returns
|
2547
|
+
* a writable file descriptor.
|
2548
|
+
*/
|
2549
|
+
static VALUE
|
2550
|
+
pgconn_trace(VALUE self, VALUE stream)
|
2551
|
+
{
|
2552
|
+
VALUE fileno;
|
2553
|
+
FILE *new_fp;
|
2554
|
+
int old_fd, new_fd;
|
2555
|
+
VALUE new_file;
|
2556
|
+
|
2557
|
+
if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
|
2558
|
+
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2559
|
+
|
2560
|
+
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
2561
|
+
if(fileno == Qnil)
|
2562
|
+
rb_raise(rb_eArgError, "can't get file descriptor from stream");
|
2563
|
+
|
2564
|
+
/* Duplicate the file descriptor and re-open
|
2565
|
+
* it. Then, make it into a ruby File object
|
2566
|
+
* and assign it to an instance variable.
|
2567
|
+
* This prevents a problem when the File
|
2568
|
+
* object passed to this function is closed
|
2569
|
+
* before the connection object is. */
|
2570
|
+
old_fd = NUM2INT(fileno);
|
2571
|
+
new_fd = dup(old_fd);
|
2572
|
+
new_fp = fdopen(new_fd, "w");
|
2573
|
+
|
2574
|
+
if(new_fp == NULL)
|
2575
|
+
rb_raise(rb_eArgError, "stream is not writable");
|
2576
|
+
|
2577
|
+
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2578
|
+
rb_iv_set(self, "@trace_stream", new_file);
|
2579
|
+
|
2580
|
+
PQtrace(pg_get_pgconn(self), new_fp);
|
2581
|
+
return Qnil;
|
2582
|
+
}
|
2583
|
+
|
2584
|
+
/*
|
2585
|
+
* call-seq:
|
2586
|
+
* conn.untrace() -> nil
|
2587
|
+
*
|
2588
|
+
* Disables the message tracing.
|
2589
|
+
*/
|
2590
|
+
static VALUE
|
2591
|
+
pgconn_untrace(VALUE self)
|
2592
|
+
{
|
2593
|
+
VALUE trace_stream;
|
2594
|
+
PQuntrace(pg_get_pgconn(self));
|
2595
|
+
trace_stream = rb_iv_get(self, "@trace_stream");
|
2596
|
+
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2597
|
+
rb_iv_set(self, "@trace_stream", Qnil);
|
2598
|
+
return Qnil;
|
2599
|
+
}
|
2600
|
+
|
2601
|
+
|
2602
|
+
/*
|
2603
|
+
* Notice callback proxy function -- delegate the callback to the
|
2604
|
+
* currently-registered Ruby notice_receiver object.
|
2605
|
+
*/
|
2606
|
+
void
|
2607
|
+
notice_receiver_proxy(void *arg, const PGresult *result)
|
2608
|
+
{
|
2609
|
+
VALUE proc;
|
2610
|
+
VALUE self = (VALUE)arg;
|
2611
|
+
|
2612
|
+
if ((proc = rb_iv_get(self, "@notice_receiver")) != Qnil) {
|
2613
|
+
VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, NULL, (PGresult*)result);
|
2614
|
+
#ifdef M17N_SUPPORTED
|
2615
|
+
PGconn *conn = pg_get_pgconn( self );
|
2616
|
+
rb_encoding *enc = pg_conn_enc_get( conn );
|
2617
|
+
ENCODING_SET( val, rb_enc_to_index(enc) );
|
2618
|
+
#endif
|
2619
|
+
rb_funcall(proc, rb_intern("call"), 1, val);
|
2620
|
+
}
|
2621
|
+
return;
|
2622
|
+
}
|
2623
|
+
|
2624
|
+
/*
|
2625
|
+
* call-seq:
|
2626
|
+
* conn.set_notice_receiver {|result| ... } -> Proc
|
2627
|
+
*
|
2628
|
+
* Notice and warning messages generated by the server are not returned
|
2629
|
+
* by the query execution functions, since they do not imply failure of
|
2630
|
+
* the query. Instead they are passed to a notice handling function, and
|
2631
|
+
* execution continues normally after the handler returns. The default
|
2632
|
+
* notice handling function prints the message on <tt>stderr</tt>, but the
|
2633
|
+
* application can override this behavior by supplying its own handling
|
2634
|
+
* function.
|
2635
|
+
*
|
2636
|
+
* For historical reasons, there are two levels of notice handling, called the
|
2637
|
+
* notice receiver and notice processor. The default behavior is for the notice
|
2638
|
+
* receiver to format the notice and pass a string to the notice processor for
|
2639
|
+
* printing. However, an application that chooses to provide its own notice
|
2640
|
+
* receiver will typically ignore the notice processor layer and just do all
|
2641
|
+
* the work in the notice receiver.
|
2642
|
+
*
|
2643
|
+
* This function takes a new block to act as the handler, which should
|
2644
|
+
* accept a single parameter that will be a PG::Result object, and returns
|
2645
|
+
* the Proc object previously set, or +nil+ if it was previously the default.
|
2646
|
+
*
|
2647
|
+
* If you pass no arguments, it will reset the handler to the default.
|
2648
|
+
*
|
2649
|
+
* *Note:* The +result+ passed to the block should not be used outside
|
2650
|
+
* of the block, since the corresponding C object could be freed after the
|
2651
|
+
* block finishes.
|
2652
|
+
*/
|
2653
|
+
static VALUE
|
2654
|
+
pgconn_set_notice_receiver(VALUE self)
|
2655
|
+
{
|
2656
|
+
VALUE proc, old_proc;
|
2657
|
+
PGconn *conn = pg_get_pgconn(self);
|
2658
|
+
|
2659
|
+
/* If default_notice_receiver is unset, assume that the current
|
2660
|
+
* notice receiver is the default, and save it to a global variable.
|
2661
|
+
* This should not be a problem because the default receiver is
|
2662
|
+
* always the same, so won't vary among connections.
|
2663
|
+
*/
|
2664
|
+
if(default_notice_receiver == NULL)
|
2665
|
+
default_notice_receiver = PQsetNoticeReceiver(conn, NULL, NULL);
|
2666
|
+
|
2667
|
+
old_proc = rb_iv_get(self, "@notice_receiver");
|
2668
|
+
if( rb_block_given_p() ) {
|
2669
|
+
proc = rb_block_proc();
|
2670
|
+
PQsetNoticeReceiver(conn, gvl_notice_receiver_proxy, (void *)self);
|
2671
|
+
} else {
|
2672
|
+
/* if no block is given, set back to default */
|
2673
|
+
proc = Qnil;
|
2674
|
+
PQsetNoticeReceiver(conn, default_notice_receiver, NULL);
|
2675
|
+
}
|
2676
|
+
|
2677
|
+
rb_iv_set(self, "@notice_receiver", proc);
|
2678
|
+
return old_proc;
|
2679
|
+
}
|
2680
|
+
|
2681
|
+
|
2682
|
+
/*
|
2683
|
+
* Notice callback proxy function -- delegate the callback to the
|
2684
|
+
* currently-registered Ruby notice_processor object.
|
2685
|
+
*/
|
2686
|
+
void
|
2687
|
+
notice_processor_proxy(void *arg, const char *message)
|
2688
|
+
{
|
2689
|
+
VALUE proc;
|
2690
|
+
VALUE self = (VALUE)arg;
|
2691
|
+
|
2692
|
+
if ((proc = rb_iv_get(self, "@notice_processor")) != Qnil) {
|
2693
|
+
VALUE message_str = rb_tainted_str_new2(message);
|
2694
|
+
#ifdef M17N_SUPPORTED
|
2695
|
+
PGconn *conn = pg_get_pgconn( self );
|
2696
|
+
rb_encoding *enc = pg_conn_enc_get( conn );
|
2697
|
+
ENCODING_SET( message_str, rb_enc_to_index(enc) );
|
2698
|
+
#endif
|
2699
|
+
rb_funcall(proc, rb_intern("call"), 1, message_str);
|
2700
|
+
}
|
2701
|
+
return;
|
2702
|
+
}
|
2703
|
+
|
2704
|
+
/*
|
2705
|
+
* call-seq:
|
2706
|
+
* conn.set_notice_processor {|message| ... } -> Proc
|
2707
|
+
*
|
2708
|
+
* See #set_notice_receiver for the desription of what this and the
|
2709
|
+
* notice_processor methods do.
|
2710
|
+
*
|
2711
|
+
* This function takes a new block to act as the notice processor and returns
|
2712
|
+
* the Proc object previously set, or +nil+ if it was previously the default.
|
2713
|
+
* The block should accept a single String object.
|
2714
|
+
*
|
2715
|
+
* If you pass no arguments, it will reset the handler to the default.
|
2716
|
+
*/
|
2717
|
+
static VALUE
|
2718
|
+
pgconn_set_notice_processor(VALUE self)
|
2719
|
+
{
|
2720
|
+
VALUE proc, old_proc;
|
2721
|
+
PGconn *conn = pg_get_pgconn(self);
|
2722
|
+
|
2723
|
+
/* If default_notice_processor is unset, assume that the current
|
2724
|
+
* notice processor is the default, and save it to a global variable.
|
2725
|
+
* This should not be a problem because the default processor is
|
2726
|
+
* always the same, so won't vary among connections.
|
2727
|
+
*/
|
2728
|
+
if(default_notice_processor == NULL)
|
2729
|
+
default_notice_processor = PQsetNoticeProcessor(conn, NULL, NULL);
|
2730
|
+
|
2731
|
+
old_proc = rb_iv_get(self, "@notice_processor");
|
2732
|
+
if( rb_block_given_p() ) {
|
2733
|
+
proc = rb_block_proc();
|
2734
|
+
PQsetNoticeProcessor(conn, gvl_notice_processor_proxy, (void *)self);
|
2735
|
+
} else {
|
2736
|
+
/* if no block is given, set back to default */
|
2737
|
+
proc = Qnil;
|
2738
|
+
PQsetNoticeProcessor(conn, default_notice_processor, NULL);
|
2739
|
+
}
|
2740
|
+
|
2741
|
+
rb_iv_set(self, "@notice_processor", proc);
|
2742
|
+
return old_proc;
|
2743
|
+
}
|
2744
|
+
|
2745
|
+
|
2746
|
+
/*
|
2747
|
+
* call-seq:
|
2748
|
+
* conn.get_client_encoding() -> String
|
2749
|
+
*
|
2750
|
+
* Returns the client encoding as a String.
|
2751
|
+
*/
|
2752
|
+
static VALUE
|
2753
|
+
pgconn_get_client_encoding(VALUE self)
|
2754
|
+
{
|
2755
|
+
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(pg_get_pgconn(self)));
|
2756
|
+
return rb_tainted_str_new2(encoding);
|
2757
|
+
}
|
2758
|
+
|
2759
|
+
|
2760
|
+
/*
|
2761
|
+
* call-seq:
|
2762
|
+
* conn.set_client_encoding( encoding )
|
2763
|
+
*
|
2764
|
+
* Sets the client encoding to the _encoding_ String.
|
2765
|
+
*/
|
2766
|
+
static VALUE
|
2767
|
+
pgconn_set_client_encoding(VALUE self, VALUE str)
|
2768
|
+
{
|
2769
|
+
PGconn *conn = pg_get_pgconn( self );
|
2770
|
+
|
2771
|
+
Check_Type(str, T_STRING);
|
2772
|
+
|
2773
|
+
if ( (PQsetClientEncoding(conn, StringValuePtr(str))) == -1 ) {
|
2774
|
+
rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValuePtr(str));
|
2775
|
+
}
|
2776
|
+
|
2777
|
+
return Qnil;
|
2778
|
+
}
|
2779
|
+
|
2780
|
+
/*
|
2781
|
+
* call-seq:
|
2782
|
+
* conn.transaction { |conn| ... } -> nil
|
2783
|
+
*
|
2784
|
+
* Executes a +BEGIN+ at the start of the block,
|
2785
|
+
* and a +COMMIT+ at the end of the block, or
|
2786
|
+
* +ROLLBACK+ if any exception occurs.
|
2787
|
+
*/
|
2788
|
+
static VALUE
|
2789
|
+
pgconn_transaction(VALUE self)
|
2790
|
+
{
|
2791
|
+
PGconn *conn = pg_get_pgconn(self);
|
2792
|
+
PGresult *result;
|
2793
|
+
VALUE rb_pgresult;
|
2794
|
+
int status;
|
2795
|
+
|
2796
|
+
if (rb_block_given_p()) {
|
2797
|
+
result = gvl_PQexec(conn, "BEGIN");
|
2798
|
+
rb_pgresult = pg_new_result(result, self);
|
2799
|
+
pg_result_check(rb_pgresult);
|
2800
|
+
rb_protect(rb_yield, self, &status);
|
2801
|
+
if(status == 0) {
|
2802
|
+
result = gvl_PQexec(conn, "COMMIT");
|
2803
|
+
rb_pgresult = pg_new_result(result, self);
|
2804
|
+
pg_result_check(rb_pgresult);
|
2805
|
+
}
|
2806
|
+
else {
|
2807
|
+
/* exception occurred, ROLLBACK and re-raise */
|
2808
|
+
result = gvl_PQexec(conn, "ROLLBACK");
|
2809
|
+
rb_pgresult = pg_new_result(result, self);
|
2810
|
+
pg_result_check(rb_pgresult);
|
2811
|
+
rb_jump_tag(status);
|
2812
|
+
}
|
2813
|
+
|
2814
|
+
}
|
2815
|
+
else {
|
2816
|
+
/* no block supplied? */
|
2817
|
+
rb_raise(rb_eArgError, "Must supply block for PG::Connection#transaction");
|
2818
|
+
}
|
2819
|
+
return Qnil;
|
2820
|
+
}
|
2821
|
+
|
2822
|
+
|
2823
|
+
/*
|
2824
|
+
* call-seq:
|
2825
|
+
* PG::Connection.quote_ident( str ) -> String
|
2826
|
+
* conn.quote_ident( str ) -> String
|
2827
|
+
*
|
2828
|
+
* Returns a string that is safe for inclusion in a SQL query as an
|
2829
|
+
* identifier. Note: this is not a quote function for values, but for
|
2830
|
+
* identifiers.
|
2831
|
+
*
|
2832
|
+
* For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
|
2833
|
+
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
2834
|
+
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
2835
|
+
* field name <tt>FOO</tt>, use this function like
|
2836
|
+
* <tt>PG::Connection.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
2837
|
+
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
2838
|
+
* it will not fold to lower case.
|
2839
|
+
*
|
2840
|
+
* Similarly, this function also protects against special characters,
|
2841
|
+
* and other things that might allow SQL injection if the identifier
|
2842
|
+
* comes from an untrusted source.
|
2843
|
+
*/
|
2844
|
+
static VALUE
|
2845
|
+
pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
2846
|
+
{
|
2847
|
+
VALUE ret;
|
2848
|
+
char *str = StringValuePtr(in_str);
|
2849
|
+
/* result size at most NAMEDATALEN*2 plus surrounding
|
2850
|
+
* double-quotes. */
|
2851
|
+
char buffer[NAMEDATALEN*2+2];
|
2852
|
+
unsigned int i=0,j=0;
|
2853
|
+
|
2854
|
+
UNUSED( self );
|
2855
|
+
|
2856
|
+
if(strlen(str) >= NAMEDATALEN) {
|
2857
|
+
rb_raise(rb_eArgError,
|
2858
|
+
"Input string is longer than NAMEDATALEN-1 (%d)",
|
2859
|
+
NAMEDATALEN-1);
|
2860
|
+
}
|
2861
|
+
buffer[j++] = '"';
|
2862
|
+
for(i = 0; i < strlen(str) && str[i]; i++) {
|
2863
|
+
if(str[i] == '"')
|
2864
|
+
buffer[j++] = '"';
|
2865
|
+
buffer[j++] = str[i];
|
2866
|
+
}
|
2867
|
+
buffer[j++] = '"';
|
2868
|
+
ret = rb_str_new(buffer,j);
|
2869
|
+
OBJ_INFECT(ret, in_str);
|
2870
|
+
return ret;
|
2871
|
+
}
|
2872
|
+
|
2873
|
+
|
2874
|
+
static void *
|
2875
|
+
get_result_readable(PGconn *conn)
|
2876
|
+
{
|
2877
|
+
return PQisBusy(conn) ? NULL : (void*)1;
|
2878
|
+
}
|
2879
|
+
|
2880
|
+
|
2881
|
+
/*
|
2882
|
+
* call-seq:
|
2883
|
+
* conn.block( [ timeout ] ) -> Boolean
|
2884
|
+
*
|
2885
|
+
* Blocks until the server is no longer busy, or until the
|
2886
|
+
* optional _timeout_ is reached, whichever comes first.
|
2887
|
+
* _timeout_ is measured in seconds and can be fractional.
|
2888
|
+
*
|
2889
|
+
* Returns +false+ if _timeout_ is reached, +true+ otherwise.
|
2890
|
+
*
|
2891
|
+
* If +true+ is returned, +conn.is_busy+ will return +false+
|
2892
|
+
* and +conn.get_result+ will not block.
|
2893
|
+
*/
|
2894
|
+
static VALUE
|
2895
|
+
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
2896
|
+
PGconn *conn = pg_get_pgconn( self );
|
2897
|
+
|
2898
|
+
/* If WIN32 and Ruby 1.9 do not use rb_thread_select() which sometimes hangs
|
2899
|
+
* and does not wait (nor sleep) any time even if timeout is given.
|
2900
|
+
* Instead use the Winsock events and rb_w32_wait_events(). */
|
2901
|
+
|
2902
|
+
struct timeval timeout;
|
2903
|
+
struct timeval *ptimeout = NULL;
|
2904
|
+
VALUE timeout_in;
|
2905
|
+
double timeout_sec;
|
2906
|
+
void *ret;
|
2907
|
+
|
2908
|
+
if ( rb_scan_args(argc, argv, "01", &timeout_in) == 1 ) {
|
2909
|
+
timeout_sec = NUM2DBL( timeout_in );
|
2910
|
+
timeout.tv_sec = (time_t)timeout_sec;
|
2911
|
+
timeout.tv_usec = (suseconds_t)((timeout_sec - (long)timeout_sec) * 1e6);
|
2912
|
+
ptimeout = &timeout;
|
2913
|
+
}
|
2914
|
+
|
2915
|
+
ret = wait_socket_readable( conn, ptimeout, get_result_readable);
|
2916
|
+
|
2917
|
+
if( !ret )
|
2918
|
+
return Qfalse;
|
2919
|
+
|
2920
|
+
return Qtrue;
|
2921
|
+
}
|
2922
|
+
|
2923
|
+
|
2924
|
+
/*
|
2925
|
+
* call-seq:
|
2926
|
+
* conn.get_last_result( ) -> PG::Result
|
2927
|
+
*
|
2928
|
+
* This function retrieves all available results
|
2929
|
+
* on the current connection (from previously issued
|
2930
|
+
* asynchronous commands like +send_query()+) and
|
2931
|
+
* returns the last non-NULL result, or +nil+ if no
|
2932
|
+
* results are available.
|
2933
|
+
*
|
2934
|
+
* This function is similar to #get_result
|
2935
|
+
* except that it is designed to get one and only
|
2936
|
+
* one result.
|
2937
|
+
*/
|
2938
|
+
static VALUE
|
2939
|
+
pgconn_get_last_result(VALUE self)
|
2940
|
+
{
|
2941
|
+
PGconn *conn = pg_get_pgconn(self);
|
2942
|
+
VALUE rb_pgresult = Qnil;
|
2943
|
+
PGresult *cur, *prev;
|
2944
|
+
|
2945
|
+
|
2946
|
+
cur = prev = NULL;
|
2947
|
+
while ((cur = gvl_PQgetResult(conn)) != NULL) {
|
2948
|
+
int status;
|
2949
|
+
|
2950
|
+
if (prev) PQclear(prev);
|
2951
|
+
prev = cur;
|
2952
|
+
|
2953
|
+
status = PQresultStatus(cur);
|
2954
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
2955
|
+
break;
|
2956
|
+
}
|
2957
|
+
|
2958
|
+
if (prev) {
|
2959
|
+
rb_pgresult = pg_new_result( prev, self );
|
2960
|
+
pg_result_check(rb_pgresult);
|
2961
|
+
}
|
2962
|
+
|
2963
|
+
return rb_pgresult;
|
2964
|
+
}
|
2965
|
+
|
2966
|
+
#if !defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
2967
|
+
|
2968
|
+
/*
|
2969
|
+
* call-seq:
|
2970
|
+
* conn.async_exec(sql [, params, result_format ] ) -> PG::Result
|
2971
|
+
* conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
|
2972
|
+
*
|
2973
|
+
* This function has the same behavior as #exec,
|
2974
|
+
* but ensures that other threads can process while
|
2975
|
+
* waiting for the server to complete the request.
|
2976
|
+
*
|
2977
|
+
* On Ruby platforms with native threads (MRI-1.9+ and all others)
|
2978
|
+
* this method is an alias to #exec.
|
2979
|
+
*
|
2980
|
+
* On MRI-1.8 it's implemented using asynchronous command
|
2981
|
+
* processing and ruby's +rb_thread_select+ .
|
2982
|
+
*/
|
2983
|
+
static VALUE
|
2984
|
+
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
2985
|
+
{
|
2986
|
+
VALUE rb_pgresult = Qnil;
|
2987
|
+
|
2988
|
+
/* remove any remaining results from the queue */
|
2989
|
+
pgconn_block( 0, NULL, self ); /* wait for input (without blocking) before reading the last result */
|
2990
|
+
pgconn_get_last_result( self );
|
2991
|
+
|
2992
|
+
pgconn_send_query( argc, argv, self );
|
2993
|
+
pgconn_block( 0, NULL, self );
|
2994
|
+
rb_pgresult = pgconn_get_last_result( self );
|
2995
|
+
|
2996
|
+
if ( rb_block_given_p() ) {
|
2997
|
+
return rb_ensure( rb_yield, rb_pgresult, pg_result_clear, rb_pgresult );
|
2998
|
+
}
|
2999
|
+
return rb_pgresult;
|
3000
|
+
}
|
3001
|
+
|
3002
|
+
#endif
|
3003
|
+
|
3004
|
+
/**************************************************************************
|
3005
|
+
* LARGE OBJECT SUPPORT
|
3006
|
+
**************************************************************************/
|
3007
|
+
|
3008
|
+
/*
|
3009
|
+
* call-seq:
|
3010
|
+
* conn.lo_creat( [mode] ) -> Fixnum
|
3011
|
+
*
|
3012
|
+
* Creates a large object with mode _mode_. Returns a large object Oid.
|
3013
|
+
* On failure, it raises PG::Error.
|
3014
|
+
*/
|
3015
|
+
static VALUE
|
3016
|
+
pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
3017
|
+
{
|
3018
|
+
Oid lo_oid;
|
3019
|
+
int mode;
|
3020
|
+
VALUE nmode;
|
3021
|
+
PGconn *conn = pg_get_pgconn(self);
|
3022
|
+
|
3023
|
+
if (rb_scan_args(argc, argv, "01", &nmode) == 0)
|
3024
|
+
mode = INV_READ;
|
3025
|
+
else
|
3026
|
+
mode = NUM2INT(nmode);
|
3027
|
+
|
3028
|
+
lo_oid = lo_creat(conn, mode);
|
3029
|
+
if (lo_oid == 0)
|
3030
|
+
rb_raise(rb_ePGerror, "lo_creat failed");
|
3031
|
+
|
3032
|
+
return INT2FIX(lo_oid);
|
3033
|
+
}
|
3034
|
+
|
3035
|
+
/*
|
3036
|
+
* call-seq:
|
3037
|
+
* conn.lo_create( oid ) -> Fixnum
|
3038
|
+
*
|
3039
|
+
* Creates a large object with oid _oid_. Returns the large object Oid.
|
3040
|
+
* On failure, it raises PG::Error.
|
3041
|
+
*/
|
3042
|
+
static VALUE
|
3043
|
+
pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
3044
|
+
{
|
3045
|
+
Oid ret, lo_oid;
|
3046
|
+
PGconn *conn = pg_get_pgconn(self);
|
3047
|
+
lo_oid = NUM2INT(in_lo_oid);
|
3048
|
+
|
3049
|
+
ret = lo_create(conn, lo_oid);
|
3050
|
+
if (ret == InvalidOid)
|
3051
|
+
rb_raise(rb_ePGerror, "lo_create failed");
|
3052
|
+
|
3053
|
+
return INT2FIX(ret);
|
3054
|
+
}
|
3055
|
+
|
3056
|
+
/*
|
3057
|
+
* call-seq:
|
3058
|
+
* conn.lo_import(file) -> Fixnum
|
3059
|
+
*
|
3060
|
+
* Import a file to a large object. Returns a large object Oid.
|
3061
|
+
*
|
3062
|
+
* On failure, it raises a PG::Error.
|
3063
|
+
*/
|
3064
|
+
static VALUE
|
3065
|
+
pgconn_loimport(VALUE self, VALUE filename)
|
3066
|
+
{
|
3067
|
+
Oid lo_oid;
|
3068
|
+
|
3069
|
+
PGconn *conn = pg_get_pgconn(self);
|
3070
|
+
|
3071
|
+
Check_Type(filename, T_STRING);
|
3072
|
+
|
3073
|
+
lo_oid = lo_import(conn, StringValuePtr(filename));
|
3074
|
+
if (lo_oid == 0) {
|
3075
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3076
|
+
}
|
3077
|
+
return INT2FIX(lo_oid);
|
3078
|
+
}
|
3079
|
+
|
3080
|
+
/*
|
3081
|
+
* call-seq:
|
3082
|
+
* conn.lo_export( oid, file ) -> nil
|
3083
|
+
*
|
3084
|
+
* Saves a large object of _oid_ to a _file_.
|
3085
|
+
*/
|
3086
|
+
static VALUE
|
3087
|
+
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
3088
|
+
{
|
3089
|
+
PGconn *conn = pg_get_pgconn(self);
|
3090
|
+
int oid;
|
3091
|
+
Check_Type(filename, T_STRING);
|
3092
|
+
|
3093
|
+
oid = NUM2INT(lo_oid);
|
3094
|
+
if (oid < 0) {
|
3095
|
+
rb_raise(rb_ePGerror, "invalid large object oid %d",oid);
|
3096
|
+
}
|
3097
|
+
|
3098
|
+
if (lo_export(conn, oid, StringValuePtr(filename)) < 0) {
|
3099
|
+
rb_raise(rb_ePGerror, "%s", PQerrorMessage(conn));
|
3100
|
+
}
|
3101
|
+
return Qnil;
|
3102
|
+
}
|
3103
|
+
|
3104
|
+
/*
|
3105
|
+
* call-seq:
|
3106
|
+
* conn.lo_open( oid, [mode] ) -> Fixnum
|
3107
|
+
*
|
3108
|
+
* Open a large object of _oid_. Returns a large object descriptor
|
3109
|
+
* instance on success. The _mode_ argument specifies the mode for
|
3110
|
+
* the opened large object,which is either +INV_READ+, or +INV_WRITE+.
|
3111
|
+
*
|
3112
|
+
* If _mode_ is omitted, the default is +INV_READ+.
|
3113
|
+
*/
|
3114
|
+
static VALUE
|
3115
|
+
pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
3116
|
+
{
|
3117
|
+
Oid lo_oid;
|
3118
|
+
int fd, mode;
|
3119
|
+
VALUE nmode, selfid;
|
3120
|
+
PGconn *conn = pg_get_pgconn(self);
|
3121
|
+
|
3122
|
+
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
3123
|
+
lo_oid = NUM2INT(selfid);
|
3124
|
+
if(NIL_P(nmode))
|
3125
|
+
mode = INV_READ;
|
3126
|
+
else
|
3127
|
+
mode = NUM2INT(nmode);
|
3128
|
+
|
3129
|
+
if((fd = lo_open(conn, lo_oid, mode)) < 0) {
|
3130
|
+
rb_raise(rb_ePGerror, "can't open large object: %s", PQerrorMessage(conn));
|
3131
|
+
}
|
3132
|
+
return INT2FIX(fd);
|
3133
|
+
}
|
3134
|
+
|
3135
|
+
/*
|
3136
|
+
* call-seq:
|
3137
|
+
* conn.lo_write( lo_desc, buffer ) -> Fixnum
|
3138
|
+
*
|
3139
|
+
* Writes the string _buffer_ to the large object _lo_desc_.
|
3140
|
+
* Returns the number of bytes written.
|
3141
|
+
*/
|
3142
|
+
static VALUE
|
3143
|
+
pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
3144
|
+
{
|
3145
|
+
int n;
|
3146
|
+
PGconn *conn = pg_get_pgconn(self);
|
3147
|
+
int fd = NUM2INT(in_lo_desc);
|
3148
|
+
|
3149
|
+
Check_Type(buffer, T_STRING);
|
3150
|
+
|
3151
|
+
if( RSTRING_LEN(buffer) < 0) {
|
3152
|
+
rb_raise(rb_ePGerror, "write buffer zero string");
|
3153
|
+
}
|
3154
|
+
if((n = lo_write(conn, fd, StringValuePtr(buffer),
|
3155
|
+
RSTRING_LEN(buffer))) < 0) {
|
3156
|
+
rb_raise(rb_ePGerror, "lo_write failed: %s", PQerrorMessage(conn));
|
3157
|
+
}
|
3158
|
+
|
3159
|
+
return INT2FIX(n);
|
3160
|
+
}
|
3161
|
+
|
3162
|
+
/*
|
3163
|
+
* call-seq:
|
3164
|
+
* conn.lo_read( lo_desc, len ) -> String
|
3165
|
+
*
|
3166
|
+
* Attempts to read _len_ bytes from large object _lo_desc_,
|
3167
|
+
* returns resulting data.
|
3168
|
+
*/
|
3169
|
+
static VALUE
|
3170
|
+
pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
3171
|
+
{
|
3172
|
+
int ret;
|
3173
|
+
PGconn *conn = pg_get_pgconn(self);
|
3174
|
+
int len = NUM2INT(in_len);
|
3175
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
3176
|
+
VALUE str;
|
3177
|
+
char *buffer;
|
3178
|
+
|
3179
|
+
buffer = ALLOC_N(char, len);
|
3180
|
+
if(buffer == NULL)
|
3181
|
+
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
3182
|
+
|
3183
|
+
if (len < 0){
|
3184
|
+
rb_raise(rb_ePGerror,"nagative length %d given", len);
|
3185
|
+
}
|
3186
|
+
|
3187
|
+
if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
|
3188
|
+
rb_raise(rb_ePGerror, "lo_read failed");
|
3189
|
+
|
3190
|
+
if(ret == 0) {
|
3191
|
+
xfree(buffer);
|
3192
|
+
return Qnil;
|
3193
|
+
}
|
3194
|
+
|
3195
|
+
str = rb_tainted_str_new(buffer, ret);
|
3196
|
+
xfree(buffer);
|
3197
|
+
|
3198
|
+
return str;
|
3199
|
+
}
|
3200
|
+
|
3201
|
+
|
3202
|
+
/*
|
3203
|
+
* call-seq:
|
3204
|
+
* conn.lo_lseek( lo_desc, offset, whence ) -> Fixnum
|
3205
|
+
*
|
3206
|
+
* Move the large object pointer _lo_desc_ to offset _offset_.
|
3207
|
+
* Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
|
3208
|
+
* (Or 0, 1, or 2.)
|
3209
|
+
*/
|
3210
|
+
static VALUE
|
3211
|
+
pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
3212
|
+
{
|
3213
|
+
PGconn *conn = pg_get_pgconn(self);
|
3214
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
3215
|
+
int ret;
|
3216
|
+
|
3217
|
+
if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
|
3218
|
+
rb_raise(rb_ePGerror, "lo_lseek failed");
|
3219
|
+
}
|
3220
|
+
|
3221
|
+
return INT2FIX(ret);
|
3222
|
+
}
|
3223
|
+
|
3224
|
+
/*
|
3225
|
+
* call-seq:
|
3226
|
+
* conn.lo_tell( lo_desc ) -> Fixnum
|
3227
|
+
*
|
3228
|
+
* Returns the current position of the large object _lo_desc_.
|
3229
|
+
*/
|
3230
|
+
static VALUE
|
3231
|
+
pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
3232
|
+
{
|
3233
|
+
int position;
|
3234
|
+
PGconn *conn = pg_get_pgconn(self);
|
3235
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
3236
|
+
|
3237
|
+
if((position = lo_tell(conn, lo_desc)) < 0)
|
3238
|
+
rb_raise(rb_ePGerror,"lo_tell failed");
|
3239
|
+
|
3240
|
+
return INT2FIX(position);
|
3241
|
+
}
|
3242
|
+
|
3243
|
+
/*
|
3244
|
+
* call-seq:
|
3245
|
+
* conn.lo_truncate( lo_desc, len ) -> nil
|
3246
|
+
*
|
3247
|
+
* Truncates the large object _lo_desc_ to size _len_.
|
3248
|
+
*/
|
3249
|
+
static VALUE
|
3250
|
+
pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
3251
|
+
{
|
3252
|
+
PGconn *conn = pg_get_pgconn(self);
|
3253
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
3254
|
+
size_t len = NUM2INT(in_len);
|
3255
|
+
|
3256
|
+
if(lo_truncate(conn,lo_desc,len) < 0)
|
3257
|
+
rb_raise(rb_ePGerror,"lo_truncate failed");
|
3258
|
+
|
3259
|
+
return Qnil;
|
3260
|
+
}
|
3261
|
+
|
3262
|
+
/*
|
3263
|
+
* call-seq:
|
3264
|
+
* conn.lo_close( lo_desc ) -> nil
|
3265
|
+
*
|
3266
|
+
* Closes the postgres large object of _lo_desc_.
|
3267
|
+
*/
|
3268
|
+
static VALUE
|
3269
|
+
pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
3270
|
+
{
|
3271
|
+
PGconn *conn = pg_get_pgconn(self);
|
3272
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
3273
|
+
|
3274
|
+
if(lo_close(conn,lo_desc) < 0)
|
3275
|
+
rb_raise(rb_ePGerror,"lo_close failed");
|
3276
|
+
|
3277
|
+
return Qnil;
|
3278
|
+
}
|
3279
|
+
|
3280
|
+
/*
|
3281
|
+
* call-seq:
|
3282
|
+
* conn.lo_unlink( oid ) -> nil
|
3283
|
+
*
|
3284
|
+
* Unlinks (deletes) the postgres large object of _oid_.
|
3285
|
+
*/
|
3286
|
+
static VALUE
|
3287
|
+
pgconn_lounlink(VALUE self, VALUE in_oid)
|
3288
|
+
{
|
3289
|
+
PGconn *conn = pg_get_pgconn(self);
|
3290
|
+
int oid = NUM2INT(in_oid);
|
3291
|
+
|
3292
|
+
if (oid < 0)
|
3293
|
+
rb_raise(rb_ePGerror, "invalid oid %d",oid);
|
3294
|
+
|
3295
|
+
if(lo_unlink(conn,oid) < 0)
|
3296
|
+
rb_raise(rb_ePGerror,"lo_unlink failed");
|
3297
|
+
|
3298
|
+
return Qnil;
|
3299
|
+
}
|
3300
|
+
|
3301
|
+
|
3302
|
+
#ifdef M17N_SUPPORTED
|
3303
|
+
|
3304
|
+
/*
|
3305
|
+
* call-seq:
|
3306
|
+
* conn.internal_encoding -> Encoding
|
3307
|
+
*
|
3308
|
+
* defined in Ruby 1.9 or later.
|
3309
|
+
*
|
3310
|
+
* Returns:
|
3311
|
+
* * an Encoding - client_encoding of the connection as a Ruby Encoding object.
|
3312
|
+
* * nil - the client_encoding is 'SQL_ASCII'
|
3313
|
+
*/
|
3314
|
+
static VALUE
|
3315
|
+
pgconn_internal_encoding(VALUE self)
|
3316
|
+
{
|
3317
|
+
PGconn *conn = pg_get_pgconn( self );
|
3318
|
+
rb_encoding *enc = pg_conn_enc_get( conn );
|
3319
|
+
|
3320
|
+
if ( enc ) {
|
3321
|
+
return rb_enc_from_encoding( enc );
|
3322
|
+
} else {
|
3323
|
+
return Qnil;
|
3324
|
+
}
|
3325
|
+
}
|
3326
|
+
|
3327
|
+
static VALUE pgconn_external_encoding(VALUE self);
|
3328
|
+
|
3329
|
+
/*
|
3330
|
+
* call-seq:
|
3331
|
+
* conn.internal_encoding = value
|
3332
|
+
*
|
3333
|
+
* A wrapper of #set_client_encoding.
|
3334
|
+
* defined in Ruby 1.9 or later.
|
3335
|
+
*
|
3336
|
+
* +value+ can be one of:
|
3337
|
+
* * an Encoding
|
3338
|
+
* * a String - a name of Encoding
|
3339
|
+
* * +nil+ - sets the client_encoding to SQL_ASCII.
|
3340
|
+
*/
|
3341
|
+
static VALUE
|
3342
|
+
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3343
|
+
{
|
3344
|
+
if (NIL_P(enc)) {
|
3345
|
+
pgconn_set_client_encoding( self, rb_usascii_str_new_cstr("SQL_ASCII") );
|
3346
|
+
return enc;
|
3347
|
+
}
|
3348
|
+
else if ( TYPE(enc) == T_STRING && strcasecmp("JOHAB", RSTRING_PTR(enc)) == 0 ) {
|
3349
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3350
|
+
return enc;
|
3351
|
+
}
|
3352
|
+
else {
|
3353
|
+
rb_encoding *rbenc = rb_to_encoding( enc );
|
3354
|
+
const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
|
3355
|
+
|
3356
|
+
if ( PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
|
3357
|
+
VALUE server_encoding = pgconn_external_encoding( self );
|
3358
|
+
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3359
|
+
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
3360
|
+
}
|
3361
|
+
return enc;
|
3362
|
+
}
|
3363
|
+
|
3364
|
+
rb_raise( rb_ePGerror, "unknown encoding: %s", RSTRING_PTR(rb_inspect(enc)) );
|
3365
|
+
|
3366
|
+
return Qnil;
|
3367
|
+
}
|
3368
|
+
|
3369
|
+
|
3370
|
+
|
3371
|
+
/*
|
3372
|
+
* call-seq:
|
3373
|
+
* conn.external_encoding() -> Encoding
|
3374
|
+
*
|
3375
|
+
* Return the +server_encoding+ of the connected database as a Ruby Encoding object.
|
3376
|
+
* The <tt>SQL_ASCII</tt> encoding is mapped to to <tt>ASCII_8BIT</tt>.
|
3377
|
+
*/
|
3378
|
+
static VALUE
|
3379
|
+
pgconn_external_encoding(VALUE self)
|
3380
|
+
{
|
3381
|
+
PGconn *conn = pg_get_pgconn( self );
|
3382
|
+
VALUE encoding = rb_iv_get( self, "@external_encoding" );
|
3383
|
+
rb_encoding *enc = NULL;
|
3384
|
+
const char *pg_encname = NULL;
|
3385
|
+
|
3386
|
+
/* Use cached value if found */
|
3387
|
+
if ( RTEST(encoding) ) return encoding;
|
3388
|
+
|
3389
|
+
pg_encname = PQparameterStatus( conn, "server_encoding" );
|
3390
|
+
enc = pg_get_pg_encname_as_rb_encoding( pg_encname );
|
3391
|
+
encoding = rb_enc_from_encoding( enc );
|
3392
|
+
|
3393
|
+
rb_iv_set( self, "@external_encoding", encoding );
|
3394
|
+
|
3395
|
+
return encoding;
|
3396
|
+
}
|
3397
|
+
|
3398
|
+
|
3399
|
+
|
3400
|
+
/*
|
3401
|
+
* call-seq:
|
3402
|
+
* conn.set_default_encoding() -> Encoding
|
3403
|
+
*
|
3404
|
+
* If Ruby has its Encoding.default_internal set, set PostgreSQL's client_encoding
|
3405
|
+
* to match. Returns the new Encoding, or +nil+ if the default internal encoding
|
3406
|
+
* wasn't set.
|
3407
|
+
*/
|
3408
|
+
static VALUE
|
3409
|
+
pgconn_set_default_encoding( VALUE self )
|
3410
|
+
{
|
3411
|
+
PGconn *conn = pg_get_pgconn( self );
|
3412
|
+
rb_encoding *enc;
|
3413
|
+
const char *encname;
|
3414
|
+
|
3415
|
+
if (( enc = rb_default_internal_encoding() )) {
|
3416
|
+
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3417
|
+
if ( PQsetClientEncoding(conn, encname) != 0 )
|
3418
|
+
rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
|
3419
|
+
encname, PQerrorMessage(conn) );
|
3420
|
+
return rb_enc_from_encoding( enc );
|
3421
|
+
} else {
|
3422
|
+
return Qnil;
|
3423
|
+
}
|
3424
|
+
}
|
3425
|
+
|
3426
|
+
|
3427
|
+
#endif /* M17N_SUPPORTED */
|
3428
|
+
|
3429
|
+
|
3430
|
+
|
3431
|
+
void
|
3432
|
+
init_pg_connection()
|
3433
|
+
{
|
3434
|
+
rb_cPGconn = rb_define_class_under( rb_mPG, "Connection", rb_cObject );
|
3435
|
+
rb_include_module(rb_cPGconn, rb_mPGconstants);
|
3436
|
+
|
3437
|
+
/****** PG::Connection CLASS METHODS ******/
|
3438
|
+
rb_define_alloc_func( rb_cPGconn, pgconn_s_allocate );
|
3439
|
+
|
3440
|
+
SINGLETON_ALIAS(rb_cPGconn, "connect", "new");
|
3441
|
+
SINGLETON_ALIAS(rb_cPGconn, "open", "new");
|
3442
|
+
SINGLETON_ALIAS(rb_cPGconn, "setdb", "new");
|
3443
|
+
SINGLETON_ALIAS(rb_cPGconn, "setdblogin", "new");
|
3444
|
+
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3445
|
+
SINGLETON_ALIAS(rb_cPGconn, "escape", "escape_string");
|
3446
|
+
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3447
|
+
rb_define_singleton_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3448
|
+
rb_define_singleton_method(rb_cPGconn, "encrypt_password", pgconn_s_encrypt_password, 2);
|
3449
|
+
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3450
|
+
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3451
|
+
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3452
|
+
#ifdef HAVE_PQPING
|
3453
|
+
rb_define_singleton_method(rb_cPGconn, "ping", pgconn_s_ping, -1);
|
3454
|
+
#endif
|
3455
|
+
|
3456
|
+
/****** PG::Connection INSTANCE METHODS: Connection Control ******/
|
3457
|
+
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
3458
|
+
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
3459
|
+
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
3460
|
+
rb_define_method(rb_cPGconn, "finished?", pgconn_finished_p, 0);
|
3461
|
+
rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
|
3462
|
+
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
3463
|
+
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
3464
|
+
rb_define_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3465
|
+
rb_define_alias(rb_cPGconn, "close", "finish");
|
3466
|
+
|
3467
|
+
/****** PG::Connection INSTANCE METHODS: Connection Status ******/
|
3468
|
+
rb_define_method(rb_cPGconn, "db", pgconn_db, 0);
|
3469
|
+
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
3470
|
+
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
3471
|
+
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3472
|
+
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3473
|
+
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3474
|
+
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
3475
|
+
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
3476
|
+
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
3477
|
+
rb_define_method(rb_cPGconn, "parameter_status", pgconn_parameter_status, 1);
|
3478
|
+
rb_define_method(rb_cPGconn, "protocol_version", pgconn_protocol_version, 0);
|
3479
|
+
rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
|
3480
|
+
rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
|
3481
|
+
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
3482
|
+
#if !defined(_WIN32) || defined(HAVE_RB_W32_WRAP_IO_HANDLE)
|
3483
|
+
rb_define_method(rb_cPGconn, "socket_io", pgconn_socket_io, 0);
|
3484
|
+
#endif
|
3485
|
+
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
3486
|
+
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
3487
|
+
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
3488
|
+
/* rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0); */
|
3489
|
+
|
3490
|
+
/****** PG::Connection INSTANCE METHODS: Command Execution ******/
|
3491
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_exec, -1);
|
3492
|
+
rb_define_alias(rb_cPGconn, "query", "exec");
|
3493
|
+
rb_define_method(rb_cPGconn, "exec_params", pgconn_exec_params, -1);
|
3494
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_prepare, -1);
|
3495
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_exec_prepared, -1);
|
3496
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_describe_prepared, 1);
|
3497
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_describe_portal, 1);
|
3498
|
+
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
3499
|
+
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3500
|
+
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
3501
|
+
#ifdef HAVE_PQESCAPELITERAL
|
3502
|
+
rb_define_method(rb_cPGconn, "escape_literal", pgconn_escape_literal, 1);
|
3503
|
+
#endif
|
3504
|
+
#ifdef HAVE_PQESCAPEIDENTIFIER
|
3505
|
+
rb_define_method(rb_cPGconn, "escape_identifier", pgconn_escape_identifier, 1);
|
3506
|
+
#endif
|
3507
|
+
rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3508
|
+
rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3509
|
+
#ifdef HAVE_PQSETSINGLEROWMODE
|
3510
|
+
rb_define_method(rb_cPGconn, "set_single_row_mode", pgconn_set_single_row_mode, 0);
|
3511
|
+
#endif
|
3512
|
+
|
3513
|
+
/****** PG::Connection INSTANCE METHODS: Asynchronous Command Processing ******/
|
3514
|
+
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
3515
|
+
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
3516
|
+
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
3517
|
+
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
3518
|
+
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
3519
|
+
rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
|
3520
|
+
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
3521
|
+
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
3522
|
+
rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
|
3523
|
+
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
3524
|
+
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
3525
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
|
3526
|
+
|
3527
|
+
/****** PG::Connection INSTANCE METHODS: Cancelling Queries in Progress ******/
|
3528
|
+
rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
|
3529
|
+
|
3530
|
+
/****** PG::Connection INSTANCE METHODS: NOTIFY ******/
|
3531
|
+
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
3532
|
+
|
3533
|
+
/****** PG::Connection INSTANCE METHODS: COPY ******/
|
3534
|
+
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, 1);
|
3535
|
+
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
3536
|
+
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
3537
|
+
|
3538
|
+
/****** PG::Connection INSTANCE METHODS: Control Functions ******/
|
3539
|
+
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
3540
|
+
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
3541
|
+
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
3542
|
+
|
3543
|
+
/****** PG::Connection INSTANCE METHODS: Notice Processing ******/
|
3544
|
+
rb_define_method(rb_cPGconn, "set_notice_receiver", pgconn_set_notice_receiver, 0);
|
3545
|
+
rb_define_method(rb_cPGconn, "set_notice_processor", pgconn_set_notice_processor, 0);
|
3546
|
+
|
3547
|
+
/****** PG::Connection INSTANCE METHODS: Other ******/
|
3548
|
+
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
3549
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
|
3550
|
+
rb_define_alias(rb_cPGconn, "client_encoding=", "set_client_encoding");
|
3551
|
+
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
3552
|
+
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
3553
|
+
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
3554
|
+
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
3555
|
+
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3556
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
3557
|
+
rb_define_alias(rb_cPGconn, "async_exec", "exec");
|
3558
|
+
#else
|
3559
|
+
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
3560
|
+
#endif
|
3561
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
3562
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
|
3563
|
+
|
3564
|
+
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
3565
|
+
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
3566
|
+
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
3567
|
+
rb_define_method(rb_cPGconn, "lo_create", pgconn_locreate, 1);
|
3568
|
+
rb_define_alias(rb_cPGconn, "locreate", "lo_create");
|
3569
|
+
rb_define_method(rb_cPGconn, "lo_import", pgconn_loimport, 1);
|
3570
|
+
rb_define_alias(rb_cPGconn, "loimport", "lo_import");
|
3571
|
+
rb_define_method(rb_cPGconn, "lo_export", pgconn_loexport, 2);
|
3572
|
+
rb_define_alias(rb_cPGconn, "loexport", "lo_export");
|
3573
|
+
rb_define_method(rb_cPGconn, "lo_open", pgconn_loopen, -1);
|
3574
|
+
rb_define_alias(rb_cPGconn, "loopen", "lo_open");
|
3575
|
+
rb_define_method(rb_cPGconn, "lo_write",pgconn_lowrite, 2);
|
3576
|
+
rb_define_alias(rb_cPGconn, "lowrite", "lo_write");
|
3577
|
+
rb_define_method(rb_cPGconn, "lo_read",pgconn_loread, 2);
|
3578
|
+
rb_define_alias(rb_cPGconn, "loread", "lo_read");
|
3579
|
+
rb_define_method(rb_cPGconn, "lo_lseek",pgconn_lolseek, 3);
|
3580
|
+
rb_define_alias(rb_cPGconn, "lolseek", "lo_lseek");
|
3581
|
+
rb_define_alias(rb_cPGconn, "lo_seek", "lo_lseek");
|
3582
|
+
rb_define_alias(rb_cPGconn, "loseek", "lo_lseek");
|
3583
|
+
rb_define_method(rb_cPGconn, "lo_tell",pgconn_lotell, 1);
|
3584
|
+
rb_define_alias(rb_cPGconn, "lotell", "lo_tell");
|
3585
|
+
rb_define_method(rb_cPGconn, "lo_truncate", pgconn_lotruncate, 2);
|
3586
|
+
rb_define_alias(rb_cPGconn, "lotruncate", "lo_truncate");
|
3587
|
+
rb_define_method(rb_cPGconn, "lo_close",pgconn_loclose, 1);
|
3588
|
+
rb_define_alias(rb_cPGconn, "loclose", "lo_close");
|
3589
|
+
rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
|
3590
|
+
rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
|
3591
|
+
|
3592
|
+
#ifdef M17N_SUPPORTED
|
3593
|
+
rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
|
3594
|
+
rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
|
3595
|
+
rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
|
3596
|
+
rb_define_method(rb_cPGconn, "set_default_encoding", pgconn_set_default_encoding, 0);
|
3597
|
+
#endif /* M17N_SUPPORTED */
|
3598
|
+
|
3599
|
+
}
|
3600
|
+
|