pg 0.9.0.pre156-x86-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/BSD +23 -0
- data/ChangeLog +471 -0
- data/Contributors +30 -0
- data/GPL +340 -0
- data/LICENSE +58 -0
- data/README +68 -0
- data/README.OS_X +19 -0
- data/README.ja +183 -0
- data/README.windows +72 -0
- data/Rakefile.local +239 -0
- data/ext/compat.c +541 -0
- data/ext/compat.h +180 -0
- data/ext/extconf.rb +126 -0
- data/ext/pg.c +4250 -0
- data/ext/pg.h +49 -0
- data/lib/1.8/pg_ext.so +0 -0
- data/lib/1.9/pg_ext.so +0 -0
- data/lib/pg.rb +11 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/helpers.rb +435 -0
- data/rake/hg.rb +273 -0
- data/rake/manual.rb +782 -0
- data/rake/packaging.rb +123 -0
- data/rake/publishing.rb +274 -0
- data/rake/rdoc.rb +30 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/lib/helpers.rb +216 -0
- data/spec/m17n_spec.rb +139 -0
- data/spec/pgconn_spec.rb +291 -0
- data/spec/pgresult_spec.rb +218 -0
- metadata +113 -0
data/ext/compat.h
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
|
2
|
+
#ifndef __compat_h
|
3
|
+
#define __compat_h
|
4
|
+
|
5
|
+
#include <stdlib.h>
|
6
|
+
|
7
|
+
#include "libpq-fe.h"
|
8
|
+
#include "libpq/libpq-fs.h" /* large-object interface */
|
9
|
+
|
10
|
+
#include "ruby.h"
|
11
|
+
|
12
|
+
/* pg_config.h does not exist in older versions of
|
13
|
+
* PostgreSQL, so I can't effectively use PG_VERSION_NUM
|
14
|
+
* Instead, I create some #defines to help organization.
|
15
|
+
*/
|
16
|
+
#ifndef HAVE_PQCONNECTIONUSEDPASSWORD
|
17
|
+
#define PG_BEFORE_080300
|
18
|
+
#endif
|
19
|
+
|
20
|
+
#ifndef HAVE_PQISTHREADSAFE
|
21
|
+
#define PG_BEFORE_080200
|
22
|
+
#endif
|
23
|
+
|
24
|
+
#ifndef HAVE_LO_CREATE
|
25
|
+
#define PG_BEFORE_080100
|
26
|
+
#endif
|
27
|
+
|
28
|
+
#ifndef HAVE_PQPREPARE
|
29
|
+
#define PG_BEFORE_080000
|
30
|
+
#endif
|
31
|
+
|
32
|
+
#ifndef HAVE_PQEXECPARAMS
|
33
|
+
#define PG_BEFORE_070400
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#ifndef HAVE_PQESCAPESTRINGCONN
|
37
|
+
#define PG_BEFORE_070300
|
38
|
+
#error PostgreSQL client version too old, requires 7.3 or later.
|
39
|
+
#endif
|
40
|
+
|
41
|
+
/* This is necessary because NAMEDATALEN is defined in
|
42
|
+
* pg_config_manual.h in 8.3, and that include file doesn't
|
43
|
+
* exist before 7.4
|
44
|
+
*/
|
45
|
+
#ifndef PG_BEFORE_070400
|
46
|
+
#include "pg_config_manual.h"
|
47
|
+
#endif
|
48
|
+
|
49
|
+
#ifndef PG_DIAG_INTERNAL_POSITION
|
50
|
+
#define PG_DIAG_INTERNAL_POSITION 'p'
|
51
|
+
#endif /* PG_DIAG_INTERNAL_POSITION */
|
52
|
+
|
53
|
+
#ifndef PG_DIAG_INTERNAL_QUERY
|
54
|
+
#define PG_DIAG_INTERNAL_QUERY 'q'
|
55
|
+
#endif /* PG_DIAG_INTERNAL_QUERY */
|
56
|
+
|
57
|
+
#ifdef PG_BEFORE_080300
|
58
|
+
|
59
|
+
#ifndef HAVE_PG_ENCODING_TO_CHAR
|
60
|
+
#define pg_encoding_to_char(x) "SQL_ASCII"
|
61
|
+
#else
|
62
|
+
/* Some versions ofPostgreSQL prior to 8.3 define pg_encoding_to_char
|
63
|
+
* but do not declare it in a header file, so this declaration will
|
64
|
+
* eliminate an unecessary warning
|
65
|
+
*/
|
66
|
+
extern char* pg_encoding_to_char(int);
|
67
|
+
#endif /* HAVE_PG_ENCODING_TO_CHAR */
|
68
|
+
|
69
|
+
int PQconnectionNeedsPassword(PGconn *conn);
|
70
|
+
int PQconnectionUsedPassword(PGconn *conn);
|
71
|
+
int lo_truncate(PGconn *conn, int fd, size_t len);
|
72
|
+
|
73
|
+
#endif /* PG_BEFORE_080300 */
|
74
|
+
|
75
|
+
#ifdef PG_BEFORE_080200
|
76
|
+
int PQisthreadsafe(void);
|
77
|
+
int PQnparams(const PGresult *res);
|
78
|
+
Oid PQparamtype(const PGresult *res, int param_number);
|
79
|
+
PGresult * PQdescribePrepared(PGconn *conn, const char *stmtName);
|
80
|
+
PGresult * PQdescribePortal(PGconn *conn, const char *portalName);
|
81
|
+
int PQsendDescribePrepared(PGconn *conn, const char *stmtName);
|
82
|
+
int PQsendDescribePortal(PGconn *conn, const char *portalName);
|
83
|
+
char *PQencryptPassword(const char *passwd, const char *user);
|
84
|
+
#endif /* PG_BEFORE_080200 */
|
85
|
+
|
86
|
+
#ifdef PG_BEFORE_080100
|
87
|
+
Oid lo_create(PGconn *conn, Oid lobjId);
|
88
|
+
#endif /* PG_BEFORE_080100 */
|
89
|
+
|
90
|
+
#ifdef PG_BEFORE_080000
|
91
|
+
PGresult *PQprepare(PGconn *conn, const char *stmtName, const char *query,
|
92
|
+
int nParams, const Oid *paramTypes);
|
93
|
+
int PQsendPrepare(PGconn *conn, const char *stmtName, const char *query,
|
94
|
+
int nParams, const Oid *paramTypes);
|
95
|
+
int PQserverVersion(const PGconn* conn);
|
96
|
+
#endif /* PG_BEFORE_080000 */
|
97
|
+
|
98
|
+
#ifdef PG_BEFORE_070400
|
99
|
+
|
100
|
+
#define PG_DIAG_SEVERITY 'S'
|
101
|
+
#define PG_DIAG_SQLSTATE 'C'
|
102
|
+
#define PG_DIAG_MESSAGE_PRIMARY 'M'
|
103
|
+
#define PG_DIAG_MESSAGE_DETAIL 'D'
|
104
|
+
#define PG_DIAG_MESSAGE_HINT 'H'
|
105
|
+
#define PG_DIAG_STATEMENT_POSITION 'P'
|
106
|
+
#define PG_DIAG_CONTEXT 'W'
|
107
|
+
#define PG_DIAG_SOURCE_FILE 'F'
|
108
|
+
#define PG_DIAG_SOURCE_LINE 'L'
|
109
|
+
#define PG_DIAG_SOURCE_FUNCTION 'R'
|
110
|
+
|
111
|
+
#define PQfreemem(ptr) free(ptr)
|
112
|
+
#define PGNOTIFY_EXTRA(notify) ""
|
113
|
+
|
114
|
+
/* CONNECTION_SSL_STARTUP was added to an enum type
|
115
|
+
* after 7.3. For 7.3 in order to compile, we just need
|
116
|
+
* it to evaluate to something that is not present in that
|
117
|
+
* enum.
|
118
|
+
*/
|
119
|
+
#define CONNECTION_SSL_STARTUP 1000000
|
120
|
+
|
121
|
+
typedef void (*PQnoticeReceiver) (void *arg, const PGresult *res);
|
122
|
+
|
123
|
+
typedef enum
|
124
|
+
{
|
125
|
+
PQERRORS_TERSE, /* single-line error messages */
|
126
|
+
PQERRORS_DEFAULT, /* recommended style */
|
127
|
+
PQERRORS_VERBOSE /* all the facts, ma'am */
|
128
|
+
} PGVerbosity;
|
129
|
+
|
130
|
+
typedef enum
|
131
|
+
{
|
132
|
+
PQTRANS_IDLE, /* connection idle */
|
133
|
+
PQTRANS_ACTIVE, /* command in progress */
|
134
|
+
PQTRANS_INTRANS, /* idle, within transaction block */
|
135
|
+
PQTRANS_INERROR, /* idle, within failed transaction */
|
136
|
+
PQTRANS_UNKNOWN /* cannot determine status */
|
137
|
+
} PGTransactionStatusType;
|
138
|
+
|
139
|
+
PGresult *PQexecParams(PGconn *conn, const char *command, int nParams,
|
140
|
+
const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
|
141
|
+
const int *paramFormats, int resultFormat);
|
142
|
+
PGTransactionStatusType PQtransactionStatus(const PGconn *conn);
|
143
|
+
char *PQparameterStatus(const PGconn *conn, const char *paramName);
|
144
|
+
int PQprotocolVersion(const PGconn *conn);
|
145
|
+
PGresult *PQexecPrepared(PGconn *conn, const char *stmtName, int nParams,
|
146
|
+
const char * const *ParamValues, const int *paramLengths, const int *paramFormats,
|
147
|
+
int resultFormat);
|
148
|
+
int PQsendQueryParams(PGconn *conn, const char *command, int nParams,
|
149
|
+
const Oid *paramTypes, const char * const * paramValues, const int *paramLengths,
|
150
|
+
const int *paramFormats, int resultFormat);
|
151
|
+
int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams,
|
152
|
+
const char * const *ParamValues, const int *paramLengths, const int *paramFormats,
|
153
|
+
int resultFormat);
|
154
|
+
int PQputCopyData(PGconn *conn, const char *buffer, int nbytes);
|
155
|
+
int PQputCopyEnd(PGconn *conn, const char *errormsg);
|
156
|
+
int PQgetCopyData(PGconn *conn, char **buffer, int async);
|
157
|
+
PGVerbosity PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity);
|
158
|
+
Oid PQftable(const PGresult *res, int column_number);
|
159
|
+
int PQftablecol(const PGresult *res, int column_number);
|
160
|
+
int PQfformat(const PGresult *res, int column_number);
|
161
|
+
char *PQresultErrorField(const PGresult *res, int fieldcode);
|
162
|
+
PQnoticeReceiver PQsetNoticeReceiver(PGconn *conn, PQnoticeReceiver proc, void *arg);
|
163
|
+
|
164
|
+
#else
|
165
|
+
#define PGNOTIFY_EXTRA(notify) ((notify)->extra)
|
166
|
+
#endif /* PG_BEFORE_070400 */
|
167
|
+
|
168
|
+
#ifdef PG_BEFORE_070300
|
169
|
+
#error unsupported postgresql version, requires 7.3 or later.
|
170
|
+
int PQsetClientEncoding(PGconn *conn, const char *encoding)
|
171
|
+
size_t PQescapeString(char *to, const char *from, size_t length);
|
172
|
+
unsigned char * PQescapeBytea(const unsigned char *bintext, size_t binlen, size_t *bytealen);
|
173
|
+
unsigned char * PQunescapeBytea(const unsigned char *strtext, size_t *retbuflen);
|
174
|
+
size_t PQescapeStringConn(PGconn *conn, char *to, const char *from,
|
175
|
+
size_t length, int *error);
|
176
|
+
unsigned char *PQescapeByteaConn(PGconn *conn, const unsigned char *from,
|
177
|
+
size_t from_length, size_t *to_length);
|
178
|
+
#endif /* PG_BEFORE_070300 */
|
179
|
+
|
180
|
+
#endif /* __compat_h */
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
if pgdir = with_config( 'pg' )
|
4
|
+
ENV['PATH'] = "#{pgdir}/bin" + File::PATH_SEPERATOR + ENV['PATH']
|
5
|
+
end
|
6
|
+
|
7
|
+
### Read the output of a command using the fork+pipe syntax so execution errors
|
8
|
+
### propagate to Ruby.
|
9
|
+
def read_cmd_output( *cmd )
|
10
|
+
output = IO.read( '|-' ) or exec( *cmd )
|
11
|
+
return output.chomp
|
12
|
+
end
|
13
|
+
|
14
|
+
### Turn a version string into a Comparable binary datastructure
|
15
|
+
def vvec( version )
|
16
|
+
version.split( '.' ).collect {|i| Integer(i) }.pack( 'N*' )
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
if vvec(RUBY_VERSION) < vvec('1.8')
|
21
|
+
puts 'This library is for ruby-1.8 or higher.'
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
pgconfig = with_config( 'pg-config' ) || 'pg_config'
|
26
|
+
if pgconfig = find_executable( pgconfig )
|
27
|
+
$CPPFLAGS << " -I%s" % [ read_cmd_output(pgconfig, '--includedir') ]
|
28
|
+
$LDFLAGS << " -L%s" % [ read_cmd_output(pgconfig, '--libdir') ]
|
29
|
+
end
|
30
|
+
|
31
|
+
# Sort out the universal vs. single-archicture build problems on MacOS X
|
32
|
+
if RUBY_PLATFORM.include?( 'darwin' )
|
33
|
+
puts "MacOS X build: fixing architecture flags:"
|
34
|
+
|
35
|
+
# Only keep the '-arch <a>' flags present in both the cflags reported
|
36
|
+
# by pg_config and those that Ruby specifies.
|
37
|
+
commonflags = nil
|
38
|
+
if ENV['ARCHFLAGS']
|
39
|
+
puts " using the value in ARCHFLAGS environment variable (%p)." % [ ENV['ARCHFLAGS'] ]
|
40
|
+
commonflags = ENV['ARCHFLAGS']
|
41
|
+
elsif pgconfig
|
42
|
+
puts " finding flags common to both Ruby and PostgreSQL..."
|
43
|
+
archflags = []
|
44
|
+
pgcflags = read_cmd_output( pgconfig, '--cflags' )
|
45
|
+
pgcflags.scan( /-arch\s+(\S+)/ ).each do |arch|
|
46
|
+
puts " testing for architecture: %p" % [ arch ]
|
47
|
+
archflags << "-arch #{arch}" if Config::CONFIG['CFLAGS'].index("-arch #{arch}")
|
48
|
+
end
|
49
|
+
|
50
|
+
commonflags = archflags.join(' ')
|
51
|
+
puts " common arch flags: %s" % [ commonflags ]
|
52
|
+
else
|
53
|
+
$stderr.puts %{
|
54
|
+
=========== WARNING ===========
|
55
|
+
|
56
|
+
You are building this extension on OS X without setting the
|
57
|
+
ARCHFLAGS environment variable, and pg_config wasn't found in
|
58
|
+
your PATH. If you are seeing this message, that means that the
|
59
|
+
build will probably fail.
|
60
|
+
|
61
|
+
If it does, you can correct this by either including the path
|
62
|
+
to 'pg_config' in your PATH or setting the environment variable
|
63
|
+
ARCHFLAGS to '-arch <arch>' before building.
|
64
|
+
|
65
|
+
For example:
|
66
|
+
(in bash) $ export PATH=/opt/local/lib/postgresql84/bin:$PATH
|
67
|
+
$ export ARCHFLAGS='-arch x86_64'
|
68
|
+
(in tcsh) % set path = ( /opt/local/lib/postgresql84/bin $PATH )
|
69
|
+
% setenv ARCHFLAGS '-arch x86_64'
|
70
|
+
|
71
|
+
Then try building again.
|
72
|
+
|
73
|
+
===================================
|
74
|
+
}.gsub( /^\t+/, ' ' )
|
75
|
+
end
|
76
|
+
|
77
|
+
if commonflags
|
78
|
+
$CFLAGS.gsub!( /-arch\s+\S+ /, '' )
|
79
|
+
$LDFLAGS.gsub!( /-arch\s+\S+ /, '' )
|
80
|
+
CONFIG['LDSHARED'].gsub!( /-arch\s+\S+ /, '' )
|
81
|
+
|
82
|
+
$CFLAGS << ' ' << commonflags
|
83
|
+
$LDFLAGS << ' ' << commonflags
|
84
|
+
CONFIG['LDSHARED'] << ' ' << commonflags
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
dir_config 'pg'
|
90
|
+
|
91
|
+
if enable_config("static-build")
|
92
|
+
# Link against all required libraries for static build, if they are available
|
93
|
+
have_library('gdi32', 'CreateDC') && append_library($libs, 'gdi32')
|
94
|
+
have_library('secur32') && append_library($libs, 'secur32')
|
95
|
+
have_library('crypto', 'BIO_new') && append_library($libs, 'crypto')
|
96
|
+
have_library('ssl', 'SSL_new') && append_library($libs, 'ssl')
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
abort "Can't find the 'libpq-fe.h header" unless have_header( 'libpq-fe.h' )
|
101
|
+
abort "Can't find the 'libpq/libpq-fs.h header" unless have_header('libpq/libpq-fs.h')
|
102
|
+
|
103
|
+
abort "Can't find the PostgreSQL client library (libpq)" unless
|
104
|
+
have_library( 'pq', 'PQconnectdb' ) ||
|
105
|
+
have_library( 'libpq', 'PQconnectdb' ) ||
|
106
|
+
have_library( 'ms/libpq', 'PQconnectdb' )
|
107
|
+
|
108
|
+
# optional headers/functions
|
109
|
+
have_func 'PQconnectionUsedPassword'
|
110
|
+
have_func 'PQisthreadsafe'
|
111
|
+
have_func 'PQprepare'
|
112
|
+
have_func 'PQexecParams'
|
113
|
+
have_func 'PQescapeString'
|
114
|
+
have_func 'PQescapeStringConn'
|
115
|
+
have_func 'lo_create'
|
116
|
+
have_func 'pg_encoding_to_char'
|
117
|
+
have_func 'PQsetClientEncoding'
|
118
|
+
|
119
|
+
# unistd.h confilicts with ruby/win32.h when cross compiling for win32 and ruby 1.9.1
|
120
|
+
have_header 'unistd.h' unless enable_config("static-build")
|
121
|
+
|
122
|
+
$CFLAGS << ' -Wall'
|
123
|
+
|
124
|
+
create_header()
|
125
|
+
create_makefile( "pg_ext" )
|
126
|
+
|
data/ext/pg.c
ADDED
@@ -0,0 +1,4250 @@
|
|
1
|
+
/************************************************
|
2
|
+
|
3
|
+
pg.c -
|
4
|
+
|
5
|
+
Author: matz
|
6
|
+
created at: Tue May 13 20:07:35 JST 1997
|
7
|
+
|
8
|
+
Author: ematsu
|
9
|
+
modified at: Wed Jan 20 16:41:51 1999
|
10
|
+
|
11
|
+
$Author$
|
12
|
+
$Date$
|
13
|
+
************************************************/
|
14
|
+
|
15
|
+
#include "pg.h"
|
16
|
+
#if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H
|
17
|
+
# define M17N_SUPPORTED
|
18
|
+
#endif
|
19
|
+
|
20
|
+
#define rb_define_singleton_alias(klass,new,old) rb_define_alias(rb_singleton_class(klass),new,old)
|
21
|
+
|
22
|
+
static VALUE rb_cPGconn;
|
23
|
+
static VALUE rb_cPGresult;
|
24
|
+
static VALUE rb_ePGError;
|
25
|
+
|
26
|
+
static const char *VERSION = "0.9.0";
|
27
|
+
|
28
|
+
|
29
|
+
/* The following functions are part of libpq, but not
|
30
|
+
* available from ruby-pg, because they are deprecated,
|
31
|
+
* obsolete, or generally not useful:
|
32
|
+
*
|
33
|
+
* * PQfreemem -- unnecessary: copied to ruby object, then
|
34
|
+
* freed. Ruby object's memory is freed when
|
35
|
+
* it is garbage collected.
|
36
|
+
* * PQbinaryTuples -- better to use PQfformat
|
37
|
+
* * PQprint -- not very useful
|
38
|
+
* * PQsetdb -- not very useful
|
39
|
+
* * PQoidStatus -- deprecated, use PQoidValue
|
40
|
+
* * PQrequestCancel -- deprecated, use PQcancel
|
41
|
+
* * PQfn -- use a prepared statement instead
|
42
|
+
* * PQgetline -- deprecated, use PQgetCopyData
|
43
|
+
* * PQgetlineAsync -- deprecated, use PQgetCopyData
|
44
|
+
* * PQputline -- deprecated, use PQputCopyData
|
45
|
+
* * PQputnbytes -- deprecated, use PQputCopyData
|
46
|
+
* * PQendcopy -- deprecated, use PQputCopyEnd
|
47
|
+
*/
|
48
|
+
|
49
|
+
/***************************************************************************
|
50
|
+
* UTILITY FUNCTIONS
|
51
|
+
**************************************************************************/
|
52
|
+
|
53
|
+
static void free_pgconn(PGconn *);
|
54
|
+
static void pgresult_check(VALUE, VALUE);
|
55
|
+
|
56
|
+
static PGconn *get_pgconn(VALUE self);
|
57
|
+
static VALUE pgconn_finish(VALUE self);
|
58
|
+
static VALUE pgresult_clear(VALUE self);
|
59
|
+
static VALUE pgresult_aref(VALUE self, VALUE index);
|
60
|
+
static VALUE make_column_result_array( VALUE self, int col );
|
61
|
+
|
62
|
+
#ifdef M17N_SUPPORTED
|
63
|
+
# define ASSOCIATE_INDEX(obj, index_holder) rb_enc_associate_index((obj), enc_get_index((index_holder)))
|
64
|
+
static rb_encoding * pgconn_get_client_encoding_as_rb_encoding(PGconn* conn);
|
65
|
+
static int enc_get_index(VALUE val);
|
66
|
+
#else
|
67
|
+
# define ASSOCIATE_INDEX(obj, index_holder) /* nothing */
|
68
|
+
#endif
|
69
|
+
|
70
|
+
static PQnoticeReceiver default_notice_receiver = NULL;
|
71
|
+
static PQnoticeProcessor default_notice_processor = NULL;
|
72
|
+
|
73
|
+
|
74
|
+
/*
|
75
|
+
* Used to quote the values passed in a Hash to PGconn.init
|
76
|
+
* when building the connection string.
|
77
|
+
*/
|
78
|
+
static VALUE
|
79
|
+
pgconn_s_quote_connstr(VALUE string)
|
80
|
+
{
|
81
|
+
char *str,*ptr;
|
82
|
+
int i,j=0,len;
|
83
|
+
VALUE result;
|
84
|
+
|
85
|
+
Check_Type(string, T_STRING);
|
86
|
+
|
87
|
+
ptr = RSTRING_PTR(string);
|
88
|
+
len = RSTRING_LEN(string);
|
89
|
+
str = ALLOC_N(char, len * 2 + 2 + 1);
|
90
|
+
str[j++] = '\'';
|
91
|
+
for(i = 0; i < len; i++) {
|
92
|
+
if(ptr[i] == '\'' || ptr[i] == '\\')
|
93
|
+
str[j++] = '\\';
|
94
|
+
str[j++] = ptr[i];
|
95
|
+
}
|
96
|
+
str[j++] = '\'';
|
97
|
+
result = rb_str_new(str, j);
|
98
|
+
xfree(str);
|
99
|
+
return result;
|
100
|
+
}
|
101
|
+
|
102
|
+
static void
|
103
|
+
free_pgconn(PGconn *conn)
|
104
|
+
{
|
105
|
+
if(conn != NULL)
|
106
|
+
PQfinish(conn);
|
107
|
+
}
|
108
|
+
|
109
|
+
static void
|
110
|
+
free_pgresult(PGresult *result)
|
111
|
+
{
|
112
|
+
if(result != NULL)
|
113
|
+
PQclear(result);
|
114
|
+
}
|
115
|
+
|
116
|
+
static PGconn*
|
117
|
+
get_pgconn(VALUE self)
|
118
|
+
{
|
119
|
+
PGconn *conn;
|
120
|
+
Data_Get_Struct(self, PGconn, conn);
|
121
|
+
if (conn == NULL) rb_raise(rb_ePGError, "not connected");
|
122
|
+
return conn;
|
123
|
+
}
|
124
|
+
|
125
|
+
static PGresult*
|
126
|
+
get_pgresult(VALUE self)
|
127
|
+
{
|
128
|
+
PGresult *result;
|
129
|
+
Data_Get_Struct(self, PGresult, result);
|
130
|
+
if (result == NULL) rb_raise(rb_ePGError, "result has been cleared");
|
131
|
+
return result;
|
132
|
+
}
|
133
|
+
|
134
|
+
#ifdef M17N_SUPPORTED
|
135
|
+
static VALUE
|
136
|
+
new_pgresult(PGresult *result, PGconn *conn)
|
137
|
+
{
|
138
|
+
VALUE val = Data_Wrap_Struct(rb_cPGresult, NULL, free_pgresult, result);
|
139
|
+
rb_encoding *enc = pgconn_get_client_encoding_as_rb_encoding(conn);
|
140
|
+
rb_enc_set_index(val, rb_enc_to_index(enc));
|
141
|
+
return val;
|
142
|
+
}
|
143
|
+
#else
|
144
|
+
static VALUE
|
145
|
+
new_pgresult(PGresult *result)
|
146
|
+
{
|
147
|
+
return Data_Wrap_Struct(rb_cPGresult, NULL, free_pgresult, result);
|
148
|
+
}
|
149
|
+
# define new_pgresult(result, conn) new_pgresult((result))
|
150
|
+
#endif
|
151
|
+
|
152
|
+
/*
|
153
|
+
* Raises appropriate exception if PGresult is
|
154
|
+
* in a bad state.
|
155
|
+
*/
|
156
|
+
static void
|
157
|
+
pgresult_check(VALUE rb_pgconn, VALUE rb_pgresult)
|
158
|
+
{
|
159
|
+
VALUE error;
|
160
|
+
PGconn *conn = get_pgconn(rb_pgconn);
|
161
|
+
PGresult *result;
|
162
|
+
Data_Get_Struct(rb_pgresult, PGresult, result);
|
163
|
+
|
164
|
+
if(result == NULL)
|
165
|
+
{
|
166
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
167
|
+
}
|
168
|
+
else
|
169
|
+
{
|
170
|
+
switch (PQresultStatus(result))
|
171
|
+
{
|
172
|
+
case PGRES_TUPLES_OK:
|
173
|
+
case PGRES_COPY_OUT:
|
174
|
+
case PGRES_COPY_IN:
|
175
|
+
case PGRES_EMPTY_QUERY:
|
176
|
+
case PGRES_COMMAND_OK:
|
177
|
+
return;
|
178
|
+
case PGRES_BAD_RESPONSE:
|
179
|
+
case PGRES_FATAL_ERROR:
|
180
|
+
case PGRES_NONFATAL_ERROR:
|
181
|
+
error = rb_exc_new2(rb_ePGError, PQresultErrorMessage(result));
|
182
|
+
break;
|
183
|
+
default:
|
184
|
+
error = rb_exc_new2(rb_ePGError,
|
185
|
+
"internal error : unknown result status.");
|
186
|
+
}
|
187
|
+
}
|
188
|
+
|
189
|
+
rb_iv_set(error, "@connection", rb_pgconn);
|
190
|
+
rb_iv_set(error, "@result", rb_pgresult);
|
191
|
+
rb_exc_raise(error);
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
|
195
|
+
static void
|
196
|
+
notice_receiver_proxy(void *arg, const PGresult *result)
|
197
|
+
{
|
198
|
+
VALUE proc;
|
199
|
+
VALUE self = (VALUE)arg;
|
200
|
+
|
201
|
+
if ((proc = rb_iv_get(self, "@notice_receiver")) != Qnil) {
|
202
|
+
rb_funcall(proc, rb_intern("call"), 1,
|
203
|
+
Data_Wrap_Struct(rb_cPGresult, NULL, NULL, (PGresult*)result));
|
204
|
+
}
|
205
|
+
return;
|
206
|
+
}
|
207
|
+
|
208
|
+
static void
|
209
|
+
notice_processor_proxy(void *arg, const char *message)
|
210
|
+
{
|
211
|
+
VALUE proc;
|
212
|
+
VALUE self = (VALUE)arg;
|
213
|
+
|
214
|
+
if ((proc = rb_iv_get(self, "@notice_processor")) != Qnil) {
|
215
|
+
rb_funcall(proc, rb_intern("call"), 1, rb_tainted_str_new2(message));
|
216
|
+
}
|
217
|
+
return;
|
218
|
+
}
|
219
|
+
|
220
|
+
/*
|
221
|
+
* Appends key='val' to conninfo_rstr
|
222
|
+
*/
|
223
|
+
static void
|
224
|
+
build_key_value_string(VALUE conninfo_rstr, char *key, VALUE val)
|
225
|
+
{
|
226
|
+
if(val != Qnil) {
|
227
|
+
if(RSTRING_LEN(conninfo_rstr) > 0)
|
228
|
+
rb_str_cat2(conninfo_rstr, " ");
|
229
|
+
rb_str_cat2(conninfo_rstr, key);
|
230
|
+
rb_str_cat2(conninfo_rstr, "=");
|
231
|
+
rb_str_concat(conninfo_rstr,
|
232
|
+
pgconn_s_quote_connstr(rb_obj_as_string(val)));
|
233
|
+
}
|
234
|
+
return;
|
235
|
+
}
|
236
|
+
|
237
|
+
static VALUE
|
238
|
+
parse_connect_args(int argc, VALUE *argv, VALUE self)
|
239
|
+
{
|
240
|
+
VALUE args,arg;
|
241
|
+
VALUE conninfo_rstr = rb_str_new("",0);
|
242
|
+
char *host, *port, *opt, *tty, *dbname, *login, *pwd;
|
243
|
+
host=port=opt=tty=dbname=login=pwd=NULL;
|
244
|
+
|
245
|
+
rb_scan_args(argc, argv, "0*", &args);
|
246
|
+
if (RARRAY_LEN(args) == 1) {
|
247
|
+
arg = rb_ary_entry(args,0);
|
248
|
+
if(TYPE(arg) == T_HASH) {
|
249
|
+
build_key_value_string(conninfo_rstr, "host",
|
250
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("host"))));
|
251
|
+
build_key_value_string(conninfo_rstr, "hostaddr",
|
252
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("hostaddr"))));
|
253
|
+
build_key_value_string(conninfo_rstr, "port",
|
254
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("port"))));
|
255
|
+
build_key_value_string(conninfo_rstr, "dbname",
|
256
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("dbname"))));
|
257
|
+
build_key_value_string(conninfo_rstr, "user",
|
258
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("user"))));
|
259
|
+
build_key_value_string(conninfo_rstr, "password",
|
260
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("password"))));
|
261
|
+
build_key_value_string(conninfo_rstr, "connect_timeout",
|
262
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("connect_timeout"))));
|
263
|
+
build_key_value_string(conninfo_rstr, "options",
|
264
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("options"))));
|
265
|
+
build_key_value_string(conninfo_rstr, "tty",
|
266
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("tty"))));
|
267
|
+
build_key_value_string(conninfo_rstr, "sslmode",
|
268
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("sslmode"))));
|
269
|
+
build_key_value_string(conninfo_rstr, "krbsrvname",
|
270
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("krbsrvname"))));
|
271
|
+
build_key_value_string(conninfo_rstr, "gsslib",
|
272
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("gsslib"))));
|
273
|
+
build_key_value_string(conninfo_rstr, "service",
|
274
|
+
rb_hash_aref(arg, ID2SYM(rb_intern("service"))));
|
275
|
+
}
|
276
|
+
else if(TYPE(arg) == T_STRING) {
|
277
|
+
conninfo_rstr = arg;
|
278
|
+
}
|
279
|
+
else {
|
280
|
+
rb_raise(rb_eArgError,
|
281
|
+
"Expecting String or Hash as single argument");
|
282
|
+
}
|
283
|
+
}
|
284
|
+
else if (RARRAY_LEN(args) == 7) {
|
285
|
+
build_key_value_string(conninfo_rstr, "host", rb_ary_entry(args,0));
|
286
|
+
build_key_value_string(conninfo_rstr, "port", rb_ary_entry(args,1));
|
287
|
+
build_key_value_string(conninfo_rstr, "options", rb_ary_entry(args,2));
|
288
|
+
build_key_value_string(conninfo_rstr, "tty", rb_ary_entry(args,3));
|
289
|
+
build_key_value_string(conninfo_rstr, "dbname", rb_ary_entry(args,4));
|
290
|
+
build_key_value_string(conninfo_rstr, "user", rb_ary_entry(args,5));
|
291
|
+
build_key_value_string(conninfo_rstr, "password", rb_ary_entry(args,6));
|
292
|
+
}
|
293
|
+
else {
|
294
|
+
rb_raise(rb_eArgError,
|
295
|
+
"Expected connection info string, hash, or 7 separate arguments.");
|
296
|
+
}
|
297
|
+
|
298
|
+
return conninfo_rstr;
|
299
|
+
}
|
300
|
+
|
301
|
+
/********************************************************************
|
302
|
+
*
|
303
|
+
* Document-class: PGError
|
304
|
+
*
|
305
|
+
* This is the exception class raised when an error is returned from
|
306
|
+
* a libpq API call.
|
307
|
+
*
|
308
|
+
* The attributes +connection+ and +result+ are set to the connection
|
309
|
+
* object and result set object, respectively.
|
310
|
+
*
|
311
|
+
* If the connection object or result set object is not available from
|
312
|
+
* the context in which the error was encountered, it is +nil+.
|
313
|
+
*/
|
314
|
+
|
315
|
+
/********************************************************************
|
316
|
+
*
|
317
|
+
* Document-class: PGconn
|
318
|
+
*
|
319
|
+
* The class to access PostgreSQL RDBMS, based on the libpq interface,
|
320
|
+
* provides convenient OO methods to interact with PostgreSQL.
|
321
|
+
*
|
322
|
+
* For example, to send query to the database on the localhost:
|
323
|
+
* require 'pg'
|
324
|
+
* conn = PGconn.open(:dbname => 'test')
|
325
|
+
* res = conn.exec('SELECT $1 AS a, $2 AS b, $3 AS c',[1, 2, nil])
|
326
|
+
* # Equivalent to:
|
327
|
+
* # res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
328
|
+
*
|
329
|
+
* See the PGresult class for information on working with the results of a query.
|
330
|
+
*
|
331
|
+
*/
|
332
|
+
|
333
|
+
static VALUE
|
334
|
+
pgconn_alloc(VALUE klass)
|
335
|
+
{
|
336
|
+
return Data_Wrap_Struct(klass, NULL, free_pgconn, NULL);
|
337
|
+
}
|
338
|
+
|
339
|
+
/**************************************************************************
|
340
|
+
* PGconn SINGLETON METHODS
|
341
|
+
**************************************************************************/
|
342
|
+
|
343
|
+
/*
|
344
|
+
* Document-method: new
|
345
|
+
*
|
346
|
+
* call-seq:
|
347
|
+
* PGconn.new(connection_hash) -> PGconn
|
348
|
+
* PGconn.new(connection_string) -> PGconn
|
349
|
+
* PGconn.new(host, port, options, tty, dbname, login, password) -> PGconn
|
350
|
+
*
|
351
|
+
* Create a connection to the specified server.
|
352
|
+
*
|
353
|
+
* [+host+]
|
354
|
+
* server hostname
|
355
|
+
* [+hostaddr+]
|
356
|
+
* server address (avoids hostname lookup, overrides +host+)
|
357
|
+
* [+port+]
|
358
|
+
* server port number
|
359
|
+
* [+dbname+]
|
360
|
+
* connecting database name
|
361
|
+
* [+user+]
|
362
|
+
* login user name
|
363
|
+
* [+password+]
|
364
|
+
* login password
|
365
|
+
* [+connect_timeout+]
|
366
|
+
* maximum time to wait for connection to succeed
|
367
|
+
* [+options+]
|
368
|
+
* backend options
|
369
|
+
* [+tty+]
|
370
|
+
* (ignored in newer versions of PostgreSQL)
|
371
|
+
* [+sslmode+]
|
372
|
+
* (disable|allow|prefer|require)
|
373
|
+
* [+krbsrvname+]
|
374
|
+
* kerberos service name
|
375
|
+
* [+gsslib+]
|
376
|
+
* GSS library to use for GSSAPI authentication
|
377
|
+
* [+service+]
|
378
|
+
* service name to use for additional parameters
|
379
|
+
*
|
380
|
+
* Examples:
|
381
|
+
*
|
382
|
+
* # As a Hash
|
383
|
+
* PGconn.connect( :dbname => 'test', :port => 5432 )
|
384
|
+
*
|
385
|
+
* # As a String
|
386
|
+
* PGconn.connect( "dbname=test port=5432" )
|
387
|
+
*
|
388
|
+
* # As an Array
|
389
|
+
* PGconn.connect( nil, 5432, nil, nil, 'test', nil, nil )
|
390
|
+
*
|
391
|
+
* On failure, it raises a PGError.
|
392
|
+
*/
|
393
|
+
static VALUE
|
394
|
+
pgconn_init(int argc, VALUE *argv, VALUE self)
|
395
|
+
{
|
396
|
+
PGconn *conn = NULL;
|
397
|
+
VALUE conninfo;
|
398
|
+
VALUE error;
|
399
|
+
|
400
|
+
conninfo = parse_connect_args(argc, argv, self);
|
401
|
+
conn = PQconnectdb(StringValuePtr(conninfo));
|
402
|
+
|
403
|
+
if(conn == NULL)
|
404
|
+
rb_raise(rb_ePGError, "PQconnectStart() unable to allocate structure");
|
405
|
+
|
406
|
+
Check_Type(self, T_DATA);
|
407
|
+
DATA_PTR(self) = conn;
|
408
|
+
|
409
|
+
if (PQstatus(conn) == CONNECTION_BAD) {
|
410
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
411
|
+
rb_iv_set(error, "@connection", self);
|
412
|
+
rb_exc_raise(error);
|
413
|
+
}
|
414
|
+
|
415
|
+
if (rb_block_given_p()) {
|
416
|
+
return rb_ensure(rb_yield, self, pgconn_finish, self);
|
417
|
+
}
|
418
|
+
return self;
|
419
|
+
}
|
420
|
+
|
421
|
+
/*
|
422
|
+
* call-seq:
|
423
|
+
* PGconn.connect_start(connection_hash) -> PGconn
|
424
|
+
* PGconn.connect_start(connection_string) -> PGconn
|
425
|
+
* PGconn.connect_start(host, port, options, tty, dbname, login, password) -> PGconn
|
426
|
+
*
|
427
|
+
* This is an asynchronous version of PGconn.connect().
|
428
|
+
*
|
429
|
+
* Use PGconn#connect_poll to poll the status of the connection.
|
430
|
+
*/
|
431
|
+
static VALUE
|
432
|
+
pgconn_s_connect_start(int argc, VALUE *argv, VALUE self)
|
433
|
+
{
|
434
|
+
PGconn *conn = NULL;
|
435
|
+
VALUE rb_conn;
|
436
|
+
VALUE conninfo;
|
437
|
+
VALUE error;
|
438
|
+
|
439
|
+
/*
|
440
|
+
* PGconn.connect_start must act as both alloc() and initialize()
|
441
|
+
* because it is not invoked by calling new().
|
442
|
+
*/
|
443
|
+
rb_conn = pgconn_alloc(rb_cPGconn);
|
444
|
+
|
445
|
+
conninfo = parse_connect_args(argc, argv, self);
|
446
|
+
conn = PQconnectStart(StringValuePtr(conninfo));
|
447
|
+
|
448
|
+
if(conn == NULL)
|
449
|
+
rb_raise(rb_ePGError, "PQconnectStart() unable to allocate structure");
|
450
|
+
if (PQstatus(conn) == CONNECTION_BAD) {
|
451
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
452
|
+
rb_iv_set(error, "@connection", self);
|
453
|
+
rb_exc_raise(error);
|
454
|
+
}
|
455
|
+
|
456
|
+
Check_Type(rb_conn, T_DATA);
|
457
|
+
DATA_PTR(rb_conn) = conn;
|
458
|
+
|
459
|
+
if (rb_block_given_p()) {
|
460
|
+
return rb_ensure(rb_yield, self, pgconn_finish, self);
|
461
|
+
}
|
462
|
+
return rb_conn;
|
463
|
+
}
|
464
|
+
|
465
|
+
/*
|
466
|
+
* call-seq:
|
467
|
+
* PGconn.conndefaults() -> Array
|
468
|
+
*
|
469
|
+
* Returns an array of hashes. Each hash has the keys:
|
470
|
+
* [+:keyword+]
|
471
|
+
* the name of the option
|
472
|
+
* [+:envvar+]
|
473
|
+
* the environment variable to fall back to
|
474
|
+
* [+:compiled+]
|
475
|
+
* the compiled in option as a secondary fallback
|
476
|
+
* [+:val+]
|
477
|
+
* the option's current value, or +nil+ if not known
|
478
|
+
* [+:label+]
|
479
|
+
* the label for the field
|
480
|
+
* [+:dispchar+]
|
481
|
+
* "" for normal, "D" for debug, and "*" for password
|
482
|
+
* [+:dispsize+]
|
483
|
+
* field size
|
484
|
+
*/
|
485
|
+
static VALUE
|
486
|
+
pgconn_s_conndefaults(VALUE self)
|
487
|
+
{
|
488
|
+
PQconninfoOption *options = PQconndefaults();
|
489
|
+
VALUE ary = rb_ary_new();
|
490
|
+
VALUE hash;
|
491
|
+
int i = 0;
|
492
|
+
|
493
|
+
for(i = 0; options[i].keyword != NULL; i++) {
|
494
|
+
hash = rb_hash_new();
|
495
|
+
if(options[i].keyword)
|
496
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("keyword")),
|
497
|
+
rb_str_new2(options[i].keyword));
|
498
|
+
if(options[i].envvar)
|
499
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("envvar")),
|
500
|
+
rb_str_new2(options[i].envvar));
|
501
|
+
if(options[i].compiled)
|
502
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("compiled")),
|
503
|
+
rb_str_new2(options[i].compiled));
|
504
|
+
if(options[i].val)
|
505
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("val")),
|
506
|
+
rb_str_new2(options[i].val));
|
507
|
+
if(options[i].label)
|
508
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("label")),
|
509
|
+
rb_str_new2(options[i].label));
|
510
|
+
if(options[i].dispchar)
|
511
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispchar")),
|
512
|
+
rb_str_new2(options[i].dispchar));
|
513
|
+
rb_hash_aset(hash, ID2SYM(rb_intern("dispsize")),
|
514
|
+
INT2NUM(options[i].dispsize));
|
515
|
+
rb_ary_push(ary, hash);
|
516
|
+
}
|
517
|
+
PQconninfoFree(options);
|
518
|
+
return ary;
|
519
|
+
}
|
520
|
+
|
521
|
+
|
522
|
+
/*
|
523
|
+
* call-seq:
|
524
|
+
* PGconn.encrypt_password( password, username ) -> String
|
525
|
+
*
|
526
|
+
* This function is intended to be used by client applications that
|
527
|
+
* send commands like: +ALTER USER joe PASSWORD 'pwd'+.
|
528
|
+
* The arguments are the cleartext password, and the SQL name
|
529
|
+
* of the user it is for.
|
530
|
+
*
|
531
|
+
* Return value is the encrypted password.
|
532
|
+
*/
|
533
|
+
static VALUE
|
534
|
+
pgconn_s_encrypt_password(VALUE self, VALUE password, VALUE username)
|
535
|
+
{
|
536
|
+
char *encrypted = NULL;
|
537
|
+
VALUE rval = Qnil;
|
538
|
+
|
539
|
+
Check_Type(password, T_STRING);
|
540
|
+
Check_Type(username, T_STRING);
|
541
|
+
|
542
|
+
encrypted = PQencryptPassword(StringValuePtr(password), StringValuePtr(username));
|
543
|
+
rval = rb_str_new2( encrypted );
|
544
|
+
PQfreemem( encrypted );
|
545
|
+
|
546
|
+
OBJ_INFECT( rval, password );
|
547
|
+
OBJ_INFECT( rval, username );
|
548
|
+
|
549
|
+
return rval;
|
550
|
+
}
|
551
|
+
|
552
|
+
|
553
|
+
/*
|
554
|
+
* call-seq:
|
555
|
+
* PGconn.isthreadsafe() -> Boolean
|
556
|
+
*
|
557
|
+
* Returns +true+ if libpq is thread safe, +false+ otherwise.
|
558
|
+
*/
|
559
|
+
static VALUE
|
560
|
+
pgconn_s_isthreadsafe(VALUE self)
|
561
|
+
{
|
562
|
+
return PQisthreadsafe() ? Qtrue : Qfalse;
|
563
|
+
}
|
564
|
+
|
565
|
+
/**************************************************************************
|
566
|
+
* PGconn INSTANCE METHODS
|
567
|
+
**************************************************************************/
|
568
|
+
|
569
|
+
/*
|
570
|
+
* call-seq:
|
571
|
+
* conn.connect_poll() -> Fixnum
|
572
|
+
*
|
573
|
+
* Returns one of:
|
574
|
+
* [+PGRES_POLLING_READING+]
|
575
|
+
* wait until the socket is ready to read
|
576
|
+
* [+PGRES_POLLING_WRITING+]
|
577
|
+
* wait until the socket is ready to write
|
578
|
+
* [+PGRES_POLLING_FAILED+]
|
579
|
+
* the asynchronous connection has failed
|
580
|
+
* [+PGRES_POLLING_OK+]
|
581
|
+
* the asynchronous connection is ready
|
582
|
+
*
|
583
|
+
* Example:
|
584
|
+
* conn = PGconn.connect_start("dbname=mydatabase")
|
585
|
+
* socket = IO.for_fd(conn.socket)
|
586
|
+
* status = conn.connect_poll
|
587
|
+
* while(status != PGconn::PGRES_POLLING_OK) do
|
588
|
+
* # do some work while waiting for the connection to complete
|
589
|
+
* if(status == PGconn::PGRES_POLLING_READING)
|
590
|
+
* if(not select([socket], [], [], 10.0))
|
591
|
+
* raise "Asynchronous connection timed out!"
|
592
|
+
* end
|
593
|
+
* elsif(status == PGconn::PGRES_POLLING_WRITING)
|
594
|
+
* if(not select([], [socket], [], 10.0))
|
595
|
+
* raise "Asynchronous connection timed out!"
|
596
|
+
* end
|
597
|
+
* end
|
598
|
+
* status = conn.connect_poll
|
599
|
+
* end
|
600
|
+
* # now conn.status == CONNECTION_OK, and connection
|
601
|
+
* # is ready.
|
602
|
+
*/
|
603
|
+
static VALUE
|
604
|
+
pgconn_connect_poll(VALUE self)
|
605
|
+
{
|
606
|
+
PostgresPollingStatusType status;
|
607
|
+
status = PQconnectPoll(get_pgconn(self));
|
608
|
+
return INT2FIX((int)status);
|
609
|
+
}
|
610
|
+
|
611
|
+
/*
|
612
|
+
* call-seq:
|
613
|
+
* conn.finish()
|
614
|
+
*
|
615
|
+
* Closes the backend connection.
|
616
|
+
*/
|
617
|
+
static VALUE
|
618
|
+
pgconn_finish(VALUE self)
|
619
|
+
{
|
620
|
+
PQfinish(get_pgconn(self));
|
621
|
+
DATA_PTR(self) = NULL;
|
622
|
+
return Qnil;
|
623
|
+
}
|
624
|
+
|
625
|
+
/*
|
626
|
+
* call-seq:
|
627
|
+
* conn.reset()
|
628
|
+
*
|
629
|
+
* Resets the backend connection. This method closes the
|
630
|
+
* backend connection and tries to re-connect.
|
631
|
+
*/
|
632
|
+
static VALUE
|
633
|
+
pgconn_reset(VALUE self)
|
634
|
+
{
|
635
|
+
PQreset(get_pgconn(self));
|
636
|
+
return self;
|
637
|
+
}
|
638
|
+
|
639
|
+
/*
|
640
|
+
* call-seq:
|
641
|
+
* conn.reset_start() -> nil
|
642
|
+
*
|
643
|
+
* Initiate a connection reset in a nonblocking manner.
|
644
|
+
* This will close the current connection and attempt to
|
645
|
+
* reconnect using the same connection parameters.
|
646
|
+
* Use PGconn#reset_poll to check the status of the
|
647
|
+
* connection reset.
|
648
|
+
*/
|
649
|
+
static VALUE
|
650
|
+
pgconn_reset_start(VALUE self)
|
651
|
+
{
|
652
|
+
if(PQresetStart(get_pgconn(self)) == 0)
|
653
|
+
rb_raise(rb_ePGError, "reset has failed");
|
654
|
+
return Qnil;
|
655
|
+
}
|
656
|
+
|
657
|
+
/*
|
658
|
+
* call-seq:
|
659
|
+
* conn.reset_poll -> Fixnum
|
660
|
+
*
|
661
|
+
* Checks the status of a connection reset operation.
|
662
|
+
* See PGconn#connect_start and PGconn#connect_poll for
|
663
|
+
* usage information and return values.
|
664
|
+
*/
|
665
|
+
static VALUE
|
666
|
+
pgconn_reset_poll(VALUE self)
|
667
|
+
{
|
668
|
+
PostgresPollingStatusType status;
|
669
|
+
status = PQresetPoll(get_pgconn(self));
|
670
|
+
return INT2FIX((int)status);
|
671
|
+
}
|
672
|
+
|
673
|
+
/*
|
674
|
+
* call-seq:
|
675
|
+
* conn.db()
|
676
|
+
*
|
677
|
+
* Returns the connected database name.
|
678
|
+
*/
|
679
|
+
static VALUE
|
680
|
+
pgconn_db(VALUE self)
|
681
|
+
{
|
682
|
+
char *db = PQdb(get_pgconn(self));
|
683
|
+
if (!db) return Qnil;
|
684
|
+
return rb_tainted_str_new2(db);
|
685
|
+
}
|
686
|
+
|
687
|
+
/*
|
688
|
+
* call-seq:
|
689
|
+
* conn.user()
|
690
|
+
*
|
691
|
+
* Returns the authenticated user name.
|
692
|
+
*/
|
693
|
+
static VALUE
|
694
|
+
pgconn_user(VALUE self)
|
695
|
+
{
|
696
|
+
char *user = PQuser(get_pgconn(self));
|
697
|
+
if (!user) return Qnil;
|
698
|
+
return rb_tainted_str_new2(user);
|
699
|
+
}
|
700
|
+
|
701
|
+
/*
|
702
|
+
* call-seq:
|
703
|
+
* conn.pass()
|
704
|
+
*
|
705
|
+
* Returns the authenticated user name.
|
706
|
+
*/
|
707
|
+
static VALUE
|
708
|
+
pgconn_pass(VALUE self)
|
709
|
+
{
|
710
|
+
char *user = PQpass(get_pgconn(self));
|
711
|
+
if (!user) return Qnil;
|
712
|
+
return rb_tainted_str_new2(user);
|
713
|
+
}
|
714
|
+
|
715
|
+
/*
|
716
|
+
* call-seq:
|
717
|
+
* conn.host()
|
718
|
+
*
|
719
|
+
* Returns the connected server name.
|
720
|
+
*/
|
721
|
+
static VALUE
|
722
|
+
pgconn_host(VALUE self)
|
723
|
+
{
|
724
|
+
char *host = PQhost(get_pgconn(self));
|
725
|
+
if (!host) return Qnil;
|
726
|
+
return rb_tainted_str_new2(host);
|
727
|
+
}
|
728
|
+
|
729
|
+
/*
|
730
|
+
* call-seq:
|
731
|
+
* conn.port()
|
732
|
+
*
|
733
|
+
* Returns the connected server port number.
|
734
|
+
*/
|
735
|
+
static VALUE
|
736
|
+
pgconn_port(VALUE self)
|
737
|
+
{
|
738
|
+
char* port = PQport(get_pgconn(self));
|
739
|
+
return INT2NUM(atol(port));
|
740
|
+
}
|
741
|
+
|
742
|
+
/*
|
743
|
+
* call-seq:
|
744
|
+
* conn.tty()
|
745
|
+
*
|
746
|
+
* Returns the connected pgtty. (Obsolete)
|
747
|
+
*/
|
748
|
+
static VALUE
|
749
|
+
pgconn_tty(VALUE self)
|
750
|
+
{
|
751
|
+
char *tty = PQtty(get_pgconn(self));
|
752
|
+
if (!tty) return Qnil;
|
753
|
+
return rb_tainted_str_new2(tty);
|
754
|
+
}
|
755
|
+
|
756
|
+
/*
|
757
|
+
* call-seq:
|
758
|
+
* conn.options()
|
759
|
+
*
|
760
|
+
* Returns backend option string.
|
761
|
+
*/
|
762
|
+
static VALUE
|
763
|
+
pgconn_options(VALUE self)
|
764
|
+
{
|
765
|
+
char *options = PQoptions(get_pgconn(self));
|
766
|
+
if (!options) return Qnil;
|
767
|
+
return rb_tainted_str_new2(options);
|
768
|
+
}
|
769
|
+
|
770
|
+
/*
|
771
|
+
* call-seq:
|
772
|
+
* conn.status()
|
773
|
+
*
|
774
|
+
* Returns status of connection : CONNECTION_OK or CONNECTION_BAD
|
775
|
+
*/
|
776
|
+
static VALUE
|
777
|
+
pgconn_status(VALUE self)
|
778
|
+
{
|
779
|
+
return INT2NUM(PQstatus(get_pgconn(self)));
|
780
|
+
}
|
781
|
+
|
782
|
+
/*
|
783
|
+
* call-seq:
|
784
|
+
* conn.transaction_status()
|
785
|
+
*
|
786
|
+
* returns one of the following statuses:
|
787
|
+
* PQTRANS_IDLE = 0 (connection idle)
|
788
|
+
* PQTRANS_ACTIVE = 1 (command in progress)
|
789
|
+
* PQTRANS_INTRANS = 2 (idle, within transaction block)
|
790
|
+
* PQTRANS_INERROR = 3 (idle, within failed transaction)
|
791
|
+
* PQTRANS_UNKNOWN = 4 (cannot determine status)
|
792
|
+
*/
|
793
|
+
static VALUE
|
794
|
+
pgconn_transaction_status(VALUE self)
|
795
|
+
{
|
796
|
+
return INT2NUM(PQtransactionStatus(get_pgconn(self)));
|
797
|
+
}
|
798
|
+
|
799
|
+
/*
|
800
|
+
* call-seq:
|
801
|
+
* conn.parameter_status( param_name ) -> String
|
802
|
+
*
|
803
|
+
* Returns the setting of parameter _param_name_, where
|
804
|
+
* _param_name_ is one of
|
805
|
+
* * +server_version+
|
806
|
+
* * +server_encoding+
|
807
|
+
* * +client_encoding+
|
808
|
+
* * +is_superuser+
|
809
|
+
* * +session_authorization+
|
810
|
+
* * +DateStyle+
|
811
|
+
* * +TimeZone+
|
812
|
+
* * +integer_datetimes+
|
813
|
+
* * +standard_conforming_strings+
|
814
|
+
*
|
815
|
+
* Returns nil if the value of the parameter is not known.
|
816
|
+
*/
|
817
|
+
static VALUE
|
818
|
+
pgconn_parameter_status(VALUE self, VALUE param_name)
|
819
|
+
{
|
820
|
+
const char *ret = PQparameterStatus(get_pgconn(self),
|
821
|
+
StringValuePtr(param_name));
|
822
|
+
if(ret == NULL)
|
823
|
+
return Qnil;
|
824
|
+
else
|
825
|
+
return rb_tainted_str_new2(ret);
|
826
|
+
}
|
827
|
+
|
828
|
+
/*
|
829
|
+
* call-seq:
|
830
|
+
* conn.protocol_version -> Integer
|
831
|
+
*
|
832
|
+
* The 3.0 protocol will normally be used when communicating with PostgreSQL 7.4
|
833
|
+
* or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is
|
834
|
+
* obsolete and not supported by libpq.)
|
835
|
+
*/
|
836
|
+
static VALUE
|
837
|
+
pgconn_protocol_version(VALUE self)
|
838
|
+
{
|
839
|
+
return INT2NUM(PQprotocolVersion(get_pgconn(self)));
|
840
|
+
}
|
841
|
+
|
842
|
+
/*
|
843
|
+
* call-seq:
|
844
|
+
* conn.server_version -> Integer
|
845
|
+
*
|
846
|
+
* The number is formed by converting the major, minor, and revision
|
847
|
+
* numbers into two-decimal-digit numbers and appending them together.
|
848
|
+
* For example, version 7.4.2 will be returned as 70402, and version
|
849
|
+
* 8.1 will be returned as 80100 (leading zeroes are not shown). Zero
|
850
|
+
* is returned if the connection is bad.
|
851
|
+
*
|
852
|
+
*/
|
853
|
+
static VALUE
|
854
|
+
pgconn_server_version(VALUE self)
|
855
|
+
{
|
856
|
+
return INT2NUM(PQserverVersion(get_pgconn(self)));
|
857
|
+
}
|
858
|
+
|
859
|
+
/*
|
860
|
+
* call-seq:
|
861
|
+
* conn.error() -> String
|
862
|
+
*
|
863
|
+
* Returns the error message about connection.
|
864
|
+
*/
|
865
|
+
static VALUE
|
866
|
+
pgconn_error_message(VALUE self)
|
867
|
+
{
|
868
|
+
char *error = PQerrorMessage(get_pgconn(self));
|
869
|
+
if (!error) return Qnil;
|
870
|
+
return rb_tainted_str_new2(error);
|
871
|
+
}
|
872
|
+
|
873
|
+
/*
|
874
|
+
* call-seq:
|
875
|
+
* conn.socket() -> Fixnum
|
876
|
+
*
|
877
|
+
* Returns the socket's file descriptor for this connection.
|
878
|
+
*/
|
879
|
+
static VALUE
|
880
|
+
pgconn_socket(VALUE self)
|
881
|
+
{
|
882
|
+
int sd;
|
883
|
+
if( (sd = PQsocket(get_pgconn(self))) < 0)
|
884
|
+
rb_raise(rb_ePGError, "Can't get socket descriptor");
|
885
|
+
return INT2NUM(sd);
|
886
|
+
}
|
887
|
+
|
888
|
+
|
889
|
+
/*
|
890
|
+
* call-seq:
|
891
|
+
* conn.backend_pid() -> Fixnum
|
892
|
+
*
|
893
|
+
* Returns the process ID of the backend server
|
894
|
+
* process for this connection.
|
895
|
+
* Note that this is a PID on database server host.
|
896
|
+
*/
|
897
|
+
static VALUE
|
898
|
+
pgconn_backend_pid(VALUE self)
|
899
|
+
{
|
900
|
+
return INT2NUM(PQbackendPID(get_pgconn(self)));
|
901
|
+
}
|
902
|
+
|
903
|
+
/*
|
904
|
+
* call-seq:
|
905
|
+
* conn.connection_needs_password() -> Boolean
|
906
|
+
*
|
907
|
+
* Returns +true+ if the authentication method required a
|
908
|
+
* password, but none was available. +false+ otherwise.
|
909
|
+
*/
|
910
|
+
static VALUE
|
911
|
+
pgconn_connection_needs_password(VALUE self)
|
912
|
+
{
|
913
|
+
return PQconnectionNeedsPassword(get_pgconn(self)) ? Qtrue : Qfalse;
|
914
|
+
}
|
915
|
+
|
916
|
+
/*
|
917
|
+
* call-seq:
|
918
|
+
* conn.connection_used_password() -> Boolean
|
919
|
+
*
|
920
|
+
* Returns +true+ if the authentication method used
|
921
|
+
* a caller-supplied password, +false+ otherwise.
|
922
|
+
*/
|
923
|
+
static VALUE
|
924
|
+
pgconn_connection_used_password(VALUE self)
|
925
|
+
{
|
926
|
+
return PQconnectionUsedPassword(get_pgconn(self)) ? Qtrue : Qfalse;
|
927
|
+
}
|
928
|
+
|
929
|
+
|
930
|
+
//TODO get_ssl
|
931
|
+
|
932
|
+
|
933
|
+
/*
|
934
|
+
* call-seq:
|
935
|
+
* conn.exec(sql [, params, result_format ] ) -> PGresult
|
936
|
+
* conn.exec(sql [, params, result_format ] ) {|pg_result| block }
|
937
|
+
*
|
938
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL.
|
939
|
+
* Returns a PGresult instance on success.
|
940
|
+
* On failure, it raises a PGError exception.
|
941
|
+
*
|
942
|
+
* +params+ is an optional array of the bind parameters for the SQL query.
|
943
|
+
* Each element of the +params+ array may be either:
|
944
|
+
* a hash of the form:
|
945
|
+
* {:value => String (value of bind parameter)
|
946
|
+
* :type => Fixnum (oid of type of bind parameter)
|
947
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
948
|
+
* }
|
949
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
950
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
951
|
+
*
|
952
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
953
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
954
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
955
|
+
*
|
956
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
957
|
+
* Instead of specifying type oids, it's recommended to simply add
|
958
|
+
* explicit casts in the query to ensure that the right type is used.
|
959
|
+
*
|
960
|
+
* For example: "SELECT $1::int"
|
961
|
+
*
|
962
|
+
* The optional +result_format+ should be 0 for text results, 1
|
963
|
+
* for binary.
|
964
|
+
*
|
965
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
966
|
+
* and the PGresult object will automatically be cleared when the block terminates.
|
967
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
968
|
+
*/
|
969
|
+
static VALUE
|
970
|
+
pgconn_exec(int argc, VALUE *argv, VALUE self)
|
971
|
+
{
|
972
|
+
PGconn *conn = get_pgconn(self);
|
973
|
+
PGresult *result = NULL;
|
974
|
+
VALUE rb_pgresult;
|
975
|
+
VALUE command, params, in_res_fmt;
|
976
|
+
VALUE param, param_type, param_value, param_format;
|
977
|
+
VALUE param_value_tmp;
|
978
|
+
VALUE sym_type, sym_value, sym_format;
|
979
|
+
VALUE gc_array;
|
980
|
+
int i=0;
|
981
|
+
int nParams;
|
982
|
+
Oid *paramTypes;
|
983
|
+
char ** paramValues;
|
984
|
+
int *paramLengths;
|
985
|
+
int *paramFormats;
|
986
|
+
int resultFormat;
|
987
|
+
|
988
|
+
rb_scan_args(argc, argv, "12", &command, ¶ms, &in_res_fmt);
|
989
|
+
|
990
|
+
Check_Type(command, T_STRING);
|
991
|
+
|
992
|
+
/* If called with no parameters, use PQexec */
|
993
|
+
if(NIL_P(params)) {
|
994
|
+
result = PQexec(conn, StringValuePtr(command));
|
995
|
+
rb_pgresult = new_pgresult(result, conn);
|
996
|
+
pgresult_check(self, rb_pgresult);
|
997
|
+
if (rb_block_given_p()) {
|
998
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
999
|
+
pgresult_clear, rb_pgresult);
|
1000
|
+
}
|
1001
|
+
return rb_pgresult;
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
/* If called with parameters, and optionally result_format,
|
1005
|
+
* use PQexecParams
|
1006
|
+
*/
|
1007
|
+
Check_Type(params, T_ARRAY);
|
1008
|
+
|
1009
|
+
if(NIL_P(in_res_fmt)) {
|
1010
|
+
resultFormat = 0;
|
1011
|
+
}
|
1012
|
+
else {
|
1013
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1014
|
+
}
|
1015
|
+
|
1016
|
+
gc_array = rb_ary_new();
|
1017
|
+
rb_gc_register_address(&gc_array);
|
1018
|
+
sym_type = ID2SYM(rb_intern("type"));
|
1019
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1020
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1021
|
+
nParams = RARRAY_LEN(params);
|
1022
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1023
|
+
paramValues = ALLOC_N(char *, nParams);
|
1024
|
+
paramLengths = ALLOC_N(int, nParams);
|
1025
|
+
paramFormats = ALLOC_N(int, nParams);
|
1026
|
+
for(i = 0; i < nParams; i++) {
|
1027
|
+
param = rb_ary_entry(params, i);
|
1028
|
+
if (TYPE(param) == T_HASH) {
|
1029
|
+
param_type = rb_hash_aref(param, sym_type);
|
1030
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1031
|
+
if(param_value_tmp == Qnil)
|
1032
|
+
param_value = param_value_tmp;
|
1033
|
+
else
|
1034
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1035
|
+
param_format = rb_hash_aref(param, sym_format);
|
1036
|
+
}
|
1037
|
+
else {
|
1038
|
+
param_type = Qnil;
|
1039
|
+
if(param == Qnil)
|
1040
|
+
param_value = param;
|
1041
|
+
else
|
1042
|
+
param_value = rb_obj_as_string(param);
|
1043
|
+
param_format = Qnil;
|
1044
|
+
}
|
1045
|
+
|
1046
|
+
if(param_type == Qnil)
|
1047
|
+
paramTypes[i] = 0;
|
1048
|
+
else
|
1049
|
+
paramTypes[i] = NUM2INT(param_type);
|
1050
|
+
|
1051
|
+
if(param_value == Qnil) {
|
1052
|
+
paramValues[i] = NULL;
|
1053
|
+
paramLengths[i] = 0;
|
1054
|
+
}
|
1055
|
+
else {
|
1056
|
+
Check_Type(param_value, T_STRING);
|
1057
|
+
/* make sure param_value doesn't get freed by the GC */
|
1058
|
+
rb_ary_push(gc_array, param_value);
|
1059
|
+
paramValues[i] = StringValuePtr(param_value);
|
1060
|
+
paramLengths[i] = RSTRING_LEN(param_value);
|
1061
|
+
}
|
1062
|
+
|
1063
|
+
if(param_format == Qnil)
|
1064
|
+
paramFormats[i] = 0;
|
1065
|
+
else
|
1066
|
+
paramFormats[i] = NUM2INT(param_format);
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
result = PQexecParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1070
|
+
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1071
|
+
|
1072
|
+
rb_gc_unregister_address(&gc_array);
|
1073
|
+
|
1074
|
+
xfree(paramTypes);
|
1075
|
+
xfree(paramValues);
|
1076
|
+
xfree(paramLengths);
|
1077
|
+
xfree(paramFormats);
|
1078
|
+
|
1079
|
+
rb_pgresult = new_pgresult(result, conn);
|
1080
|
+
pgresult_check(self, rb_pgresult);
|
1081
|
+
if (rb_block_given_p()) {
|
1082
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1083
|
+
pgresult_clear, rb_pgresult);
|
1084
|
+
}
|
1085
|
+
return rb_pgresult;
|
1086
|
+
}
|
1087
|
+
|
1088
|
+
/*
|
1089
|
+
* call-seq:
|
1090
|
+
* conn.prepare(stmt_name, sql [, param_types ] ) -> PGresult
|
1091
|
+
*
|
1092
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
1093
|
+
* Returns a PGresult instance on success.
|
1094
|
+
* On failure, it raises a PGError exception.
|
1095
|
+
*
|
1096
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
1097
|
+
* types of the parameters.
|
1098
|
+
*
|
1099
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
1100
|
+
* Instead of specifying type oids, it's recommended to simply add
|
1101
|
+
* explicit casts in the query to ensure that the right type is used.
|
1102
|
+
*
|
1103
|
+
* For example: "SELECT $1::int"
|
1104
|
+
*
|
1105
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1106
|
+
* inside the SQL query.
|
1107
|
+
*/
|
1108
|
+
static VALUE
|
1109
|
+
pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
1110
|
+
{
|
1111
|
+
PGconn *conn = get_pgconn(self);
|
1112
|
+
PGresult *result = NULL;
|
1113
|
+
VALUE rb_pgresult;
|
1114
|
+
VALUE name, command, in_paramtypes;
|
1115
|
+
VALUE param;
|
1116
|
+
int i = 0;
|
1117
|
+
int nParams = 0;
|
1118
|
+
Oid *paramTypes = NULL;
|
1119
|
+
|
1120
|
+
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1121
|
+
Check_Type(name, T_STRING);
|
1122
|
+
Check_Type(command, T_STRING);
|
1123
|
+
|
1124
|
+
if(! NIL_P(in_paramtypes)) {
|
1125
|
+
Check_Type(in_paramtypes, T_ARRAY);
|
1126
|
+
nParams = RARRAY_LEN(in_paramtypes);
|
1127
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1128
|
+
for(i = 0; i < nParams; i++) {
|
1129
|
+
param = rb_ary_entry(in_paramtypes, i);
|
1130
|
+
Check_Type(param, T_FIXNUM);
|
1131
|
+
if(param == Qnil)
|
1132
|
+
paramTypes[i] = 0;
|
1133
|
+
else
|
1134
|
+
paramTypes[i] = NUM2INT(param);
|
1135
|
+
}
|
1136
|
+
}
|
1137
|
+
result = PQprepare(conn, StringValuePtr(name), StringValuePtr(command),
|
1138
|
+
nParams, paramTypes);
|
1139
|
+
|
1140
|
+
xfree(paramTypes);
|
1141
|
+
|
1142
|
+
rb_pgresult = new_pgresult(result, conn);
|
1143
|
+
pgresult_check(self, rb_pgresult);
|
1144
|
+
return rb_pgresult;
|
1145
|
+
}
|
1146
|
+
|
1147
|
+
/*
|
1148
|
+
* call-seq:
|
1149
|
+
* conn.exec_prepared(statement_name [, params, result_format ] ) -> PGresult
|
1150
|
+
* conn.exec_prepared(statement_name [, params, result_format ] ) {|pg_result| block }
|
1151
|
+
*
|
1152
|
+
* Execute prepared named statement specified by _statement_name_.
|
1153
|
+
* Returns a PGresult instance on success.
|
1154
|
+
* On failure, it raises a PGError exception.
|
1155
|
+
*
|
1156
|
+
* +params+ is an array of the optional bind parameters for the
|
1157
|
+
* SQL query. Each element of the +params+ array may be either:
|
1158
|
+
* a hash of the form:
|
1159
|
+
* {:value => String (value of bind parameter)
|
1160
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
1161
|
+
* }
|
1162
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1163
|
+
* { :value => <string value>, :format => 0 }
|
1164
|
+
*
|
1165
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1166
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
1167
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1168
|
+
*
|
1169
|
+
* The optional +result_format+ should be 0 for text results, 1
|
1170
|
+
* for binary.
|
1171
|
+
*
|
1172
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1173
|
+
* and the PGresult object will automatically be cleared when the block terminates.
|
1174
|
+
* In this instance, <code>conn.exec_prepared</code> returns the value of the block.
|
1175
|
+
*/
|
1176
|
+
static VALUE
|
1177
|
+
pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
1178
|
+
{
|
1179
|
+
PGconn *conn = get_pgconn(self);
|
1180
|
+
PGresult *result = NULL;
|
1181
|
+
VALUE rb_pgresult;
|
1182
|
+
VALUE name, params, in_res_fmt;
|
1183
|
+
VALUE param, param_value, param_format;
|
1184
|
+
VALUE param_value_tmp;
|
1185
|
+
VALUE sym_value, sym_format;
|
1186
|
+
VALUE gc_array;
|
1187
|
+
int i = 0;
|
1188
|
+
int nParams;
|
1189
|
+
char ** paramValues;
|
1190
|
+
int *paramLengths;
|
1191
|
+
int *paramFormats;
|
1192
|
+
int resultFormat;
|
1193
|
+
|
1194
|
+
|
1195
|
+
rb_scan_args(argc, argv, "12", &name, ¶ms, &in_res_fmt);
|
1196
|
+
Check_Type(name, T_STRING);
|
1197
|
+
|
1198
|
+
if(NIL_P(params)) {
|
1199
|
+
params = rb_ary_new2(0);
|
1200
|
+
resultFormat = 0;
|
1201
|
+
}
|
1202
|
+
else {
|
1203
|
+
Check_Type(params, T_ARRAY);
|
1204
|
+
}
|
1205
|
+
|
1206
|
+
if(NIL_P(in_res_fmt)) {
|
1207
|
+
resultFormat = 0;
|
1208
|
+
}
|
1209
|
+
else {
|
1210
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
gc_array = rb_ary_new();
|
1214
|
+
rb_gc_register_address(&gc_array);
|
1215
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1216
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1217
|
+
nParams = RARRAY_LEN(params);
|
1218
|
+
paramValues = ALLOC_N(char *, nParams);
|
1219
|
+
paramLengths = ALLOC_N(int, nParams);
|
1220
|
+
paramFormats = ALLOC_N(int, nParams);
|
1221
|
+
for(i = 0; i < nParams; i++) {
|
1222
|
+
param = rb_ary_entry(params, i);
|
1223
|
+
if (TYPE(param) == T_HASH) {
|
1224
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1225
|
+
if(param_value_tmp == Qnil)
|
1226
|
+
param_value = param_value_tmp;
|
1227
|
+
else
|
1228
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1229
|
+
param_format = rb_hash_aref(param, sym_format);
|
1230
|
+
}
|
1231
|
+
else {
|
1232
|
+
if(param == Qnil)
|
1233
|
+
param_value = param;
|
1234
|
+
else
|
1235
|
+
param_value = rb_obj_as_string(param);
|
1236
|
+
param_format = INT2NUM(0);
|
1237
|
+
}
|
1238
|
+
if(param_value == Qnil) {
|
1239
|
+
paramValues[i] = NULL;
|
1240
|
+
paramLengths[i] = 0;
|
1241
|
+
}
|
1242
|
+
else {
|
1243
|
+
Check_Type(param_value, T_STRING);
|
1244
|
+
/* make sure param_value doesn't get freed by the GC */
|
1245
|
+
rb_ary_push(gc_array, param_value);
|
1246
|
+
paramValues[i] = StringValuePtr(param_value);
|
1247
|
+
paramLengths[i] = RSTRING_LEN(param_value);
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
if(param_format == Qnil)
|
1251
|
+
paramFormats[i] = 0;
|
1252
|
+
else
|
1253
|
+
paramFormats[i] = NUM2INT(param_format);
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
result = PQexecPrepared(conn, StringValuePtr(name), nParams,
|
1257
|
+
(const char * const *)paramValues, paramLengths, paramFormats,
|
1258
|
+
resultFormat);
|
1259
|
+
|
1260
|
+
rb_gc_unregister_address(&gc_array);
|
1261
|
+
|
1262
|
+
xfree(paramValues);
|
1263
|
+
xfree(paramLengths);
|
1264
|
+
xfree(paramFormats);
|
1265
|
+
|
1266
|
+
rb_pgresult = new_pgresult(result, conn);
|
1267
|
+
pgresult_check(self, rb_pgresult);
|
1268
|
+
if (rb_block_given_p()) {
|
1269
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1270
|
+
pgresult_clear, rb_pgresult);
|
1271
|
+
}
|
1272
|
+
return rb_pgresult;
|
1273
|
+
}
|
1274
|
+
|
1275
|
+
/*
|
1276
|
+
* call-seq:
|
1277
|
+
* conn.describe_prepared( statement_name ) -> PGresult
|
1278
|
+
*
|
1279
|
+
* Retrieve information about the prepared statement
|
1280
|
+
* _statement_name_.
|
1281
|
+
*/
|
1282
|
+
static VALUE
|
1283
|
+
pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
1284
|
+
{
|
1285
|
+
PGresult *result;
|
1286
|
+
VALUE rb_pgresult;
|
1287
|
+
PGconn *conn = get_pgconn(self);
|
1288
|
+
char *stmt;
|
1289
|
+
if(stmt_name == Qnil) {
|
1290
|
+
stmt = NULL;
|
1291
|
+
}
|
1292
|
+
else {
|
1293
|
+
Check_Type(stmt_name, T_STRING);
|
1294
|
+
stmt = StringValuePtr(stmt_name);
|
1295
|
+
}
|
1296
|
+
result = PQdescribePrepared(conn, stmt);
|
1297
|
+
rb_pgresult = new_pgresult(result, conn);
|
1298
|
+
pgresult_check(self, rb_pgresult);
|
1299
|
+
return rb_pgresult;
|
1300
|
+
}
|
1301
|
+
|
1302
|
+
|
1303
|
+
/*
|
1304
|
+
* call-seq:
|
1305
|
+
* conn.describe_portal( portal_name ) -> PGresult
|
1306
|
+
*
|
1307
|
+
* Retrieve information about the portal _portal_name_.
|
1308
|
+
*/
|
1309
|
+
static VALUE
|
1310
|
+
pgconn_describe_portal(self, stmt_name)
|
1311
|
+
VALUE self, stmt_name;
|
1312
|
+
{
|
1313
|
+
PGresult *result;
|
1314
|
+
VALUE rb_pgresult;
|
1315
|
+
PGconn *conn = get_pgconn(self);
|
1316
|
+
char *stmt;
|
1317
|
+
if(stmt_name == Qnil) {
|
1318
|
+
stmt = NULL;
|
1319
|
+
}
|
1320
|
+
else {
|
1321
|
+
Check_Type(stmt_name, T_STRING);
|
1322
|
+
stmt = StringValuePtr(stmt_name);
|
1323
|
+
}
|
1324
|
+
result = PQdescribePortal(conn, stmt);
|
1325
|
+
rb_pgresult = new_pgresult(result, conn);
|
1326
|
+
pgresult_check(self, rb_pgresult);
|
1327
|
+
return rb_pgresult;
|
1328
|
+
}
|
1329
|
+
|
1330
|
+
|
1331
|
+
/*
|
1332
|
+
* call-seq:
|
1333
|
+
* conn.make_empty_pgresult( status ) -> PGresult
|
1334
|
+
*
|
1335
|
+
* Constructs and empty PGresult with status _status_.
|
1336
|
+
* _status_ may be one of:
|
1337
|
+
* * +PGRES_EMPTY_QUERY+
|
1338
|
+
* * +PGRES_COMMAND_OK+
|
1339
|
+
* * +PGRES_TUPLES_OK+
|
1340
|
+
* * +PGRES_COPY_OUT+
|
1341
|
+
* * +PGRES_COPY_IN+
|
1342
|
+
* * +PGRES_BAD_RESPONSE+
|
1343
|
+
* * +PGRES_NONFATAL_ERROR+
|
1344
|
+
* * +PGRES_FATAL_ERROR+
|
1345
|
+
*/
|
1346
|
+
static VALUE
|
1347
|
+
pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
1348
|
+
{
|
1349
|
+
PGresult *result;
|
1350
|
+
VALUE rb_pgresult;
|
1351
|
+
PGconn *conn = get_pgconn(self);
|
1352
|
+
result = PQmakeEmptyPGresult(conn, NUM2INT(status));
|
1353
|
+
rb_pgresult = new_pgresult(result, conn);
|
1354
|
+
pgresult_check(self, rb_pgresult);
|
1355
|
+
return rb_pgresult;
|
1356
|
+
}
|
1357
|
+
|
1358
|
+
|
1359
|
+
/*
|
1360
|
+
* call-seq:
|
1361
|
+
* conn.escape_string( str ) -> String
|
1362
|
+
* PGconn.escape_string( str ) -> String # DEPRECATED
|
1363
|
+
*
|
1364
|
+
* Connection instance method for versions of 8.1 and higher of libpq
|
1365
|
+
* uses PQescapeStringConn, which is safer. Avoid calling as a class method,
|
1366
|
+
* the class method uses the deprecated PQescapeString() API function.
|
1367
|
+
*
|
1368
|
+
* Returns a SQL-safe version of the String _str_.
|
1369
|
+
* This is the preferred way to make strings safe for inclusion in
|
1370
|
+
* SQL queries.
|
1371
|
+
*
|
1372
|
+
* Consider using exec_params, which avoids the need for passing values
|
1373
|
+
* inside of SQL commands.
|
1374
|
+
*
|
1375
|
+
* Encoding of escaped string will be equal to client encoding of connection.
|
1376
|
+
*/
|
1377
|
+
static VALUE
|
1378
|
+
pgconn_s_escape(VALUE self, VALUE string)
|
1379
|
+
{
|
1380
|
+
char *escaped;
|
1381
|
+
int size,error;
|
1382
|
+
VALUE result;
|
1383
|
+
#ifdef M17N_SUPPORTED
|
1384
|
+
rb_encoding* enc;
|
1385
|
+
#endif
|
1386
|
+
|
1387
|
+
Check_Type(string, T_STRING);
|
1388
|
+
|
1389
|
+
escaped = ALLOC_N(char, RSTRING_LEN(string) * 2 + 1);
|
1390
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1391
|
+
size = PQescapeStringConn(get_pgconn(self), escaped,
|
1392
|
+
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1393
|
+
if(error) {
|
1394
|
+
xfree(escaped);
|
1395
|
+
rb_raise(rb_ePGError, "%s", PQerrorMessage(get_pgconn(self)));
|
1396
|
+
}
|
1397
|
+
} else {
|
1398
|
+
size = PQescapeString(escaped, RSTRING_PTR(string),
|
1399
|
+
RSTRING_LEN(string));
|
1400
|
+
}
|
1401
|
+
result = rb_str_new(escaped, size);
|
1402
|
+
xfree(escaped);
|
1403
|
+
OBJ_INFECT(result, string);
|
1404
|
+
|
1405
|
+
#ifdef M17N_SUPPORTED
|
1406
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1407
|
+
enc = pgconn_get_client_encoding_as_rb_encoding(get_pgconn(self));
|
1408
|
+
} else {
|
1409
|
+
enc = rb_enc_get(string);
|
1410
|
+
}
|
1411
|
+
rb_enc_associate(result, enc);
|
1412
|
+
#endif
|
1413
|
+
|
1414
|
+
return result;
|
1415
|
+
}
|
1416
|
+
|
1417
|
+
/*
|
1418
|
+
* call-seq:
|
1419
|
+
* conn.escape_bytea( string ) -> String
|
1420
|
+
* PGconn.escape_bytea( string ) -> String # DEPRECATED
|
1421
|
+
*
|
1422
|
+
* Connection instance method for versions of 8.1 and higher of libpq
|
1423
|
+
* uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
|
1424
|
+
* the class method uses the deprecated PQescapeBytea() API function.
|
1425
|
+
*
|
1426
|
+
* Use the instance method version of this function, it is safer than the
|
1427
|
+
* class method.
|
1428
|
+
*
|
1429
|
+
* Escapes binary data for use within an SQL command with the type +bytea+.
|
1430
|
+
*
|
1431
|
+
* Certain byte values must be escaped (but all byte values may be escaped)
|
1432
|
+
* when used as part of a +bytea+ literal in an SQL statement. In general, to
|
1433
|
+
* escape a byte, it is converted into the three digit octal number equal to
|
1434
|
+
* the octet value, and preceded by two backslashes. The single quote (') and
|
1435
|
+
* backslash (\) characters have special alternative escape sequences.
|
1436
|
+
* #escape_bytea performs this operation, escaping only the minimally required
|
1437
|
+
* bytes.
|
1438
|
+
*
|
1439
|
+
* Consider using exec_params, which avoids the need for passing values inside of
|
1440
|
+
* SQL commands.
|
1441
|
+
*/
|
1442
|
+
static VALUE
|
1443
|
+
pgconn_s_escape_bytea(VALUE self, VALUE str)
|
1444
|
+
{
|
1445
|
+
unsigned char *from, *to;
|
1446
|
+
size_t from_len, to_len;
|
1447
|
+
VALUE ret;
|
1448
|
+
|
1449
|
+
Check_Type(str, T_STRING);
|
1450
|
+
from = (unsigned char*)RSTRING_PTR(str);
|
1451
|
+
from_len = RSTRING_LEN(str);
|
1452
|
+
|
1453
|
+
if(rb_obj_class(self) == rb_cPGconn) {
|
1454
|
+
to = PQescapeByteaConn(get_pgconn(self), from, from_len, &to_len);
|
1455
|
+
} else {
|
1456
|
+
to = PQescapeBytea( from, from_len, &to_len);
|
1457
|
+
}
|
1458
|
+
|
1459
|
+
ret = rb_str_new((char*)to, to_len - 1);
|
1460
|
+
OBJ_INFECT(ret, str);
|
1461
|
+
PQfreemem(to);
|
1462
|
+
return ret;
|
1463
|
+
}
|
1464
|
+
|
1465
|
+
|
1466
|
+
/*
|
1467
|
+
* call-seq:
|
1468
|
+
* PGconn.unescape_bytea( string )
|
1469
|
+
*
|
1470
|
+
* Converts an escaped string representation of binary data into binary data --- the
|
1471
|
+
* reverse of #escape_bytea. This is needed when retrieving +bytea+ data in text format,
|
1472
|
+
* but not when retrieving it in binary format.
|
1473
|
+
*
|
1474
|
+
*/
|
1475
|
+
static VALUE
|
1476
|
+
pgconn_s_unescape_bytea(VALUE self, VALUE str)
|
1477
|
+
{
|
1478
|
+
unsigned char *from, *to;
|
1479
|
+
size_t to_len;
|
1480
|
+
VALUE ret;
|
1481
|
+
|
1482
|
+
Check_Type(str, T_STRING);
|
1483
|
+
from = (unsigned char*)StringValuePtr(str);
|
1484
|
+
|
1485
|
+
to = PQunescapeBytea(from, &to_len);
|
1486
|
+
|
1487
|
+
ret = rb_str_new((char*)to, to_len);
|
1488
|
+
OBJ_INFECT(ret, str);
|
1489
|
+
PQfreemem(to);
|
1490
|
+
return ret;
|
1491
|
+
}
|
1492
|
+
|
1493
|
+
/*
|
1494
|
+
* call-seq:
|
1495
|
+
* conn.send_query(sql [, params, result_format ] ) -> nil
|
1496
|
+
*
|
1497
|
+
* Sends SQL query request specified by _sql_ to PostgreSQL for
|
1498
|
+
* asynchronous processing, and immediately returns.
|
1499
|
+
* On failure, it raises a PGError exception.
|
1500
|
+
*
|
1501
|
+
* +params+ is an optional array of the bind parameters for the SQL query.
|
1502
|
+
* Each element of the +params+ array may be either:
|
1503
|
+
* a hash of the form:
|
1504
|
+
* {:value => String (value of bind parameter)
|
1505
|
+
* :type => Fixnum (oid of type of bind parameter)
|
1506
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
1507
|
+
* }
|
1508
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1509
|
+
* { :value => <string value>, :type => 0, :format => 0 }
|
1510
|
+
*
|
1511
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1512
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
1513
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1514
|
+
*
|
1515
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
1516
|
+
* Instead of specifying type oids, it's recommended to simply add
|
1517
|
+
* explicit casts in the query to ensure that the right type is used.
|
1518
|
+
*
|
1519
|
+
* For example: "SELECT $1::int"
|
1520
|
+
*
|
1521
|
+
* The optional +result_format+ should be 0 for text results, 1
|
1522
|
+
* for binary.
|
1523
|
+
*/
|
1524
|
+
static VALUE
|
1525
|
+
pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
1526
|
+
{
|
1527
|
+
PGconn *conn = get_pgconn(self);
|
1528
|
+
int result;
|
1529
|
+
VALUE command, params, in_res_fmt;
|
1530
|
+
VALUE param, param_type, param_value, param_format;
|
1531
|
+
VALUE param_value_tmp;
|
1532
|
+
VALUE sym_type, sym_value, sym_format;
|
1533
|
+
VALUE gc_array;
|
1534
|
+
VALUE error;
|
1535
|
+
int i=0;
|
1536
|
+
int nParams;
|
1537
|
+
Oid *paramTypes;
|
1538
|
+
char ** paramValues;
|
1539
|
+
int *paramLengths;
|
1540
|
+
int *paramFormats;
|
1541
|
+
int resultFormat;
|
1542
|
+
|
1543
|
+
rb_scan_args(argc, argv, "12", &command, ¶ms, &in_res_fmt);
|
1544
|
+
Check_Type(command, T_STRING);
|
1545
|
+
|
1546
|
+
/* If called with no parameters, use PQsendQuery */
|
1547
|
+
if(NIL_P(params)) {
|
1548
|
+
if(PQsendQuery(conn,StringValuePtr(command)) == 0) {
|
1549
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1550
|
+
rb_iv_set(error, "@connection", self);
|
1551
|
+
rb_exc_raise(error);
|
1552
|
+
}
|
1553
|
+
return Qnil;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
/* If called with parameters, and optionally result_format,
|
1557
|
+
* use PQsendQueryParams
|
1558
|
+
*/
|
1559
|
+
Check_Type(params, T_ARRAY);
|
1560
|
+
|
1561
|
+
if(NIL_P(in_res_fmt)) {
|
1562
|
+
resultFormat = 0;
|
1563
|
+
}
|
1564
|
+
else {
|
1565
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1566
|
+
}
|
1567
|
+
|
1568
|
+
gc_array = rb_ary_new();
|
1569
|
+
rb_gc_register_address(&gc_array);
|
1570
|
+
sym_type = ID2SYM(rb_intern("type"));
|
1571
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1572
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1573
|
+
nParams = RARRAY_LEN(params);
|
1574
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1575
|
+
paramValues = ALLOC_N(char *, nParams);
|
1576
|
+
paramLengths = ALLOC_N(int, nParams);
|
1577
|
+
paramFormats = ALLOC_N(int, nParams);
|
1578
|
+
for(i = 0; i < nParams; i++) {
|
1579
|
+
param = rb_ary_entry(params, i);
|
1580
|
+
if (TYPE(param) == T_HASH) {
|
1581
|
+
param_type = rb_hash_aref(param, sym_type);
|
1582
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1583
|
+
if(param_value_tmp == Qnil)
|
1584
|
+
param_value = param_value_tmp;
|
1585
|
+
else
|
1586
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1587
|
+
param_format = rb_hash_aref(param, sym_format);
|
1588
|
+
}
|
1589
|
+
else {
|
1590
|
+
param_type = INT2NUM(0);
|
1591
|
+
if(param == Qnil)
|
1592
|
+
param_value = param;
|
1593
|
+
else
|
1594
|
+
param_value = rb_obj_as_string(param);
|
1595
|
+
param_format = INT2NUM(0);
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
if(param_type == Qnil)
|
1599
|
+
paramTypes[i] = 0;
|
1600
|
+
else
|
1601
|
+
paramTypes[i] = NUM2INT(param_type);
|
1602
|
+
|
1603
|
+
if(param_value == Qnil) {
|
1604
|
+
paramValues[i] = NULL;
|
1605
|
+
paramLengths[i] = 0;
|
1606
|
+
}
|
1607
|
+
else {
|
1608
|
+
Check_Type(param_value, T_STRING);
|
1609
|
+
/* make sure param_value doesn't get freed by the GC */
|
1610
|
+
rb_ary_push(gc_array, param_value);
|
1611
|
+
paramValues[i] = StringValuePtr(param_value);
|
1612
|
+
paramLengths[i] = RSTRING_LEN(param_value);
|
1613
|
+
}
|
1614
|
+
|
1615
|
+
if(param_format == Qnil)
|
1616
|
+
paramFormats[i] = 0;
|
1617
|
+
else
|
1618
|
+
paramFormats[i] = NUM2INT(param_format);
|
1619
|
+
}
|
1620
|
+
|
1621
|
+
result = PQsendQueryParams(conn, StringValuePtr(command), nParams, paramTypes,
|
1622
|
+
(const char * const *)paramValues, paramLengths, paramFormats, resultFormat);
|
1623
|
+
|
1624
|
+
rb_gc_unregister_address(&gc_array);
|
1625
|
+
|
1626
|
+
xfree(paramTypes);
|
1627
|
+
xfree(paramValues);
|
1628
|
+
xfree(paramLengths);
|
1629
|
+
xfree(paramFormats);
|
1630
|
+
|
1631
|
+
if(result == 0) {
|
1632
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1633
|
+
rb_iv_set(error, "@connection", self);
|
1634
|
+
rb_exc_raise(error);
|
1635
|
+
}
|
1636
|
+
return Qnil;
|
1637
|
+
}
|
1638
|
+
|
1639
|
+
/*
|
1640
|
+
* call-seq:
|
1641
|
+
* conn.send_prepare( stmt_name, sql [, param_types ] ) -> nil
|
1642
|
+
*
|
1643
|
+
* Prepares statement _sql_ with name _name_ to be executed later.
|
1644
|
+
* Sends prepare command asynchronously, and returns immediately.
|
1645
|
+
* On failure, it raises a PGError exception.
|
1646
|
+
*
|
1647
|
+
* +param_types+ is an optional parameter to specify the Oids of the
|
1648
|
+
* types of the parameters.
|
1649
|
+
*
|
1650
|
+
* If the types are not specified, they will be inferred by PostgreSQL.
|
1651
|
+
* Instead of specifying type oids, it's recommended to simply add
|
1652
|
+
* explicit casts in the query to ensure that the right type is used.
|
1653
|
+
*
|
1654
|
+
* For example: "SELECT $1::int"
|
1655
|
+
*
|
1656
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1657
|
+
* inside the SQL query.
|
1658
|
+
*/
|
1659
|
+
static VALUE
|
1660
|
+
pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
1661
|
+
{
|
1662
|
+
PGconn *conn = get_pgconn(self);
|
1663
|
+
int result;
|
1664
|
+
VALUE name, command, in_paramtypes;
|
1665
|
+
VALUE param;
|
1666
|
+
VALUE error;
|
1667
|
+
int i = 0;
|
1668
|
+
int nParams = 0;
|
1669
|
+
Oid *paramTypes = NULL;
|
1670
|
+
|
1671
|
+
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1672
|
+
Check_Type(name, T_STRING);
|
1673
|
+
Check_Type(command, T_STRING);
|
1674
|
+
|
1675
|
+
if(! NIL_P(in_paramtypes)) {
|
1676
|
+
Check_Type(in_paramtypes, T_ARRAY);
|
1677
|
+
nParams = RARRAY_LEN(in_paramtypes);
|
1678
|
+
paramTypes = ALLOC_N(Oid, nParams);
|
1679
|
+
for(i = 0; i < nParams; i++) {
|
1680
|
+
param = rb_ary_entry(in_paramtypes, i);
|
1681
|
+
Check_Type(param, T_FIXNUM);
|
1682
|
+
if(param == Qnil)
|
1683
|
+
paramTypes[i] = 0;
|
1684
|
+
else
|
1685
|
+
paramTypes[i] = NUM2INT(param);
|
1686
|
+
}
|
1687
|
+
}
|
1688
|
+
result = PQsendPrepare(conn, StringValuePtr(name), StringValuePtr(command),
|
1689
|
+
nParams, paramTypes);
|
1690
|
+
|
1691
|
+
xfree(paramTypes);
|
1692
|
+
|
1693
|
+
if(result == 0) {
|
1694
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1695
|
+
rb_iv_set(error, "@connection", self);
|
1696
|
+
rb_exc_raise(error);
|
1697
|
+
}
|
1698
|
+
return Qnil;
|
1699
|
+
}
|
1700
|
+
|
1701
|
+
/*
|
1702
|
+
* call-seq:
|
1703
|
+
* conn.send_query_prepared( statement_name [, params, result_format ] )
|
1704
|
+
* -> nil
|
1705
|
+
*
|
1706
|
+
* Execute prepared named statement specified by _statement_name_
|
1707
|
+
* asynchronously, and returns immediately.
|
1708
|
+
* On failure, it raises a PGError exception.
|
1709
|
+
*
|
1710
|
+
* +params+ is an array of the optional bind parameters for the
|
1711
|
+
* SQL query. Each element of the +params+ array may be either:
|
1712
|
+
* a hash of the form:
|
1713
|
+
* {:value => String (value of bind parameter)
|
1714
|
+
* :format => Fixnum (0 for text, 1 for binary)
|
1715
|
+
* }
|
1716
|
+
* or, it may be a String. If it is a string, that is equivalent to the hash:
|
1717
|
+
* { :value => <string value>, :format => 0 }
|
1718
|
+
*
|
1719
|
+
* PostgreSQL bind parameters are represented as $1, $1, $2, etc.,
|
1720
|
+
* inside the SQL query. The 0th element of the +params+ array is bound
|
1721
|
+
* to $1, the 1st element is bound to $2, etc. +nil+ is treated as +NULL+.
|
1722
|
+
*
|
1723
|
+
* The optional +result_format+ should be 0 for text results, 1
|
1724
|
+
* for binary.
|
1725
|
+
*/
|
1726
|
+
static VALUE
|
1727
|
+
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
1728
|
+
{
|
1729
|
+
PGconn *conn = get_pgconn(self);
|
1730
|
+
int result;
|
1731
|
+
VALUE name, params, in_res_fmt;
|
1732
|
+
VALUE param, param_value, param_format;
|
1733
|
+
VALUE param_value_tmp;
|
1734
|
+
VALUE sym_value, sym_format;
|
1735
|
+
VALUE gc_array;
|
1736
|
+
VALUE error;
|
1737
|
+
int i = 0;
|
1738
|
+
int nParams;
|
1739
|
+
char ** paramValues;
|
1740
|
+
int *paramLengths;
|
1741
|
+
int *paramFormats;
|
1742
|
+
int resultFormat;
|
1743
|
+
|
1744
|
+
rb_scan_args(argc, argv, "12", &name, ¶ms, &in_res_fmt);
|
1745
|
+
Check_Type(name, T_STRING);
|
1746
|
+
|
1747
|
+
if(NIL_P(params)) {
|
1748
|
+
params = rb_ary_new2(0);
|
1749
|
+
resultFormat = 0;
|
1750
|
+
}
|
1751
|
+
else {
|
1752
|
+
Check_Type(params, T_ARRAY);
|
1753
|
+
}
|
1754
|
+
|
1755
|
+
if(NIL_P(in_res_fmt)) {
|
1756
|
+
resultFormat = 0;
|
1757
|
+
}
|
1758
|
+
else {
|
1759
|
+
resultFormat = NUM2INT(in_res_fmt);
|
1760
|
+
}
|
1761
|
+
|
1762
|
+
gc_array = rb_ary_new();
|
1763
|
+
rb_gc_register_address(&gc_array);
|
1764
|
+
sym_value = ID2SYM(rb_intern("value"));
|
1765
|
+
sym_format = ID2SYM(rb_intern("format"));
|
1766
|
+
nParams = RARRAY_LEN(params);
|
1767
|
+
paramValues = ALLOC_N(char *, nParams);
|
1768
|
+
paramLengths = ALLOC_N(int, nParams);
|
1769
|
+
paramFormats = ALLOC_N(int, nParams);
|
1770
|
+
for(i = 0; i < nParams; i++) {
|
1771
|
+
param = rb_ary_entry(params, i);
|
1772
|
+
if (TYPE(param) == T_HASH) {
|
1773
|
+
param_value_tmp = rb_hash_aref(param, sym_value);
|
1774
|
+
if(param_value_tmp == Qnil)
|
1775
|
+
param_value = param_value_tmp;
|
1776
|
+
else
|
1777
|
+
param_value = rb_obj_as_string(param_value_tmp);
|
1778
|
+
param_format = rb_hash_aref(param, sym_format);
|
1779
|
+
}
|
1780
|
+
else {
|
1781
|
+
if(param == Qnil)
|
1782
|
+
param_value = param;
|
1783
|
+
else
|
1784
|
+
param_value = rb_obj_as_string(param);
|
1785
|
+
param_format = INT2NUM(0);
|
1786
|
+
}
|
1787
|
+
|
1788
|
+
if(param_value == Qnil) {
|
1789
|
+
paramValues[i] = NULL;
|
1790
|
+
paramLengths[i] = 0;
|
1791
|
+
}
|
1792
|
+
else {
|
1793
|
+
Check_Type(param_value, T_STRING);
|
1794
|
+
/* make sure param_value doesn't get freed by the GC */
|
1795
|
+
rb_ary_push(gc_array, param_value);
|
1796
|
+
paramValues[i] = StringValuePtr(param_value);
|
1797
|
+
paramLengths[i] = RSTRING_LEN(param_value);
|
1798
|
+
}
|
1799
|
+
|
1800
|
+
if(param_format == Qnil)
|
1801
|
+
paramFormats[i] = 0;
|
1802
|
+
else
|
1803
|
+
paramFormats[i] = NUM2INT(param_format);
|
1804
|
+
}
|
1805
|
+
|
1806
|
+
result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
|
1807
|
+
(const char * const *)paramValues, paramLengths, paramFormats,
|
1808
|
+
resultFormat);
|
1809
|
+
|
1810
|
+
rb_gc_unregister_address(&gc_array);
|
1811
|
+
|
1812
|
+
xfree(paramValues);
|
1813
|
+
xfree(paramLengths);
|
1814
|
+
xfree(paramFormats);
|
1815
|
+
|
1816
|
+
if(result == 0) {
|
1817
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1818
|
+
rb_iv_set(error, "@connection", self);
|
1819
|
+
rb_exc_raise(error);
|
1820
|
+
}
|
1821
|
+
return Qnil;
|
1822
|
+
}
|
1823
|
+
|
1824
|
+
/*
|
1825
|
+
* call-seq:
|
1826
|
+
* conn.send_describe_prepared( statement_name ) -> nil
|
1827
|
+
*
|
1828
|
+
* Asynchronously send _command_ to the server. Does not block.
|
1829
|
+
* Use in combination with +conn.get_result+.
|
1830
|
+
*/
|
1831
|
+
static VALUE
|
1832
|
+
pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
1833
|
+
{
|
1834
|
+
VALUE error;
|
1835
|
+
PGconn *conn = get_pgconn(self);
|
1836
|
+
/* returns 0 on failure */
|
1837
|
+
if(PQsendDescribePrepared(conn,StringValuePtr(stmt_name)) == 0) {
|
1838
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1839
|
+
rb_iv_set(error, "@connection", self);
|
1840
|
+
rb_exc_raise(error);
|
1841
|
+
}
|
1842
|
+
return Qnil;
|
1843
|
+
}
|
1844
|
+
|
1845
|
+
|
1846
|
+
/*
|
1847
|
+
* call-seq:
|
1848
|
+
* conn.send_describe_portal( portal_name ) -> nil
|
1849
|
+
*
|
1850
|
+
* Asynchronously send _command_ to the server. Does not block.
|
1851
|
+
* Use in combination with +conn.get_result+.
|
1852
|
+
*/
|
1853
|
+
static VALUE
|
1854
|
+
pgconn_send_describe_portal(VALUE self, VALUE portal)
|
1855
|
+
{
|
1856
|
+
VALUE error;
|
1857
|
+
PGconn *conn = get_pgconn(self);
|
1858
|
+
/* returns 0 on failure */
|
1859
|
+
if(PQsendDescribePortal(conn,StringValuePtr(portal)) == 0) {
|
1860
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1861
|
+
rb_iv_set(error, "@connection", self);
|
1862
|
+
rb_exc_raise(error);
|
1863
|
+
}
|
1864
|
+
return Qnil;
|
1865
|
+
}
|
1866
|
+
|
1867
|
+
|
1868
|
+
/*
|
1869
|
+
* call-seq:
|
1870
|
+
* conn.get_result() -> PGresult
|
1871
|
+
* conn.get_result() {|pg_result| block }
|
1872
|
+
*
|
1873
|
+
* Blocks waiting for the next result from a call to
|
1874
|
+
* +PGconn#send_query+ (or another asynchronous command), and returns
|
1875
|
+
* it. Returns +nil+ if no more results are available.
|
1876
|
+
*
|
1877
|
+
* Note: call this function repeatedly until it returns +nil+, or else
|
1878
|
+
* you will not be able to issue further commands.
|
1879
|
+
*
|
1880
|
+
* If the optional code block is given, it will be passed <i>result</i> as an argument,
|
1881
|
+
* and the PGresult object will automatically be cleared when the block terminates.
|
1882
|
+
* In this instance, <code>conn.exec</code> returns the value of the block.
|
1883
|
+
*/
|
1884
|
+
static VALUE
|
1885
|
+
pgconn_get_result(VALUE self)
|
1886
|
+
{
|
1887
|
+
PGconn *conn = get_pgconn(self);
|
1888
|
+
PGresult *result;
|
1889
|
+
VALUE rb_pgresult;
|
1890
|
+
|
1891
|
+
result = PQgetResult(conn);
|
1892
|
+
if(result == NULL)
|
1893
|
+
return Qnil;
|
1894
|
+
rb_pgresult = new_pgresult(result, conn);
|
1895
|
+
if (rb_block_given_p()) {
|
1896
|
+
return rb_ensure(rb_yield, rb_pgresult,
|
1897
|
+
pgresult_clear, rb_pgresult);
|
1898
|
+
}
|
1899
|
+
return rb_pgresult;
|
1900
|
+
}
|
1901
|
+
|
1902
|
+
/*
|
1903
|
+
* call-seq:
|
1904
|
+
* conn.consume_input()
|
1905
|
+
*
|
1906
|
+
* If input is available from the server, consume it.
|
1907
|
+
* After calling +consume_input+, you can check +is_busy+
|
1908
|
+
* or *notifies* to see if the state has changed.
|
1909
|
+
*/
|
1910
|
+
static VALUE
|
1911
|
+
pgconn_consume_input(self)
|
1912
|
+
VALUE self;
|
1913
|
+
{
|
1914
|
+
VALUE error;
|
1915
|
+
PGconn *conn = get_pgconn(self);
|
1916
|
+
/* returns 0 on error */
|
1917
|
+
if(PQconsumeInput(conn) == 0) {
|
1918
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1919
|
+
rb_iv_set(error, "@connection", self);
|
1920
|
+
rb_exc_raise(error);
|
1921
|
+
}
|
1922
|
+
return Qnil;
|
1923
|
+
}
|
1924
|
+
|
1925
|
+
/*
|
1926
|
+
* call-seq:
|
1927
|
+
* conn.is_busy() -> Boolean
|
1928
|
+
*
|
1929
|
+
* Returns +true+ if a command is busy, that is, if
|
1930
|
+
* PQgetResult would block. Otherwise returns +false+.
|
1931
|
+
*/
|
1932
|
+
static VALUE
|
1933
|
+
pgconn_is_busy(self)
|
1934
|
+
VALUE self;
|
1935
|
+
{
|
1936
|
+
return PQisBusy(get_pgconn(self)) ? Qtrue : Qfalse;
|
1937
|
+
}
|
1938
|
+
|
1939
|
+
/*
|
1940
|
+
* call-seq:
|
1941
|
+
* conn.setnonblocking(Boolean) -> nil
|
1942
|
+
*
|
1943
|
+
* Sets the nonblocking status of the connection.
|
1944
|
+
* In the blocking state, calls to PGconn#send_query
|
1945
|
+
* will block until the message is sent to the server,
|
1946
|
+
* but will not wait for the query results.
|
1947
|
+
* In the nonblocking state, calls to PGconn#send_query
|
1948
|
+
* will return an error if the socket is not ready for
|
1949
|
+
* writing.
|
1950
|
+
* Note: This function does not affect PGconn#exec, because
|
1951
|
+
* that function doesn't return until the server has
|
1952
|
+
* processed the query and returned the results.
|
1953
|
+
* Returns +nil+.
|
1954
|
+
*/
|
1955
|
+
static VALUE
|
1956
|
+
pgconn_setnonblocking(self, state)
|
1957
|
+
VALUE self, state;
|
1958
|
+
{
|
1959
|
+
int arg;
|
1960
|
+
VALUE error;
|
1961
|
+
PGconn *conn = get_pgconn(self);
|
1962
|
+
if(state == Qtrue)
|
1963
|
+
arg = 1;
|
1964
|
+
else if (state == Qfalse)
|
1965
|
+
arg = 0;
|
1966
|
+
else
|
1967
|
+
rb_raise(rb_eArgError, "Boolean value expected");
|
1968
|
+
|
1969
|
+
if(PQsetnonblocking(conn, arg) == -1) {
|
1970
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
1971
|
+
rb_iv_set(error, "@connection", self);
|
1972
|
+
rb_exc_raise(error);
|
1973
|
+
}
|
1974
|
+
return Qnil;
|
1975
|
+
}
|
1976
|
+
|
1977
|
+
|
1978
|
+
/*
|
1979
|
+
* call-seq:
|
1980
|
+
* conn.isnonblocking() -> Boolean
|
1981
|
+
*
|
1982
|
+
* Returns +true+ if a command is busy, that is, if
|
1983
|
+
* PQgetResult would block. Otherwise returns +false+.
|
1984
|
+
*/
|
1985
|
+
static VALUE
|
1986
|
+
pgconn_isnonblocking(self)
|
1987
|
+
VALUE self;
|
1988
|
+
{
|
1989
|
+
return PQisnonblocking(get_pgconn(self)) ? Qtrue : Qfalse;
|
1990
|
+
}
|
1991
|
+
|
1992
|
+
/*
|
1993
|
+
* call-seq:
|
1994
|
+
* conn.flush() -> Boolean
|
1995
|
+
*
|
1996
|
+
* Attempts to flush any queued output data to the server.
|
1997
|
+
* Returns +true+ if data is successfully flushed, +false+
|
1998
|
+
* if not (can only return +false+ if connection is
|
1999
|
+
* nonblocking.
|
2000
|
+
* Raises PGError exception if some other failure occurred.
|
2001
|
+
*/
|
2002
|
+
static VALUE
|
2003
|
+
pgconn_flush(self)
|
2004
|
+
VALUE self;
|
2005
|
+
{
|
2006
|
+
PGconn *conn = get_pgconn(self);
|
2007
|
+
int ret;
|
2008
|
+
VALUE error;
|
2009
|
+
ret = PQflush(conn);
|
2010
|
+
if(ret == -1) {
|
2011
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
2012
|
+
rb_iv_set(error, "@connection", self);
|
2013
|
+
rb_exc_raise(error);
|
2014
|
+
}
|
2015
|
+
return (ret) ? Qfalse : Qtrue;
|
2016
|
+
}
|
2017
|
+
|
2018
|
+
/*
|
2019
|
+
* call-seq:
|
2020
|
+
* conn.cancel() -> String
|
2021
|
+
*
|
2022
|
+
* Requests cancellation of the command currently being
|
2023
|
+
* processed.
|
2024
|
+
*
|
2025
|
+
* Returns +nil+ on success, or a string containing the
|
2026
|
+
* error message if a failure occurs.
|
2027
|
+
*/
|
2028
|
+
static VALUE
|
2029
|
+
pgconn_cancel(VALUE self)
|
2030
|
+
{
|
2031
|
+
char errbuf[256];
|
2032
|
+
PGcancel *cancel;
|
2033
|
+
VALUE retval;
|
2034
|
+
int ret;
|
2035
|
+
|
2036
|
+
cancel = PQgetCancel(get_pgconn(self));
|
2037
|
+
if(cancel == NULL)
|
2038
|
+
rb_raise(rb_ePGError,"Invalid connection!");
|
2039
|
+
|
2040
|
+
ret = PQcancel(cancel, errbuf, 256);
|
2041
|
+
if(ret == 1)
|
2042
|
+
retval = Qnil;
|
2043
|
+
else
|
2044
|
+
retval = rb_str_new2(errbuf);
|
2045
|
+
|
2046
|
+
PQfreeCancel(cancel);
|
2047
|
+
return retval;
|
2048
|
+
}
|
2049
|
+
|
2050
|
+
|
2051
|
+
/*
|
2052
|
+
* call-seq:
|
2053
|
+
* conn.notifies()
|
2054
|
+
*
|
2055
|
+
* Returns a hash of the unprocessed notifiers.
|
2056
|
+
* If there is no unprocessed notifier, it returns +nil+.
|
2057
|
+
*/
|
2058
|
+
static VALUE
|
2059
|
+
pgconn_notifies(VALUE self)
|
2060
|
+
{
|
2061
|
+
PGconn* conn = get_pgconn(self);
|
2062
|
+
PGnotify *notify;
|
2063
|
+
VALUE hash;
|
2064
|
+
VALUE sym_relname, sym_be_pid, sym_extra;
|
2065
|
+
VALUE relname, be_pid, extra;
|
2066
|
+
|
2067
|
+
sym_relname = ID2SYM(rb_intern("relname"));
|
2068
|
+
sym_be_pid = ID2SYM(rb_intern("be_pid"));
|
2069
|
+
sym_extra = ID2SYM(rb_intern("extra"));
|
2070
|
+
|
2071
|
+
notify = PQnotifies(conn);
|
2072
|
+
if (notify == NULL) {
|
2073
|
+
return Qnil;
|
2074
|
+
}
|
2075
|
+
|
2076
|
+
hash = rb_hash_new();
|
2077
|
+
relname = rb_tainted_str_new2(notify->relname);
|
2078
|
+
be_pid = INT2NUM(notify->be_pid);
|
2079
|
+
extra = rb_tainted_str_new2(PGNOTIFY_EXTRA(notify));
|
2080
|
+
|
2081
|
+
rb_hash_aset(hash, sym_relname, relname);
|
2082
|
+
rb_hash_aset(hash, sym_be_pid, be_pid);
|
2083
|
+
rb_hash_aset(hash, sym_extra, extra);
|
2084
|
+
|
2085
|
+
PQfreemem(notify);
|
2086
|
+
return hash;
|
2087
|
+
}
|
2088
|
+
|
2089
|
+
|
2090
|
+
/*
|
2091
|
+
* call-seq:
|
2092
|
+
* conn.wait_for_notify( [ timeout ] ) -> String
|
2093
|
+
* conn.wait_for_notify( [ timeout ] ) { |event, pid| block }
|
2094
|
+
*
|
2095
|
+
* Blocks while waiting for notification(s), or until the optional
|
2096
|
+
* _timeout_ is reached, whichever comes first. _timeout_ is
|
2097
|
+
* measured in seconds and can be fractional.
|
2098
|
+
*
|
2099
|
+
* Returns +nil+ if _timeout_ is reached, the name of the NOTIFY
|
2100
|
+
* event otherwise. If used in block form, passes the name of the
|
2101
|
+
* NOTIFY +event+ and the generating +pid+ into the block.
|
2102
|
+
*
|
2103
|
+
*/
|
2104
|
+
static VALUE
|
2105
|
+
pgconn_wait_for_notify(int argc, VALUE *argv, VALUE self)
|
2106
|
+
{
|
2107
|
+
PGconn *conn = get_pgconn(self);
|
2108
|
+
PGnotify *notify;
|
2109
|
+
int sd = PQsocket(conn);
|
2110
|
+
int ret;
|
2111
|
+
struct timeval timeout;
|
2112
|
+
struct timeval *ptimeout = NULL;
|
2113
|
+
VALUE timeout_in, relname = Qnil, be_pid = Qnil;
|
2114
|
+
double timeout_sec;
|
2115
|
+
fd_set sd_rset;
|
2116
|
+
|
2117
|
+
if (sd < 0)
|
2118
|
+
rb_bug("PQsocket(conn): couldn't fetch the connection's socket!");
|
2119
|
+
|
2120
|
+
if (rb_scan_args(argc, argv, "01", &timeout_in) == 1) {
|
2121
|
+
timeout_sec = NUM2DBL(timeout_in);
|
2122
|
+
timeout.tv_sec = (long)timeout_sec;
|
2123
|
+
timeout.tv_usec = (long)((timeout_sec - (long)timeout_sec) * 1e6);
|
2124
|
+
ptimeout = &timeout;
|
2125
|
+
}
|
2126
|
+
|
2127
|
+
FD_ZERO(&sd_rset);
|
2128
|
+
FD_SET(sd, &sd_rset);
|
2129
|
+
ret = rb_thread_select(sd+1, &sd_rset, NULL, NULL, ptimeout);
|
2130
|
+
if (ret == 0) {
|
2131
|
+
return Qnil;
|
2132
|
+
} else if (ret < 0) {
|
2133
|
+
rb_sys_fail(0);
|
2134
|
+
}
|
2135
|
+
|
2136
|
+
if ( (ret = PQconsumeInput(conn)) != 1 ) {
|
2137
|
+
rb_raise(rb_ePGError, "PQconsumeInput == %d: %s", ret, PQerrorMessage(conn));
|
2138
|
+
}
|
2139
|
+
|
2140
|
+
while ((notify = PQnotifies(conn)) != NULL) {
|
2141
|
+
relname = rb_tainted_str_new2(notify->relname);
|
2142
|
+
be_pid = INT2NUM(notify->be_pid);
|
2143
|
+
PQfreemem(notify);
|
2144
|
+
}
|
2145
|
+
|
2146
|
+
if (rb_block_given_p()) rb_yield( rb_ary_new3(2, relname, be_pid) );
|
2147
|
+
|
2148
|
+
return relname;
|
2149
|
+
}
|
2150
|
+
|
2151
|
+
|
2152
|
+
/*
|
2153
|
+
* call-seq:
|
2154
|
+
* conn.put_copy_data( buffer ) -> Boolean
|
2155
|
+
*
|
2156
|
+
* Transmits _buffer_ as copy data to the server.
|
2157
|
+
* Returns true if the data was sent, false if it was
|
2158
|
+
* not sent (false is only possible if the connection
|
2159
|
+
* is in nonblocking mode, and this command would block).
|
2160
|
+
*
|
2161
|
+
* Raises an exception if an error occurs.
|
2162
|
+
*/
|
2163
|
+
static VALUE
|
2164
|
+
pgconn_put_copy_data(self, buffer)
|
2165
|
+
VALUE self, buffer;
|
2166
|
+
{
|
2167
|
+
int ret;
|
2168
|
+
VALUE error;
|
2169
|
+
PGconn *conn = get_pgconn(self);
|
2170
|
+
Check_Type(buffer, T_STRING);
|
2171
|
+
|
2172
|
+
ret = PQputCopyData(conn, RSTRING_PTR(buffer),
|
2173
|
+
RSTRING_LEN(buffer));
|
2174
|
+
if(ret == -1) {
|
2175
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
2176
|
+
rb_iv_set(error, "@connection", self);
|
2177
|
+
rb_exc_raise(error);
|
2178
|
+
}
|
2179
|
+
return (ret) ? Qtrue : Qfalse;
|
2180
|
+
}
|
2181
|
+
|
2182
|
+
/*
|
2183
|
+
* call-seq:
|
2184
|
+
* conn.put_copy_end( [ error_message ] ) -> Boolean
|
2185
|
+
*
|
2186
|
+
* Sends end-of-data indication to the server.
|
2187
|
+
*
|
2188
|
+
* _error_message_ is an optional parameter, and if set,
|
2189
|
+
* forces the COPY command to fail with the string
|
2190
|
+
* _error_message_.
|
2191
|
+
*
|
2192
|
+
* Returns true if the end-of-data was sent, false if it was
|
2193
|
+
* not sent (false is only possible if the connection
|
2194
|
+
* is in nonblocking mode, and this command would block).
|
2195
|
+
*/
|
2196
|
+
static VALUE
|
2197
|
+
pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
2198
|
+
{
|
2199
|
+
VALUE str;
|
2200
|
+
VALUE error;
|
2201
|
+
int ret;
|
2202
|
+
char *error_message = NULL;
|
2203
|
+
PGconn *conn = get_pgconn(self);
|
2204
|
+
|
2205
|
+
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2206
|
+
error_message = NULL;
|
2207
|
+
else
|
2208
|
+
error_message = StringValuePtr(str);
|
2209
|
+
|
2210
|
+
ret = PQputCopyEnd(conn, error_message);
|
2211
|
+
if(ret == -1) {
|
2212
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
2213
|
+
rb_iv_set(error, "@connection", self);
|
2214
|
+
rb_exc_raise(error);
|
2215
|
+
}
|
2216
|
+
return (ret) ? Qtrue : Qfalse;
|
2217
|
+
}
|
2218
|
+
|
2219
|
+
/*
|
2220
|
+
* call-seq:
|
2221
|
+
* conn.get_copy_data( [ async = false ] ) -> String
|
2222
|
+
*
|
2223
|
+
* Return a string containing one row of data, +nil+
|
2224
|
+
* if the copy is done, or +false+ if the call would
|
2225
|
+
* block (only possible if _async_ is true).
|
2226
|
+
*
|
2227
|
+
*/
|
2228
|
+
static VALUE
|
2229
|
+
pgconn_get_copy_data(int argc, VALUE *argv, VALUE self )
|
2230
|
+
{
|
2231
|
+
VALUE async_in;
|
2232
|
+
VALUE error;
|
2233
|
+
VALUE result_str;
|
2234
|
+
int ret;
|
2235
|
+
int async;
|
2236
|
+
char *buffer;
|
2237
|
+
PGconn *conn = get_pgconn(self);
|
2238
|
+
|
2239
|
+
if (rb_scan_args(argc, argv, "01", &async_in) == 0)
|
2240
|
+
async = 0;
|
2241
|
+
else
|
2242
|
+
async = (async_in == Qfalse || async_in == Qnil) ? 0 : 1;
|
2243
|
+
|
2244
|
+
ret = PQgetCopyData(conn, &buffer, async);
|
2245
|
+
if(ret == -2) { // error
|
2246
|
+
error = rb_exc_new2(rb_ePGError, PQerrorMessage(conn));
|
2247
|
+
rb_iv_set(error, "@connection", self);
|
2248
|
+
rb_exc_raise(error);
|
2249
|
+
}
|
2250
|
+
if(ret == -1) { // No data left
|
2251
|
+
return Qnil;
|
2252
|
+
}
|
2253
|
+
if(ret == 0) { // would block
|
2254
|
+
return Qfalse;
|
2255
|
+
}
|
2256
|
+
result_str = rb_tainted_str_new(buffer, ret);
|
2257
|
+
PQfreemem(buffer);
|
2258
|
+
return result_str;
|
2259
|
+
}
|
2260
|
+
|
2261
|
+
/*
|
2262
|
+
* call-seq:
|
2263
|
+
* conn.set_error_verbosity( verbosity ) -> Fixnum
|
2264
|
+
*
|
2265
|
+
* Sets connection's verbosity to _verbosity_ and returns
|
2266
|
+
* the previous setting. Available settings are:
|
2267
|
+
* * PQERRORS_TERSE
|
2268
|
+
* * PQERRORS_DEFAULT
|
2269
|
+
* * PQERRORS_VERBOSE
|
2270
|
+
*/
|
2271
|
+
static VALUE
|
2272
|
+
pgconn_set_error_verbosity(VALUE self, VALUE in_verbosity)
|
2273
|
+
{
|
2274
|
+
PGconn *conn = get_pgconn(self);
|
2275
|
+
PGVerbosity verbosity = NUM2INT(in_verbosity);
|
2276
|
+
return INT2FIX(PQsetErrorVerbosity(conn, verbosity));
|
2277
|
+
}
|
2278
|
+
|
2279
|
+
/*
|
2280
|
+
* call-seq:
|
2281
|
+
* conn.trace( stream ) -> nil
|
2282
|
+
*
|
2283
|
+
* Enables tracing message passing between backend. The
|
2284
|
+
* trace message will be written to the stream _stream_,
|
2285
|
+
* which must implement a method +fileno+ that returns
|
2286
|
+
* a writable file descriptor.
|
2287
|
+
*/
|
2288
|
+
static VALUE
|
2289
|
+
pgconn_trace(VALUE self, VALUE stream)
|
2290
|
+
{
|
2291
|
+
VALUE fileno;
|
2292
|
+
FILE *new_fp;
|
2293
|
+
int old_fd, new_fd;
|
2294
|
+
VALUE new_file;
|
2295
|
+
|
2296
|
+
if(rb_respond_to(stream,rb_intern("fileno")) == Qfalse)
|
2297
|
+
rb_raise(rb_eArgError, "stream does not respond to method: fileno");
|
2298
|
+
|
2299
|
+
fileno = rb_funcall(stream, rb_intern("fileno"), 0);
|
2300
|
+
if(fileno == Qnil)
|
2301
|
+
rb_raise(rb_eArgError, "can't get file descriptor from stream");
|
2302
|
+
|
2303
|
+
/* Duplicate the file descriptor and re-open
|
2304
|
+
* it. Then, make it into a ruby File object
|
2305
|
+
* and assign it to an instance variable.
|
2306
|
+
* This prevents a problem when the File
|
2307
|
+
* object passed to this function is closed
|
2308
|
+
* before the connection object is. */
|
2309
|
+
old_fd = NUM2INT(fileno);
|
2310
|
+
new_fd = dup(old_fd);
|
2311
|
+
new_fp = fdopen(new_fd, "w");
|
2312
|
+
|
2313
|
+
if(new_fp == NULL)
|
2314
|
+
rb_raise(rb_eArgError, "stream is not writable");
|
2315
|
+
|
2316
|
+
new_file = rb_funcall(rb_cIO, rb_intern("new"), 1, INT2NUM(new_fd));
|
2317
|
+
rb_iv_set(self, "@trace_stream", new_file);
|
2318
|
+
|
2319
|
+
PQtrace(get_pgconn(self), new_fp);
|
2320
|
+
return Qnil;
|
2321
|
+
}
|
2322
|
+
|
2323
|
+
/*
|
2324
|
+
* call-seq:
|
2325
|
+
* conn.untrace() -> nil
|
2326
|
+
*
|
2327
|
+
* Disables the message tracing.
|
2328
|
+
*/
|
2329
|
+
static VALUE
|
2330
|
+
pgconn_untrace(VALUE self)
|
2331
|
+
{
|
2332
|
+
VALUE trace_stream;
|
2333
|
+
PQuntrace(get_pgconn(self));
|
2334
|
+
trace_stream = rb_iv_get(self, "@trace_stream");
|
2335
|
+
rb_funcall(trace_stream, rb_intern("close"), 0);
|
2336
|
+
rb_iv_set(self, "@trace_stream", Qnil);
|
2337
|
+
return Qnil;
|
2338
|
+
}
|
2339
|
+
|
2340
|
+
/*
|
2341
|
+
* call-seq:
|
2342
|
+
* conn.set_notice_receiver {|result| ... } -> Proc
|
2343
|
+
*
|
2344
|
+
* Notice and warning messages generated by the server are not returned
|
2345
|
+
* by the query execution functions, since they do not imply failure of
|
2346
|
+
* the query. Instead they are passed to a notice handling function, and
|
2347
|
+
* execution continues normally after the handler returns. The default
|
2348
|
+
* notice handling function prints the message on <tt>stderr</tt>, but the
|
2349
|
+
* application can override this behavior by supplying its own handling
|
2350
|
+
* function.
|
2351
|
+
*
|
2352
|
+
* This function takes a new block to act as the handler, which should
|
2353
|
+
* accept a single parameter that will be a PGresult object, and returns
|
2354
|
+
* the Proc object previously set, or +nil+ if it was previously the default.
|
2355
|
+
*
|
2356
|
+
* If you pass no arguments, it will reset the handler to the default.
|
2357
|
+
*/
|
2358
|
+
static VALUE
|
2359
|
+
pgconn_set_notice_receiver(VALUE self)
|
2360
|
+
{
|
2361
|
+
VALUE proc, old_proc;
|
2362
|
+
PGconn *conn = get_pgconn(self);
|
2363
|
+
|
2364
|
+
/* If default_notice_receiver is unset, assume that the current
|
2365
|
+
* notice receiver is the default, and save it to a global variable.
|
2366
|
+
* This should not be a problem because the default receiver is
|
2367
|
+
* always the same, so won't vary among connections.
|
2368
|
+
*/
|
2369
|
+
if(default_notice_receiver == NULL)
|
2370
|
+
default_notice_receiver = PQsetNoticeReceiver(conn, NULL, NULL);
|
2371
|
+
|
2372
|
+
old_proc = rb_iv_get(self, "@notice_receiver");
|
2373
|
+
if( rb_block_given_p() ) {
|
2374
|
+
proc = rb_block_proc();
|
2375
|
+
PQsetNoticeReceiver(conn, notice_receiver_proxy, (void *)self);
|
2376
|
+
} else {
|
2377
|
+
/* if no block is given, set back to default */
|
2378
|
+
proc = Qnil;
|
2379
|
+
PQsetNoticeReceiver(conn, default_notice_receiver, NULL);
|
2380
|
+
}
|
2381
|
+
|
2382
|
+
rb_iv_set(self, "@notice_receiver", proc);
|
2383
|
+
return old_proc;
|
2384
|
+
}
|
2385
|
+
|
2386
|
+
/*
|
2387
|
+
* call-seq:
|
2388
|
+
* conn.set_notice_processor {|message| ... } -> Proc
|
2389
|
+
*
|
2390
|
+
* Notice and warning messages generated by the server are not returned
|
2391
|
+
* by the query execution functions, since they do not imply failure of
|
2392
|
+
* the query. Instead they are passed to a notice handling function, and
|
2393
|
+
* execution continues normally after the handler returns. The default
|
2394
|
+
* notice handling function prints the message on <tt>stderr</tt>, but the
|
2395
|
+
* application can override this behavior by supplying its own handling
|
2396
|
+
* function.
|
2397
|
+
*
|
2398
|
+
* This function takes a new block to act as the handler, which should
|
2399
|
+
* accept a single parameter that will be a PGresult object, and returns
|
2400
|
+
* the Proc object previously set, or +nil+ if it was previously the default.
|
2401
|
+
*
|
2402
|
+
* If you pass no arguments, it will reset the handler to the default.
|
2403
|
+
*/
|
2404
|
+
static VALUE
|
2405
|
+
pgconn_set_notice_processor(VALUE self)
|
2406
|
+
{
|
2407
|
+
VALUE proc, old_proc;
|
2408
|
+
PGconn *conn = get_pgconn(self);
|
2409
|
+
|
2410
|
+
/* If default_notice_processor is unset, assume that the current
|
2411
|
+
* notice processor is the default, and save it to a global variable.
|
2412
|
+
* This should not be a problem because the default processor is
|
2413
|
+
* always the same, so won't vary among connections.
|
2414
|
+
*/
|
2415
|
+
if(default_notice_processor == NULL)
|
2416
|
+
default_notice_processor = PQsetNoticeProcessor(conn, NULL, NULL);
|
2417
|
+
|
2418
|
+
old_proc = rb_iv_get(self, "@notice_processor");
|
2419
|
+
if( rb_block_given_p() ) {
|
2420
|
+
proc = rb_block_proc();
|
2421
|
+
PQsetNoticeProcessor(conn, notice_processor_proxy, (void *)self);
|
2422
|
+
} else {
|
2423
|
+
/* if no block is given, set back to default */
|
2424
|
+
proc = Qnil;
|
2425
|
+
PQsetNoticeProcessor(conn, default_notice_processor, NULL);
|
2426
|
+
}
|
2427
|
+
|
2428
|
+
rb_iv_set(self, "@notice_processor", proc);
|
2429
|
+
return old_proc;
|
2430
|
+
}
|
2431
|
+
/*
|
2432
|
+
* call-seq:
|
2433
|
+
* conn.get_client_encoding() -> String
|
2434
|
+
*
|
2435
|
+
* Returns the client encoding as a String.
|
2436
|
+
*/
|
2437
|
+
static VALUE
|
2438
|
+
pgconn_get_client_encoding(VALUE self)
|
2439
|
+
{
|
2440
|
+
char *encoding = (char *)pg_encoding_to_char(PQclientEncoding(get_pgconn(self)));
|
2441
|
+
return rb_tainted_str_new2(encoding);
|
2442
|
+
}
|
2443
|
+
|
2444
|
+
/*
|
2445
|
+
* call-seq:
|
2446
|
+
* conn.set_client_encoding( encoding )
|
2447
|
+
*
|
2448
|
+
* Sets the client encoding to the _encoding_ String.
|
2449
|
+
*/
|
2450
|
+
static VALUE
|
2451
|
+
pgconn_set_client_encoding(VALUE self, VALUE str)
|
2452
|
+
{
|
2453
|
+
Check_Type(str, T_STRING);
|
2454
|
+
if ((PQsetClientEncoding(get_pgconn(self), StringValuePtr(str))) == -1){
|
2455
|
+
rb_raise(rb_ePGError, "invalid encoding name: %s",StringValuePtr(str));
|
2456
|
+
}
|
2457
|
+
return Qnil;
|
2458
|
+
}
|
2459
|
+
|
2460
|
+
/*
|
2461
|
+
* call-seq:
|
2462
|
+
* conn.transaction { |conn| ... } -> nil
|
2463
|
+
*
|
2464
|
+
* Executes a +BEGIN+ at the start of the block,
|
2465
|
+
* and a +COMMIT+ at the end of the block, or
|
2466
|
+
* +ROLLBACK+ if any exception occurs.
|
2467
|
+
*/
|
2468
|
+
static VALUE
|
2469
|
+
pgconn_transaction(VALUE self)
|
2470
|
+
{
|
2471
|
+
PGconn *conn = get_pgconn(self);
|
2472
|
+
PGresult *result;
|
2473
|
+
VALUE rb_pgresult;
|
2474
|
+
int status;
|
2475
|
+
|
2476
|
+
if (rb_block_given_p()) {
|
2477
|
+
result = PQexec(conn, "BEGIN");
|
2478
|
+
rb_pgresult = new_pgresult(result, conn);
|
2479
|
+
pgresult_check(self, rb_pgresult);
|
2480
|
+
rb_protect(rb_yield, self, &status);
|
2481
|
+
if(status == 0) {
|
2482
|
+
result = PQexec(conn, "COMMIT");
|
2483
|
+
rb_pgresult = new_pgresult(result, conn);
|
2484
|
+
pgresult_check(self, rb_pgresult);
|
2485
|
+
}
|
2486
|
+
else {
|
2487
|
+
/* exception occurred, ROLLBACK and re-raise */
|
2488
|
+
result = PQexec(conn, "ROLLBACK");
|
2489
|
+
rb_pgresult = new_pgresult(result, conn);
|
2490
|
+
pgresult_check(self, rb_pgresult);
|
2491
|
+
rb_jump_tag(status);
|
2492
|
+
}
|
2493
|
+
|
2494
|
+
}
|
2495
|
+
else {
|
2496
|
+
/* no block supplied? */
|
2497
|
+
rb_raise(rb_eArgError, "Must supply block for PGconn#transaction");
|
2498
|
+
}
|
2499
|
+
return Qnil;
|
2500
|
+
}
|
2501
|
+
|
2502
|
+
/*
|
2503
|
+
* call-seq:
|
2504
|
+
* PGconn.quote_ident( str ) -> String
|
2505
|
+
* conn.quote_ident( str ) -> String
|
2506
|
+
*
|
2507
|
+
* Returns a string that is safe for inclusion in a SQL query as an
|
2508
|
+
* identifier. Note: this is not a quote function for values, but for
|
2509
|
+
* identifiers.
|
2510
|
+
*
|
2511
|
+
* For example, in a typical SQL query: <tt>SELECT FOO FROM MYTABLE</tt>
|
2512
|
+
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
2513
|
+
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
2514
|
+
* field name <tt>FOO</tt>, use this function like
|
2515
|
+
* <tt>PGconn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
2516
|
+
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
2517
|
+
* it will not fold to lower case.
|
2518
|
+
*
|
2519
|
+
* Similarly, this function also protects against special characters,
|
2520
|
+
* and other things that might allow SQL injection if the identifier
|
2521
|
+
* comes from an untrusted source.
|
2522
|
+
*/
|
2523
|
+
static VALUE
|
2524
|
+
pgconn_s_quote_ident(VALUE self, VALUE in_str)
|
2525
|
+
{
|
2526
|
+
VALUE ret;
|
2527
|
+
char *str = StringValuePtr(in_str);
|
2528
|
+
/* result size at most NAMEDATALEN*2 plus surrounding
|
2529
|
+
* double-quotes. */
|
2530
|
+
char buffer[NAMEDATALEN*2+2];
|
2531
|
+
unsigned int i=0,j=0;
|
2532
|
+
|
2533
|
+
if(strlen(str) >= NAMEDATALEN) {
|
2534
|
+
rb_raise(rb_eArgError,
|
2535
|
+
"Input string is longer than NAMEDATALEN-1 (%d)",
|
2536
|
+
NAMEDATALEN-1);
|
2537
|
+
}
|
2538
|
+
buffer[j++] = '"';
|
2539
|
+
for(i = 0; i < strlen(str) && str[i]; i++) {
|
2540
|
+
if(str[i] == '"')
|
2541
|
+
buffer[j++] = '"';
|
2542
|
+
buffer[j++] = str[i];
|
2543
|
+
}
|
2544
|
+
buffer[j++] = '"';
|
2545
|
+
ret = rb_str_new(buffer,j);
|
2546
|
+
OBJ_INFECT(ret, in_str);
|
2547
|
+
return ret;
|
2548
|
+
}
|
2549
|
+
|
2550
|
+
|
2551
|
+
/*
|
2552
|
+
* call-seq:
|
2553
|
+
* conn.block( [ timeout ] ) -> Boolean
|
2554
|
+
*
|
2555
|
+
* Blocks until the server is no longer busy, or until the
|
2556
|
+
* optional _timeout_ is reached, whichever comes first.
|
2557
|
+
* _timeout_ is measured in seconds and can be fractional.
|
2558
|
+
*
|
2559
|
+
* Returns +false+ if _timeout_ is reached, +true+ otherwise.
|
2560
|
+
*
|
2561
|
+
* If +true+ is returned, +conn.is_busy+ will return +false+
|
2562
|
+
* and +conn.get_result+ will not block.
|
2563
|
+
*/
|
2564
|
+
static VALUE
|
2565
|
+
pgconn_block( int argc, VALUE *argv, VALUE self ) {
|
2566
|
+
PGconn *conn = get_pgconn(self);
|
2567
|
+
int sd = PQsocket(conn);
|
2568
|
+
int ret;
|
2569
|
+
struct timeval timeout;
|
2570
|
+
struct timeval *ptimeout = NULL;
|
2571
|
+
VALUE timeout_in;
|
2572
|
+
double timeout_sec;
|
2573
|
+
fd_set sd_rset;
|
2574
|
+
|
2575
|
+
/* Always set a timeout in WIN32, as rb_thread_select() sometimes
|
2576
|
+
* doesn't return when a second ruby thread is running although data
|
2577
|
+
* could be read. So we use timeout-based polling instead.
|
2578
|
+
*/
|
2579
|
+
#if defined(_WIN32)
|
2580
|
+
timeout.tv_sec = 0;
|
2581
|
+
timeout.tv_usec = 10000;
|
2582
|
+
ptimeout = &timeout;
|
2583
|
+
#endif
|
2584
|
+
|
2585
|
+
if ( rb_scan_args(argc, argv, "01", &timeout_in) == 1 ) {
|
2586
|
+
timeout_sec = NUM2DBL( timeout_in );
|
2587
|
+
timeout.tv_sec = (long)timeout_sec;
|
2588
|
+
timeout.tv_usec = (long)((timeout_sec - (long)timeout_sec) * 1e6);
|
2589
|
+
ptimeout = &timeout;
|
2590
|
+
}
|
2591
|
+
|
2592
|
+
PQconsumeInput( conn );
|
2593
|
+
|
2594
|
+
while ( PQisBusy(conn) ) {
|
2595
|
+
FD_ZERO( &sd_rset );
|
2596
|
+
FD_SET( sd, &sd_rset );
|
2597
|
+
ret = rb_thread_select( sd+1, &sd_rset, NULL, NULL, ptimeout );
|
2598
|
+
|
2599
|
+
/* Return false if there was a timeout argument and the select() timed out */
|
2600
|
+
if ( ret == 0 && argc )
|
2601
|
+
return Qfalse;
|
2602
|
+
|
2603
|
+
PQconsumeInput( conn );
|
2604
|
+
}
|
2605
|
+
|
2606
|
+
return Qtrue;
|
2607
|
+
}
|
2608
|
+
|
2609
|
+
|
2610
|
+
/*
|
2611
|
+
* call-seq:
|
2612
|
+
* conn.get_last_result( ) -> PGresult
|
2613
|
+
*
|
2614
|
+
* This function retrieves all available results
|
2615
|
+
* on the current connection (from previously issued
|
2616
|
+
* asynchronous commands like +send_query()+) and
|
2617
|
+
* returns the last non-NULL result, or +nil+ if no
|
2618
|
+
* results are available.
|
2619
|
+
*
|
2620
|
+
* This function is similar to +PGconn#get_result+
|
2621
|
+
* except that it is designed to get one and only
|
2622
|
+
* one result.
|
2623
|
+
*/
|
2624
|
+
static VALUE
|
2625
|
+
pgconn_get_last_result(VALUE self)
|
2626
|
+
{
|
2627
|
+
PGconn *conn = get_pgconn(self);
|
2628
|
+
VALUE rb_pgresult = Qnil;
|
2629
|
+
PGresult *cur, *prev;
|
2630
|
+
|
2631
|
+
|
2632
|
+
cur = prev = NULL;
|
2633
|
+
while ((cur = PQgetResult(conn)) != NULL) {
|
2634
|
+
int status;
|
2635
|
+
|
2636
|
+
if (prev) PQclear(prev);
|
2637
|
+
prev = cur;
|
2638
|
+
|
2639
|
+
status = PQresultStatus(cur);
|
2640
|
+
if (status == PGRES_COPY_OUT || status == PGRES_COPY_IN)
|
2641
|
+
break;
|
2642
|
+
}
|
2643
|
+
|
2644
|
+
if (prev) {
|
2645
|
+
rb_pgresult = new_pgresult(prev, conn);
|
2646
|
+
pgresult_check(self, rb_pgresult);
|
2647
|
+
}
|
2648
|
+
|
2649
|
+
return rb_pgresult;
|
2650
|
+
}
|
2651
|
+
|
2652
|
+
|
2653
|
+
/*
|
2654
|
+
* call-seq:
|
2655
|
+
* conn.async_exec(sql [, params, result_format ] ) -> PGresult
|
2656
|
+
* conn.async_exec(sql [, params, result_format ] ) {|pg_result| block }
|
2657
|
+
*
|
2658
|
+
* This function has the same behavior as +PGconn#exec+,
|
2659
|
+
* except that it's implemented using asynchronous command
|
2660
|
+
* processing and ruby's +rb_thread_select+ in order to
|
2661
|
+
* allow other threads to process while waiting for the
|
2662
|
+
* server to complete the request.
|
2663
|
+
*/
|
2664
|
+
static VALUE
|
2665
|
+
pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
2666
|
+
{
|
2667
|
+
VALUE rb_pgresult = Qnil;
|
2668
|
+
|
2669
|
+
/* remove any remaining results from the queue */
|
2670
|
+
pgconn_get_last_result( self );
|
2671
|
+
|
2672
|
+
pgconn_send_query( argc, argv, self );
|
2673
|
+
pgconn_block( 0, NULL, self );
|
2674
|
+
rb_pgresult = pgconn_get_last_result( self );
|
2675
|
+
|
2676
|
+
if ( rb_block_given_p() ) {
|
2677
|
+
return rb_ensure( rb_yield, rb_pgresult, pgresult_clear, rb_pgresult );
|
2678
|
+
}
|
2679
|
+
return rb_pgresult;
|
2680
|
+
}
|
2681
|
+
|
2682
|
+
|
2683
|
+
/**************************************************************************
|
2684
|
+
* LARGE OBJECT SUPPORT
|
2685
|
+
**************************************************************************/
|
2686
|
+
|
2687
|
+
/*
|
2688
|
+
* call-seq:
|
2689
|
+
* conn.lo_creat( [mode] ) -> Fixnum
|
2690
|
+
*
|
2691
|
+
* Creates a large object with mode _mode_. Returns a large object Oid.
|
2692
|
+
* On failure, it raises PGError exception.
|
2693
|
+
*/
|
2694
|
+
static VALUE
|
2695
|
+
pgconn_locreat(int argc, VALUE *argv, VALUE self)
|
2696
|
+
{
|
2697
|
+
Oid lo_oid;
|
2698
|
+
int mode;
|
2699
|
+
VALUE nmode;
|
2700
|
+
PGconn *conn = get_pgconn(self);
|
2701
|
+
|
2702
|
+
if (rb_scan_args(argc, argv, "01", &nmode) == 0)
|
2703
|
+
mode = INV_READ;
|
2704
|
+
else
|
2705
|
+
mode = NUM2INT(nmode);
|
2706
|
+
|
2707
|
+
lo_oid = lo_creat(conn, mode);
|
2708
|
+
if (lo_oid == 0)
|
2709
|
+
rb_raise(rb_ePGError, "lo_creat failed");
|
2710
|
+
|
2711
|
+
return INT2FIX(lo_oid);
|
2712
|
+
}
|
2713
|
+
|
2714
|
+
/*
|
2715
|
+
* call-seq:
|
2716
|
+
* conn.lo_create( oid ) -> Fixnum
|
2717
|
+
*
|
2718
|
+
* Creates a large object with oid _oid_. Returns the large object Oid.
|
2719
|
+
* On failure, it raises PGError exception.
|
2720
|
+
*/
|
2721
|
+
static VALUE
|
2722
|
+
pgconn_locreate(VALUE self, VALUE in_lo_oid)
|
2723
|
+
{
|
2724
|
+
Oid ret, lo_oid;
|
2725
|
+
PGconn *conn = get_pgconn(self);
|
2726
|
+
lo_oid = NUM2INT(in_lo_oid);
|
2727
|
+
|
2728
|
+
ret = lo_create(conn, in_lo_oid);
|
2729
|
+
if (ret == InvalidOid)
|
2730
|
+
rb_raise(rb_ePGError, "lo_create failed");
|
2731
|
+
|
2732
|
+
return INT2FIX(ret);
|
2733
|
+
}
|
2734
|
+
|
2735
|
+
/*
|
2736
|
+
* call-seq:
|
2737
|
+
* conn.lo_import(file) -> Fixnum
|
2738
|
+
*
|
2739
|
+
* Import a file to a large object. Returns a large object Oid.
|
2740
|
+
*
|
2741
|
+
* On failure, it raises a PGError exception.
|
2742
|
+
*/
|
2743
|
+
static VALUE
|
2744
|
+
pgconn_loimport(VALUE self, VALUE filename)
|
2745
|
+
{
|
2746
|
+
Oid lo_oid;
|
2747
|
+
|
2748
|
+
PGconn *conn = get_pgconn(self);
|
2749
|
+
|
2750
|
+
Check_Type(filename, T_STRING);
|
2751
|
+
|
2752
|
+
lo_oid = lo_import(conn, StringValuePtr(filename));
|
2753
|
+
if (lo_oid == 0) {
|
2754
|
+
rb_raise(rb_ePGError, "%s", PQerrorMessage(conn));
|
2755
|
+
}
|
2756
|
+
return INT2FIX(lo_oid);
|
2757
|
+
}
|
2758
|
+
|
2759
|
+
/*
|
2760
|
+
* call-seq:
|
2761
|
+
* conn.lo_export( oid, file ) -> nil
|
2762
|
+
*
|
2763
|
+
* Saves a large object of _oid_ to a _file_.
|
2764
|
+
*/
|
2765
|
+
static VALUE
|
2766
|
+
pgconn_loexport(VALUE self, VALUE lo_oid, VALUE filename)
|
2767
|
+
{
|
2768
|
+
PGconn *conn = get_pgconn(self);
|
2769
|
+
int oid;
|
2770
|
+
Check_Type(filename, T_STRING);
|
2771
|
+
|
2772
|
+
oid = NUM2INT(lo_oid);
|
2773
|
+
if (oid < 0) {
|
2774
|
+
rb_raise(rb_ePGError, "invalid large object oid %d",oid);
|
2775
|
+
}
|
2776
|
+
|
2777
|
+
if (lo_export(conn, oid, StringValuePtr(filename)) < 0) {
|
2778
|
+
rb_raise(rb_ePGError, "%s", PQerrorMessage(conn));
|
2779
|
+
}
|
2780
|
+
return Qnil;
|
2781
|
+
}
|
2782
|
+
|
2783
|
+
/*
|
2784
|
+
* call-seq:
|
2785
|
+
* conn.lo_open( oid, [mode] ) -> Fixnum
|
2786
|
+
*
|
2787
|
+
* Open a large object of _oid_. Returns a large object descriptor
|
2788
|
+
* instance on success. The _mode_ argument specifies the mode for
|
2789
|
+
* the opened large object,which is either +INV_READ+, or +INV_WRITE+.
|
2790
|
+
*
|
2791
|
+
* If _mode_ is omitted, the default is +INV_READ+.
|
2792
|
+
*/
|
2793
|
+
static VALUE
|
2794
|
+
pgconn_loopen(int argc, VALUE *argv, VALUE self)
|
2795
|
+
{
|
2796
|
+
Oid lo_oid;
|
2797
|
+
int fd, mode;
|
2798
|
+
VALUE nmode, selfid;
|
2799
|
+
PGconn *conn = get_pgconn(self);
|
2800
|
+
|
2801
|
+
rb_scan_args(argc, argv, "11", &selfid, &nmode);
|
2802
|
+
lo_oid = NUM2INT(selfid);
|
2803
|
+
if(NIL_P(nmode))
|
2804
|
+
mode = INV_READ;
|
2805
|
+
else
|
2806
|
+
mode = NUM2INT(nmode);
|
2807
|
+
|
2808
|
+
if((fd = lo_open(conn, lo_oid, mode)) < 0) {
|
2809
|
+
rb_raise(rb_ePGError, "can't open large object: %s", PQerrorMessage(conn));
|
2810
|
+
}
|
2811
|
+
return INT2FIX(fd);
|
2812
|
+
}
|
2813
|
+
|
2814
|
+
/*
|
2815
|
+
* call-seq:
|
2816
|
+
* conn.lo_write( lo_desc, buffer ) -> Fixnum
|
2817
|
+
*
|
2818
|
+
* Writes the string _buffer_ to the large object _lo_desc_.
|
2819
|
+
* Returns the number of bytes written.
|
2820
|
+
*/
|
2821
|
+
static VALUE
|
2822
|
+
pgconn_lowrite(VALUE self, VALUE in_lo_desc, VALUE buffer)
|
2823
|
+
{
|
2824
|
+
int n;
|
2825
|
+
PGconn *conn = get_pgconn(self);
|
2826
|
+
int fd = NUM2INT(in_lo_desc);
|
2827
|
+
|
2828
|
+
Check_Type(buffer, T_STRING);
|
2829
|
+
|
2830
|
+
if( RSTRING_LEN(buffer) < 0) {
|
2831
|
+
rb_raise(rb_ePGError, "write buffer zero string");
|
2832
|
+
}
|
2833
|
+
if((n = lo_write(conn, fd, StringValuePtr(buffer),
|
2834
|
+
RSTRING_LEN(buffer))) < 0) {
|
2835
|
+
rb_raise(rb_ePGError, "lo_write failed: %s", PQerrorMessage(conn));
|
2836
|
+
}
|
2837
|
+
|
2838
|
+
return INT2FIX(n);
|
2839
|
+
}
|
2840
|
+
|
2841
|
+
/*
|
2842
|
+
* call-seq:
|
2843
|
+
* conn.lo_read( lo_desc, len ) -> String
|
2844
|
+
*
|
2845
|
+
* Attempts to read _len_ bytes from large object _lo_desc_,
|
2846
|
+
* returns resulting data.
|
2847
|
+
*/
|
2848
|
+
static VALUE
|
2849
|
+
pgconn_loread(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
2850
|
+
{
|
2851
|
+
int ret;
|
2852
|
+
PGconn *conn = get_pgconn(self);
|
2853
|
+
int len = NUM2INT(in_len);
|
2854
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
2855
|
+
VALUE str;
|
2856
|
+
char *buffer;
|
2857
|
+
|
2858
|
+
buffer = ALLOC_N(char, len);
|
2859
|
+
if(buffer == NULL)
|
2860
|
+
rb_raise(rb_eNoMemError, "ALLOC failed!");
|
2861
|
+
|
2862
|
+
if (len < 0){
|
2863
|
+
rb_raise(rb_ePGError,"nagative length %d given", len);
|
2864
|
+
}
|
2865
|
+
|
2866
|
+
if((ret = lo_read(conn, lo_desc, buffer, len)) < 0)
|
2867
|
+
rb_raise(rb_ePGError, "lo_read failed");
|
2868
|
+
|
2869
|
+
if(ret == 0) {
|
2870
|
+
xfree(buffer);
|
2871
|
+
return Qnil;
|
2872
|
+
}
|
2873
|
+
|
2874
|
+
str = rb_tainted_str_new(buffer, ret);
|
2875
|
+
xfree(buffer);
|
2876
|
+
|
2877
|
+
return str;
|
2878
|
+
}
|
2879
|
+
|
2880
|
+
|
2881
|
+
/*
|
2882
|
+
* call-seq:
|
2883
|
+
* conn.lo_lseek( lo_desc, offset, whence ) -> Fixnum
|
2884
|
+
*
|
2885
|
+
* Move the large object pointer _lo_desc_ to offset _offset_.
|
2886
|
+
* Valid values for _whence_ are +SEEK_SET+, +SEEK_CUR+, and +SEEK_END+.
|
2887
|
+
* (Or 0, 1, or 2.)
|
2888
|
+
*/
|
2889
|
+
static VALUE
|
2890
|
+
pgconn_lolseek(VALUE self, VALUE in_lo_desc, VALUE offset, VALUE whence)
|
2891
|
+
{
|
2892
|
+
PGconn *conn = get_pgconn(self);
|
2893
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
2894
|
+
int ret;
|
2895
|
+
|
2896
|
+
if((ret = lo_lseek(conn, lo_desc, NUM2INT(offset), NUM2INT(whence))) < 0) {
|
2897
|
+
rb_raise(rb_ePGError, "lo_lseek failed");
|
2898
|
+
}
|
2899
|
+
|
2900
|
+
return INT2FIX(ret);
|
2901
|
+
}
|
2902
|
+
|
2903
|
+
/*
|
2904
|
+
* call-seq:
|
2905
|
+
* conn.lo_tell( lo_desc ) -> Fixnum
|
2906
|
+
*
|
2907
|
+
* Returns the current position of the large object _lo_desc_.
|
2908
|
+
*/
|
2909
|
+
static VALUE
|
2910
|
+
pgconn_lotell(VALUE self, VALUE in_lo_desc)
|
2911
|
+
{
|
2912
|
+
int position;
|
2913
|
+
PGconn *conn = get_pgconn(self);
|
2914
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
2915
|
+
|
2916
|
+
if((position = lo_tell(conn, lo_desc)) < 0)
|
2917
|
+
rb_raise(rb_ePGError,"lo_tell failed");
|
2918
|
+
|
2919
|
+
return INT2FIX(position);
|
2920
|
+
}
|
2921
|
+
|
2922
|
+
/*
|
2923
|
+
* call-seq:
|
2924
|
+
* conn.lo_truncate( lo_desc, len ) -> nil
|
2925
|
+
*
|
2926
|
+
* Truncates the large object _lo_desc_ to size _len_.
|
2927
|
+
*/
|
2928
|
+
static VALUE
|
2929
|
+
pgconn_lotruncate(VALUE self, VALUE in_lo_desc, VALUE in_len)
|
2930
|
+
{
|
2931
|
+
PGconn *conn = get_pgconn(self);
|
2932
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
2933
|
+
size_t len = NUM2INT(in_len);
|
2934
|
+
|
2935
|
+
if(lo_truncate(conn,lo_desc,len) < 0)
|
2936
|
+
rb_raise(rb_ePGError,"lo_truncate failed");
|
2937
|
+
|
2938
|
+
return Qnil;
|
2939
|
+
}
|
2940
|
+
|
2941
|
+
/*
|
2942
|
+
* call-seq:
|
2943
|
+
* conn.lo_close( lo_desc ) -> nil
|
2944
|
+
*
|
2945
|
+
* Closes the postgres large object of _lo_desc_.
|
2946
|
+
*/
|
2947
|
+
static VALUE
|
2948
|
+
pgconn_loclose(VALUE self, VALUE in_lo_desc)
|
2949
|
+
{
|
2950
|
+
PGconn *conn = get_pgconn(self);
|
2951
|
+
int lo_desc = NUM2INT(in_lo_desc);
|
2952
|
+
|
2953
|
+
if(lo_close(conn,lo_desc) < 0)
|
2954
|
+
rb_raise(rb_ePGError,"lo_close failed");
|
2955
|
+
|
2956
|
+
return Qnil;
|
2957
|
+
}
|
2958
|
+
|
2959
|
+
/*
|
2960
|
+
* call-seq:
|
2961
|
+
* conn.lo_unlink( oid ) -> nil
|
2962
|
+
*
|
2963
|
+
* Unlinks (deletes) the postgres large object of _oid_.
|
2964
|
+
*/
|
2965
|
+
static VALUE
|
2966
|
+
pgconn_lounlink(VALUE self, VALUE in_oid)
|
2967
|
+
{
|
2968
|
+
PGconn *conn = get_pgconn(self);
|
2969
|
+
int oid = NUM2INT(in_oid);
|
2970
|
+
|
2971
|
+
if (oid < 0)
|
2972
|
+
rb_raise(rb_ePGError, "invalid oid %d",oid);
|
2973
|
+
|
2974
|
+
if(lo_unlink(conn,oid) < 0)
|
2975
|
+
rb_raise(rb_ePGError,"lo_unlink failed");
|
2976
|
+
|
2977
|
+
return Qnil;
|
2978
|
+
}
|
2979
|
+
|
2980
|
+
/********************************************************************
|
2981
|
+
*
|
2982
|
+
* Document-class: PGresult
|
2983
|
+
*
|
2984
|
+
* The class to represent the query result tuples (rows).
|
2985
|
+
* An instance of this class is created as the result of every query.
|
2986
|
+
* You may need to invoke the #clear method of the instance when finished with
|
2987
|
+
* the result for better memory performance.
|
2988
|
+
*
|
2989
|
+
* Example:
|
2990
|
+
* require 'pg'
|
2991
|
+
* conn = PGconn.open(:dbname => 'test')
|
2992
|
+
* res = conn.exec('SELECT 1 AS a, 2 AS b, NULL AS c')
|
2993
|
+
* res.getvalue(0,0) # '1'
|
2994
|
+
* res[0]['b'] # '2'
|
2995
|
+
* res[0]['c'] # nil
|
2996
|
+
*
|
2997
|
+
*/
|
2998
|
+
|
2999
|
+
/**************************************************************************
|
3000
|
+
* PGresult INSTANCE METHODS
|
3001
|
+
**************************************************************************/
|
3002
|
+
|
3003
|
+
/*
|
3004
|
+
* call-seq:
|
3005
|
+
* res.result_status() -> Fixnum
|
3006
|
+
*
|
3007
|
+
* Returns the status of the query. The status value is one of:
|
3008
|
+
* * +PGRES_EMPTY_QUERY+
|
3009
|
+
* * +PGRES_COMMAND_OK+
|
3010
|
+
* * +PGRES_TUPLES_OK+
|
3011
|
+
* * +PGRES_COPY_OUT+
|
3012
|
+
* * +PGRES_COPY_IN+
|
3013
|
+
* * +PGRES_BAD_RESPONSE+
|
3014
|
+
* * +PGRES_NONFATAL_ERROR+
|
3015
|
+
* * +PGRES_FATAL_ERROR+
|
3016
|
+
*/
|
3017
|
+
static VALUE
|
3018
|
+
pgresult_result_status(VALUE self)
|
3019
|
+
{
|
3020
|
+
return INT2FIX(PQresultStatus(get_pgresult(self)));
|
3021
|
+
}
|
3022
|
+
|
3023
|
+
/*
|
3024
|
+
* call-seq:
|
3025
|
+
* res.res_status( status ) -> String
|
3026
|
+
*
|
3027
|
+
* Returns the string representation of status +status+.
|
3028
|
+
*
|
3029
|
+
*/
|
3030
|
+
static VALUE
|
3031
|
+
pgresult_res_status(VALUE self, VALUE status)
|
3032
|
+
{
|
3033
|
+
VALUE ret = rb_tainted_str_new2(PQresStatus(NUM2INT(status)));
|
3034
|
+
ASSOCIATE_INDEX(ret, self);
|
3035
|
+
return ret;
|
3036
|
+
}
|
3037
|
+
|
3038
|
+
/*
|
3039
|
+
* call-seq:
|
3040
|
+
* res.result_error_message() -> String
|
3041
|
+
*
|
3042
|
+
* Returns the error message of the command as a string.
|
3043
|
+
*/
|
3044
|
+
static VALUE
|
3045
|
+
pgresult_result_error_message(VALUE self)
|
3046
|
+
{
|
3047
|
+
VALUE ret = rb_tainted_str_new2(PQresultErrorMessage(get_pgresult(self)));
|
3048
|
+
ASSOCIATE_INDEX(ret, self);
|
3049
|
+
return ret;
|
3050
|
+
}
|
3051
|
+
|
3052
|
+
/*
|
3053
|
+
* call-seq:
|
3054
|
+
* res.result_error_field(fieldcode) -> String
|
3055
|
+
*
|
3056
|
+
* Returns the individual field of an error.
|
3057
|
+
*
|
3058
|
+
* +fieldcode+ is one of:
|
3059
|
+
* * +PG_DIAG_SEVERITY+
|
3060
|
+
* * +PG_DIAG_SQLSTATE+
|
3061
|
+
* * +PG_DIAG_MESSAGE_PRIMARY+
|
3062
|
+
* * +PG_DIAG_MESSAGE_DETAIL+
|
3063
|
+
* * +PG_DIAG_MESSAGE_HINT+
|
3064
|
+
* * +PG_DIAG_STATEMENT_POSITION+
|
3065
|
+
* * +PG_DIAG_INTERNAL_POSITION+
|
3066
|
+
* * +PG_DIAG_INTERNAL_QUERY+
|
3067
|
+
* * +PG_DIAG_CONTEXT+
|
3068
|
+
* * +PG_DIAG_SOURCE_FILE+
|
3069
|
+
* * +PG_DIAG_SOURCE_LINE+
|
3070
|
+
* * +PG_DIAG_SOURCE_FUNCTION+
|
3071
|
+
*/
|
3072
|
+
static VALUE
|
3073
|
+
pgresult_result_error_field(VALUE self, VALUE field)
|
3074
|
+
{
|
3075
|
+
PGresult *result = get_pgresult(self);
|
3076
|
+
int fieldcode = NUM2INT(field);
|
3077
|
+
VALUE ret = rb_tainted_str_new2(PQresultErrorField(result,fieldcode));
|
3078
|
+
ASSOCIATE_INDEX(ret, self);
|
3079
|
+
return ret;
|
3080
|
+
}
|
3081
|
+
|
3082
|
+
/*
|
3083
|
+
* call-seq:
|
3084
|
+
* res.clear() -> nil
|
3085
|
+
*
|
3086
|
+
* Clears the PGresult object as the result of the query.
|
3087
|
+
*/
|
3088
|
+
static VALUE
|
3089
|
+
pgresult_clear(VALUE self)
|
3090
|
+
{
|
3091
|
+
PQclear(get_pgresult(self));
|
3092
|
+
DATA_PTR(self) = NULL;
|
3093
|
+
return Qnil;
|
3094
|
+
}
|
3095
|
+
|
3096
|
+
/*
|
3097
|
+
* call-seq:
|
3098
|
+
* res.ntuples() -> Fixnum
|
3099
|
+
*
|
3100
|
+
* Returns the number of tuples in the query result.
|
3101
|
+
*/
|
3102
|
+
static VALUE
|
3103
|
+
pgresult_ntuples(VALUE self)
|
3104
|
+
{
|
3105
|
+
return INT2FIX(PQntuples(get_pgresult(self)));
|
3106
|
+
}
|
3107
|
+
|
3108
|
+
/*
|
3109
|
+
* call-seq:
|
3110
|
+
* res.nfields() -> Fixnum
|
3111
|
+
*
|
3112
|
+
* Returns the number of columns in the query result.
|
3113
|
+
*/
|
3114
|
+
static VALUE
|
3115
|
+
pgresult_nfields(VALUE self)
|
3116
|
+
{
|
3117
|
+
return INT2NUM(PQnfields(get_pgresult(self)));
|
3118
|
+
}
|
3119
|
+
|
3120
|
+
/*
|
3121
|
+
* call-seq:
|
3122
|
+
* res.fname( index ) -> String
|
3123
|
+
*
|
3124
|
+
* Returns the name of the column corresponding to _index_.
|
3125
|
+
*/
|
3126
|
+
static VALUE
|
3127
|
+
pgresult_fname(VALUE self, VALUE index)
|
3128
|
+
{
|
3129
|
+
VALUE fname;
|
3130
|
+
PGresult *result;
|
3131
|
+
int i = NUM2INT(index);
|
3132
|
+
|
3133
|
+
result = get_pgresult(self);
|
3134
|
+
if (i < 0 || i >= PQnfields(result)) {
|
3135
|
+
rb_raise(rb_eArgError,"invalid field number %d", i);
|
3136
|
+
}
|
3137
|
+
fname = rb_tainted_str_new2(PQfname(result, i));
|
3138
|
+
ASSOCIATE_INDEX(fname, self);
|
3139
|
+
return fname;
|
3140
|
+
}
|
3141
|
+
|
3142
|
+
/*
|
3143
|
+
* call-seq:
|
3144
|
+
* res.fnumber( name ) -> Fixnum
|
3145
|
+
*
|
3146
|
+
* Returns the index of the field specified by the string _name_.
|
3147
|
+
*
|
3148
|
+
* Raises an ArgumentError if the specified _name_ isn't one of the field names;
|
3149
|
+
* raises a TypeError if _name_ is not a String.
|
3150
|
+
*/
|
3151
|
+
static VALUE
|
3152
|
+
pgresult_fnumber(VALUE self, VALUE name)
|
3153
|
+
{
|
3154
|
+
int n;
|
3155
|
+
|
3156
|
+
Check_Type(name, T_STRING);
|
3157
|
+
|
3158
|
+
n = PQfnumber(get_pgresult(self), StringValuePtr(name));
|
3159
|
+
if (n == -1) {
|
3160
|
+
rb_raise(rb_eArgError,"Unknown field: %s", StringValuePtr(name));
|
3161
|
+
}
|
3162
|
+
return INT2FIX(n);
|
3163
|
+
}
|
3164
|
+
|
3165
|
+
/*
|
3166
|
+
* call-seq:
|
3167
|
+
* res.ftable( column_number ) -> Fixnum
|
3168
|
+
*
|
3169
|
+
* Returns the Oid of the table from which the column _column_number_
|
3170
|
+
* was fetched.
|
3171
|
+
*
|
3172
|
+
* Raises ArgumentError if _column_number_ is out of range or if
|
3173
|
+
* the Oid is undefined for that column.
|
3174
|
+
*/
|
3175
|
+
static VALUE
|
3176
|
+
pgresult_ftable(VALUE self, VALUE column_number)
|
3177
|
+
{
|
3178
|
+
Oid n ;
|
3179
|
+
int col_number = NUM2INT(column_number);
|
3180
|
+
PGresult *pgresult = get_pgresult(self);
|
3181
|
+
|
3182
|
+
if( col_number < 0 || col_number >= PQnfields(pgresult))
|
3183
|
+
rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
|
3184
|
+
|
3185
|
+
n = PQftable(pgresult, col_number);
|
3186
|
+
return INT2FIX(n);
|
3187
|
+
}
|
3188
|
+
|
3189
|
+
/*
|
3190
|
+
* call-seq:
|
3191
|
+
* res.ftablecol( column_number ) -> Fixnum
|
3192
|
+
*
|
3193
|
+
* Returns the column number (within its table) of the table from
|
3194
|
+
* which the column _column_number_ is made up.
|
3195
|
+
*
|
3196
|
+
* Raises ArgumentError if _column_number_ is out of range or if
|
3197
|
+
* the column number from its table is undefined for that column.
|
3198
|
+
*/
|
3199
|
+
static VALUE
|
3200
|
+
pgresult_ftablecol(VALUE self, VALUE column_number)
|
3201
|
+
{
|
3202
|
+
int col_number = NUM2INT(column_number);
|
3203
|
+
PGresult *pgresult = get_pgresult(self);
|
3204
|
+
|
3205
|
+
int n;
|
3206
|
+
|
3207
|
+
if( col_number < 0 || col_number >= PQnfields(pgresult))
|
3208
|
+
rb_raise(rb_eArgError,"Invalid column index: %d", col_number);
|
3209
|
+
|
3210
|
+
n = PQftablecol(pgresult, col_number);
|
3211
|
+
return INT2FIX(n);
|
3212
|
+
}
|
3213
|
+
|
3214
|
+
/*
|
3215
|
+
* call-seq:
|
3216
|
+
* res.fformat( column_number ) -> Fixnum
|
3217
|
+
*
|
3218
|
+
* Returns the format (0 for text, 1 for binary) of column
|
3219
|
+
* _column_number_.
|
3220
|
+
*
|
3221
|
+
* Raises ArgumentError if _column_number_ is out of range.
|
3222
|
+
*/
|
3223
|
+
static VALUE
|
3224
|
+
pgresult_fformat(VALUE self, VALUE column_number)
|
3225
|
+
{
|
3226
|
+
PGresult *result = get_pgresult(self);
|
3227
|
+
int fnumber = NUM2INT(column_number);
|
3228
|
+
if (fnumber < 0 || fnumber >= PQnfields(result)) {
|
3229
|
+
rb_raise(rb_eArgError, "Column number is out of range: %d",
|
3230
|
+
fnumber);
|
3231
|
+
}
|
3232
|
+
return INT2FIX(PQfformat(result, fnumber));
|
3233
|
+
}
|
3234
|
+
|
3235
|
+
/*
|
3236
|
+
* call-seq:
|
3237
|
+
* res.ftype( column_number )
|
3238
|
+
*
|
3239
|
+
* Returns the data type associated with _column_number_.
|
3240
|
+
*
|
3241
|
+
* The integer returned is the internal +OID+ number (in PostgreSQL)
|
3242
|
+
* of the type. To get a human-readable value for the type, use the
|
3243
|
+
* returned OID and the field's #fmod value with the format_type() SQL
|
3244
|
+
* function:
|
3245
|
+
*
|
3246
|
+
* # Get the type of the second column of the result 'res'
|
3247
|
+
* typename = conn.
|
3248
|
+
* exec( "SELECT format_type($1,$2)", [res.ftype(1), res.fmod(1)] ).
|
3249
|
+
* getvalue( 0, 0 )
|
3250
|
+
*
|
3251
|
+
* Raises an ArgumentError if _column_number_ is out of range.
|
3252
|
+
*/
|
3253
|
+
static VALUE
|
3254
|
+
pgresult_ftype(VALUE self, VALUE index)
|
3255
|
+
{
|
3256
|
+
PGresult* result = get_pgresult(self);
|
3257
|
+
int i = NUM2INT(index);
|
3258
|
+
if (i < 0 || i >= PQnfields(result)) {
|
3259
|
+
rb_raise(rb_eArgError, "invalid field number %d", i);
|
3260
|
+
}
|
3261
|
+
return INT2NUM(PQftype(result, i));
|
3262
|
+
}
|
3263
|
+
|
3264
|
+
/*
|
3265
|
+
* call-seq:
|
3266
|
+
* res.fmod( column_number )
|
3267
|
+
*
|
3268
|
+
* Returns the type modifier associated with column _column_number_. See
|
3269
|
+
* the #ftype method for an example of how to use this.
|
3270
|
+
*
|
3271
|
+
* Raises an ArgumentError if _column_number_ is out of range.
|
3272
|
+
*/
|
3273
|
+
static VALUE
|
3274
|
+
pgresult_fmod(VALUE self, VALUE column_number)
|
3275
|
+
{
|
3276
|
+
PGresult *result = get_pgresult(self);
|
3277
|
+
int fnumber = NUM2INT(column_number);
|
3278
|
+
int modifier;
|
3279
|
+
if (fnumber < 0 || fnumber >= PQnfields(result)) {
|
3280
|
+
rb_raise(rb_eArgError, "Column number is out of range: %d",
|
3281
|
+
fnumber);
|
3282
|
+
}
|
3283
|
+
modifier = PQfmod(result,fnumber);
|
3284
|
+
|
3285
|
+
return INT2NUM(modifier);
|
3286
|
+
}
|
3287
|
+
|
3288
|
+
/*
|
3289
|
+
* call-seq:
|
3290
|
+
* res.fsize( index )
|
3291
|
+
*
|
3292
|
+
* Returns the size of the field type in bytes. Returns <tt>-1</tt> if the field is variable sized.
|
3293
|
+
*
|
3294
|
+
* res = conn.exec("SELECT myInt, myVarChar50 FROM foo")
|
3295
|
+
* res.size(0) => 4
|
3296
|
+
* res.size(1) => -1
|
3297
|
+
*/
|
3298
|
+
static VALUE
|
3299
|
+
pgresult_fsize(VALUE self, VALUE index)
|
3300
|
+
{
|
3301
|
+
PGresult *result;
|
3302
|
+
int i = NUM2INT(index);
|
3303
|
+
|
3304
|
+
result = get_pgresult(self);
|
3305
|
+
if (i < 0 || i >= PQnfields(result)) {
|
3306
|
+
rb_raise(rb_eArgError,"invalid field number %d", i);
|
3307
|
+
}
|
3308
|
+
return INT2NUM(PQfsize(result, i));
|
3309
|
+
}
|
3310
|
+
|
3311
|
+
/*
|
3312
|
+
* call-seq:
|
3313
|
+
* res.getvalue( tup_num, field_num )
|
3314
|
+
*
|
3315
|
+
* Returns the value in tuple number _tup_num_, field _field_num_,
|
3316
|
+
* or +nil+ if the field is +NULL+.
|
3317
|
+
*/
|
3318
|
+
static VALUE
|
3319
|
+
pgresult_getvalue(VALUE self, VALUE tup_num, VALUE field_num)
|
3320
|
+
{
|
3321
|
+
VALUE ret;
|
3322
|
+
PGresult *result;
|
3323
|
+
int i = NUM2INT(tup_num);
|
3324
|
+
int j = NUM2INT(field_num);
|
3325
|
+
|
3326
|
+
result = get_pgresult(self);
|
3327
|
+
if(i < 0 || i >= PQntuples(result)) {
|
3328
|
+
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
3329
|
+
}
|
3330
|
+
if(j < 0 || j >= PQnfields(result)) {
|
3331
|
+
rb_raise(rb_eArgError,"invalid field number %d", j);
|
3332
|
+
}
|
3333
|
+
if(PQgetisnull(result, i, j))
|
3334
|
+
return Qnil;
|
3335
|
+
ret = rb_tainted_str_new(PQgetvalue(result, i, j),
|
3336
|
+
PQgetlength(result, i, j));
|
3337
|
+
ASSOCIATE_INDEX(ret, self);
|
3338
|
+
return ret;
|
3339
|
+
}
|
3340
|
+
|
3341
|
+
/*
|
3342
|
+
* call-seq:
|
3343
|
+
* res.getisnull(tuple_position, field_position) -> boolean
|
3344
|
+
*
|
3345
|
+
* Returns +true+ if the specified value is +nil+; +false+ otherwise.
|
3346
|
+
*/
|
3347
|
+
static VALUE
|
3348
|
+
pgresult_getisnull(VALUE self, VALUE tup_num, VALUE field_num)
|
3349
|
+
{
|
3350
|
+
PGresult *result;
|
3351
|
+
int i = NUM2INT(tup_num);
|
3352
|
+
int j = NUM2INT(field_num);
|
3353
|
+
|
3354
|
+
result = get_pgresult(self);
|
3355
|
+
if (i < 0 || i >= PQntuples(result)) {
|
3356
|
+
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
3357
|
+
}
|
3358
|
+
if (j < 0 || j >= PQnfields(result)) {
|
3359
|
+
rb_raise(rb_eArgError,"invalid field number %d", j);
|
3360
|
+
}
|
3361
|
+
return PQgetisnull(result, i, j) ? Qtrue : Qfalse;
|
3362
|
+
}
|
3363
|
+
|
3364
|
+
/*
|
3365
|
+
* call-seq:
|
3366
|
+
* res.getlength( tup_num, field_num ) -> Fixnum
|
3367
|
+
*
|
3368
|
+
* Returns the (String) length of the field in bytes.
|
3369
|
+
*
|
3370
|
+
* Equivalent to <tt>res.value(<i>tup_num</i>,<i>field_num</i>).length</tt>.
|
3371
|
+
*/
|
3372
|
+
static VALUE
|
3373
|
+
pgresult_getlength(VALUE self, VALUE tup_num, VALUE field_num)
|
3374
|
+
{
|
3375
|
+
PGresult *result;
|
3376
|
+
int i = NUM2INT(tup_num);
|
3377
|
+
int j = NUM2INT(field_num);
|
3378
|
+
|
3379
|
+
result = get_pgresult(self);
|
3380
|
+
if (i < 0 || i >= PQntuples(result)) {
|
3381
|
+
rb_raise(rb_eArgError,"invalid tuple number %d", i);
|
3382
|
+
}
|
3383
|
+
if (j < 0 || j >= PQnfields(result)) {
|
3384
|
+
rb_raise(rb_eArgError,"invalid field number %d", j);
|
3385
|
+
}
|
3386
|
+
return INT2FIX(PQgetlength(result, i, j));
|
3387
|
+
}
|
3388
|
+
|
3389
|
+
/*
|
3390
|
+
* call-seq:
|
3391
|
+
* res.nparams() -> Fixnum
|
3392
|
+
*
|
3393
|
+
* Returns the number of parameters of a prepared statement.
|
3394
|
+
* Only useful for the result returned by conn.describePrepared
|
3395
|
+
*/
|
3396
|
+
static VALUE
|
3397
|
+
pgresult_nparams(VALUE self)
|
3398
|
+
{
|
3399
|
+
PGresult *result;
|
3400
|
+
|
3401
|
+
result = get_pgresult(self);
|
3402
|
+
return INT2FIX(PQnparams(result));
|
3403
|
+
}
|
3404
|
+
|
3405
|
+
/*
|
3406
|
+
* call-seq:
|
3407
|
+
* res.paramtype( param_number ) -> Oid
|
3408
|
+
*
|
3409
|
+
* Returns the Oid of the data type of parameter _param_number_.
|
3410
|
+
* Only useful for the result returned by conn.describePrepared
|
3411
|
+
*/
|
3412
|
+
static VALUE
|
3413
|
+
pgresult_paramtype(VALUE self, VALUE param_number)
|
3414
|
+
{
|
3415
|
+
PGresult *result;
|
3416
|
+
|
3417
|
+
result = get_pgresult(self);
|
3418
|
+
return INT2FIX(PQparamtype(result,NUM2INT(param_number)));
|
3419
|
+
}
|
3420
|
+
|
3421
|
+
/*
|
3422
|
+
* call-seq:
|
3423
|
+
* res.cmd_status() -> String
|
3424
|
+
*
|
3425
|
+
* Returns the status string of the last query command.
|
3426
|
+
*/
|
3427
|
+
static VALUE
|
3428
|
+
pgresult_cmd_status(VALUE self)
|
3429
|
+
{
|
3430
|
+
VALUE ret = rb_tainted_str_new2(PQcmdStatus(get_pgresult(self)));
|
3431
|
+
ASSOCIATE_INDEX(ret, self);
|
3432
|
+
return ret;
|
3433
|
+
}
|
3434
|
+
|
3435
|
+
/*
|
3436
|
+
* call-seq:
|
3437
|
+
* res.cmd_tuples() -> Fixnum
|
3438
|
+
*
|
3439
|
+
* Returns the number of tuples (rows) affected by the SQL command.
|
3440
|
+
*
|
3441
|
+
* If the SQL command that generated the PGresult was not one of:
|
3442
|
+
* * +INSERT+
|
3443
|
+
* * +UPDATE+
|
3444
|
+
* * +DELETE+
|
3445
|
+
* * +MOVE+
|
3446
|
+
* * +FETCH+
|
3447
|
+
* or if no tuples were affected, <tt>0</tt> is returned.
|
3448
|
+
*/
|
3449
|
+
static VALUE
|
3450
|
+
pgresult_cmd_tuples(VALUE self)
|
3451
|
+
{
|
3452
|
+
long n;
|
3453
|
+
n = strtol(PQcmdTuples(get_pgresult(self)),NULL, 10);
|
3454
|
+
return INT2NUM(n);
|
3455
|
+
}
|
3456
|
+
|
3457
|
+
/*
|
3458
|
+
* call-seq:
|
3459
|
+
* res.oid_value() -> Fixnum
|
3460
|
+
*
|
3461
|
+
* Returns the +oid+ of the inserted row if applicable,
|
3462
|
+
* otherwise +nil+.
|
3463
|
+
*/
|
3464
|
+
static VALUE
|
3465
|
+
pgresult_oid_value(VALUE self)
|
3466
|
+
{
|
3467
|
+
Oid n = PQoidValue(get_pgresult(self));
|
3468
|
+
if (n == InvalidOid)
|
3469
|
+
return Qnil;
|
3470
|
+
else
|
3471
|
+
return INT2FIX(n);
|
3472
|
+
}
|
3473
|
+
|
3474
|
+
/* Utility methods not in libpq */
|
3475
|
+
|
3476
|
+
/*
|
3477
|
+
* call-seq:
|
3478
|
+
* res[ n ] -> Hash
|
3479
|
+
*
|
3480
|
+
* Returns tuple _n_ as a hash.
|
3481
|
+
*/
|
3482
|
+
static VALUE
|
3483
|
+
pgresult_aref(VALUE self, VALUE index)
|
3484
|
+
{
|
3485
|
+
PGresult *result = get_pgresult(self);
|
3486
|
+
int tuple_num = NUM2INT(index);
|
3487
|
+
int field_num;
|
3488
|
+
VALUE fname,val;
|
3489
|
+
VALUE tuple;
|
3490
|
+
|
3491
|
+
if(tuple_num < 0 || tuple_num >= PQntuples(result))
|
3492
|
+
rb_raise(rb_eIndexError, "Index %d is out of range", tuple_num);
|
3493
|
+
tuple = rb_hash_new();
|
3494
|
+
for(field_num = 0; field_num < PQnfields(result); field_num++) {
|
3495
|
+
fname = rb_tainted_str_new2(PQfname(result,field_num));
|
3496
|
+
ASSOCIATE_INDEX(fname, self);
|
3497
|
+
if(PQgetisnull(result, tuple_num, field_num)) {
|
3498
|
+
rb_hash_aset(tuple, fname, Qnil);
|
3499
|
+
}
|
3500
|
+
else {
|
3501
|
+
val = rb_tainted_str_new(PQgetvalue(result, tuple_num, field_num),
|
3502
|
+
PQgetlength(result, tuple_num, field_num));
|
3503
|
+
|
3504
|
+
/* associate client encoding for text format only */
|
3505
|
+
if(0 == PQfformat(result, field_num)) {
|
3506
|
+
ASSOCIATE_INDEX(val, self);
|
3507
|
+
} else {
|
3508
|
+
#ifdef M17N_SUPPORTED
|
3509
|
+
rb_enc_associate(val, rb_ascii8bit_encoding());
|
3510
|
+
#endif
|
3511
|
+
}
|
3512
|
+
rb_hash_aset(tuple, fname, val);
|
3513
|
+
}
|
3514
|
+
}
|
3515
|
+
return tuple;
|
3516
|
+
}
|
3517
|
+
|
3518
|
+
|
3519
|
+
/*
|
3520
|
+
* call-seq:
|
3521
|
+
* res.column_values( n ) -> array
|
3522
|
+
*
|
3523
|
+
* Returns an Array of the values from the nth column of each
|
3524
|
+
* tuple in the result.
|
3525
|
+
*
|
3526
|
+
*/
|
3527
|
+
static VALUE
|
3528
|
+
pgresult_column_values(VALUE self, VALUE index)
|
3529
|
+
{
|
3530
|
+
int col = NUM2INT( index );
|
3531
|
+
return make_column_result_array( self, col );
|
3532
|
+
}
|
3533
|
+
|
3534
|
+
|
3535
|
+
/*
|
3536
|
+
* call-seq:
|
3537
|
+
* res.field_values( field ) -> array
|
3538
|
+
*
|
3539
|
+
* Returns an Array of the values from the given _field_ of each tuple in the result.
|
3540
|
+
*
|
3541
|
+
*/
|
3542
|
+
static VALUE
|
3543
|
+
pgresult_field_values( VALUE self, VALUE field )
|
3544
|
+
{
|
3545
|
+
PGresult *result = get_pgresult( self );
|
3546
|
+
const char *fieldname = RSTRING_PTR( field );
|
3547
|
+
int fnum = PQfnumber( result, fieldname );
|
3548
|
+
|
3549
|
+
if ( fnum < 0 )
|
3550
|
+
rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
|
3551
|
+
|
3552
|
+
return make_column_result_array( self, fnum );
|
3553
|
+
}
|
3554
|
+
|
3555
|
+
|
3556
|
+
/*
|
3557
|
+
* Make a Ruby array out of the encoded values from the specified
|
3558
|
+
* column in the given result.
|
3559
|
+
*/
|
3560
|
+
static VALUE
|
3561
|
+
make_column_result_array( VALUE self, int col )
|
3562
|
+
{
|
3563
|
+
PGresult *result = get_pgresult( self );
|
3564
|
+
int row = PQntuples( result );
|
3565
|
+
VALUE ary = rb_ary_new2( row );
|
3566
|
+
VALUE val = Qnil;
|
3567
|
+
|
3568
|
+
if ( col >= PQnfields(result) )
|
3569
|
+
rb_raise( rb_eIndexError, "no column %d in result", col );
|
3570
|
+
|
3571
|
+
while ( row-- ) {
|
3572
|
+
val = rb_tainted_str_new( PQgetvalue(result, row, col),
|
3573
|
+
PQgetlength(result, row, col) );
|
3574
|
+
|
3575
|
+
/* associate client encoding for text format only */
|
3576
|
+
if ( 0 == PQfformat(result, col) ) {
|
3577
|
+
ASSOCIATE_INDEX( val, self );
|
3578
|
+
} else {
|
3579
|
+
#ifdef M17N_SUPPORTED
|
3580
|
+
rb_enc_associate( val, rb_ascii8bit_encoding() );
|
3581
|
+
#endif
|
3582
|
+
}
|
3583
|
+
|
3584
|
+
rb_ary_store( ary, row, val );
|
3585
|
+
}
|
3586
|
+
|
3587
|
+
return ary;
|
3588
|
+
}
|
3589
|
+
|
3590
|
+
|
3591
|
+
/*
|
3592
|
+
* call-seq:
|
3593
|
+
* res.each{ |tuple| ... }
|
3594
|
+
*
|
3595
|
+
* Invokes block for each tuple in the result set.
|
3596
|
+
*/
|
3597
|
+
static VALUE
|
3598
|
+
pgresult_each(VALUE self)
|
3599
|
+
{
|
3600
|
+
PGresult *result = get_pgresult(self);
|
3601
|
+
int tuple_num;
|
3602
|
+
|
3603
|
+
for(tuple_num = 0; tuple_num < PQntuples(result); tuple_num++) {
|
3604
|
+
rb_yield(pgresult_aref(self, INT2NUM(tuple_num)));
|
3605
|
+
}
|
3606
|
+
return self;
|
3607
|
+
}
|
3608
|
+
|
3609
|
+
/*
|
3610
|
+
* call-seq:
|
3611
|
+
* res.fields() -> Array
|
3612
|
+
*
|
3613
|
+
* Returns an array of Strings representing the names of the fields in the result.
|
3614
|
+
*/
|
3615
|
+
static VALUE
|
3616
|
+
pgresult_fields(VALUE self)
|
3617
|
+
{
|
3618
|
+
PGresult *result;
|
3619
|
+
VALUE ary;
|
3620
|
+
int n, i;
|
3621
|
+
|
3622
|
+
result = get_pgresult(self);
|
3623
|
+
n = PQnfields(result);
|
3624
|
+
ary = rb_ary_new2(n);
|
3625
|
+
for (i=0;i<n;i++) {
|
3626
|
+
VALUE val = rb_tainted_str_new2(PQfname(result, i));
|
3627
|
+
ASSOCIATE_INDEX(val, self);
|
3628
|
+
rb_ary_push(ary, val);
|
3629
|
+
}
|
3630
|
+
return ary;
|
3631
|
+
}
|
3632
|
+
|
3633
|
+
#ifdef M17N_SUPPORTED
|
3634
|
+
/**
|
3635
|
+
* The mapping from canonical encoding names in PostgreSQL to ones in Ruby.
|
3636
|
+
*/
|
3637
|
+
static const char * const (enc_pg2ruby_mapping[][2]) = {
|
3638
|
+
{"BIG5", "Big5" },
|
3639
|
+
{"EUC_CN", "GB2312" },
|
3640
|
+
{"EUC_JP", "EUC-JP" },
|
3641
|
+
{"EUC_JIS_2004", "EUC-JP" },
|
3642
|
+
{"EUC_KR", "EUC-KR" },
|
3643
|
+
{"EUC_TW", "EUC-TW" },
|
3644
|
+
{"GB18030", "GB18030" },
|
3645
|
+
{"GBK", "GBK" },
|
3646
|
+
{"ISO_8859_5", "ISO-8859-5" },
|
3647
|
+
{"ISO_8859_6", "ISO-8859-6" },
|
3648
|
+
{"ISO_8859_7", "ISO-8859-7" },
|
3649
|
+
{"ISO_8859_8", "ISO-8859-8" },
|
3650
|
+
/* {"JOHAB", "JOHAB" }, dummy */
|
3651
|
+
{"KOI8", "KOI8-U" },
|
3652
|
+
{"LATIN1", "ISO-8859-1" },
|
3653
|
+
{"LATIN2", "ISO-8859-2" },
|
3654
|
+
{"LATIN3", "ISO-8859-3" },
|
3655
|
+
{"LATIN4", "ISO-8859-4" },
|
3656
|
+
{"LATIN5", "ISO-8859-5" },
|
3657
|
+
{"LATIN6", "ISO-8859-6" },
|
3658
|
+
{"LATIN7", "ISO-8859-7" },
|
3659
|
+
{"LATIN8", "ISO-8859-8" },
|
3660
|
+
{"LATIN9", "ISO-8859-9" },
|
3661
|
+
{"LATIN10", "ISO-8859-10" },
|
3662
|
+
{"MULE_INTERNAL", "Emacs-Mule" },
|
3663
|
+
{"SJIS", "Windows-31J" },
|
3664
|
+
{"SHIFT_JIS_2004","Windows-31J" },
|
3665
|
+
/*{"SQL_ASCII", NULL }, special case*/
|
3666
|
+
{"UHC", "CP949" },
|
3667
|
+
{"UTF8", "UTF-8" },
|
3668
|
+
{"WIN866", "IBM866" },
|
3669
|
+
{"WIN874", "Windows-874" },
|
3670
|
+
{"WIN1250", "Windows-1250"},
|
3671
|
+
{"WIN1251", "Windows-1251"},
|
3672
|
+
{"WIN1252", "Windows-1252"},
|
3673
|
+
{"WIN1253", "Windows-1253"},
|
3674
|
+
{"WIN1254", "Windows-1254"},
|
3675
|
+
{"WIN1255", "Windows-1255"},
|
3676
|
+
{"WIN1256", "Windows-1256"},
|
3677
|
+
{"WIN1257", "Windows-1257"},
|
3678
|
+
{"WIN1258", "Windows-1258"}
|
3679
|
+
};
|
3680
|
+
|
3681
|
+
|
3682
|
+
/*
|
3683
|
+
* A cache of mapping from PostgreSQL's encoding indices to Ruby's rb_encoding*s.
|
3684
|
+
*/
|
3685
|
+
static struct st_table *enc_pg2ruby;
|
3686
|
+
static ID s_id_index;
|
3687
|
+
|
3688
|
+
static int enc_get_index(VALUE val)
|
3689
|
+
{
|
3690
|
+
int i = ENCODING_GET_INLINED(val);
|
3691
|
+
if (i == ENCODING_INLINE_MAX) {
|
3692
|
+
VALUE iv = rb_ivar_get(val, s_id_index);
|
3693
|
+
i = NUM2INT(iv);
|
3694
|
+
}
|
3695
|
+
return i;
|
3696
|
+
}
|
3697
|
+
|
3698
|
+
extern int rb_enc_alias(const char *alias, const char *orig); /* declaration missing in Ruby 1.9.1 */
|
3699
|
+
static rb_encoding *
|
3700
|
+
find_or_create_johab(void)
|
3701
|
+
{
|
3702
|
+
static const char * const aliases[] = { "JOHAB", "Windows-1361", "CP1361" };
|
3703
|
+
int enc_index;
|
3704
|
+
int i;
|
3705
|
+
for (i = 0; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
|
3706
|
+
enc_index = rb_enc_find_index(aliases[i]);
|
3707
|
+
if (enc_index > 0) return rb_enc_from_index(enc_index);
|
3708
|
+
}
|
3709
|
+
|
3710
|
+
enc_index = rb_define_dummy_encoding(aliases[0]);
|
3711
|
+
for (i = 1; i < sizeof(aliases)/sizeof(aliases[0]); ++i) {
|
3712
|
+
rb_enc_alias(aliases[i], aliases[0]);
|
3713
|
+
}
|
3714
|
+
return rb_enc_from_index(enc_index);
|
3715
|
+
}
|
3716
|
+
|
3717
|
+
/*
|
3718
|
+
* Returns the client_encoding of the given connection as a rb_encoding*
|
3719
|
+
*
|
3720
|
+
* * returns NULL if the client encoding is 'SQL_ASCII'.
|
3721
|
+
* * returns ASCII-8BIT if the client encoding is unknown.
|
3722
|
+
*/
|
3723
|
+
static rb_encoding *
|
3724
|
+
pgconn_get_client_encoding_as_rb_encoding(PGconn* conn)
|
3725
|
+
{
|
3726
|
+
rb_encoding *enc;
|
3727
|
+
int enc_id = PQclientEncoding(conn);
|
3728
|
+
|
3729
|
+
if (st_lookup(enc_pg2ruby, (st_data_t)enc_id, (st_data_t*)&enc)) {
|
3730
|
+
return enc;
|
3731
|
+
}
|
3732
|
+
else {
|
3733
|
+
int i;
|
3734
|
+
const char *name = pg_encoding_to_char(enc_id);
|
3735
|
+
if (strcmp("SQL_ASCII", name) == 0) {
|
3736
|
+
enc = NULL;
|
3737
|
+
goto cache;
|
3738
|
+
}
|
3739
|
+
for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
|
3740
|
+
if (strcmp(name, enc_pg2ruby_mapping[i][0]) == 0) {
|
3741
|
+
enc = rb_enc_find(enc_pg2ruby_mapping[i][1]);
|
3742
|
+
goto cache;
|
3743
|
+
}
|
3744
|
+
}
|
3745
|
+
|
3746
|
+
/* Ruby 1.9.1 does not supoort JOHAB */
|
3747
|
+
if (strcmp(name, "JOHAB") == 0) {
|
3748
|
+
enc = find_or_create_johab();
|
3749
|
+
goto cache;
|
3750
|
+
}
|
3751
|
+
|
3752
|
+
enc = rb_ascii8bit_encoding();
|
3753
|
+
}
|
3754
|
+
cache:
|
3755
|
+
st_insert(enc_pg2ruby, (st_data_t)enc_id, (st_data_t)enc);
|
3756
|
+
return enc;
|
3757
|
+
}
|
3758
|
+
|
3759
|
+
/*
|
3760
|
+
* call-seq:
|
3761
|
+
* conn.internal_encoding() -> Encoding
|
3762
|
+
*
|
3763
|
+
* defined in Ruby 1.9 or later.
|
3764
|
+
*
|
3765
|
+
* Returns:
|
3766
|
+
* * an Encoding - client_encoding of the connection as a Ruby Encoding object.
|
3767
|
+
* * nil - the client_encoding is 'SQL_ASCII'
|
3768
|
+
*/
|
3769
|
+
static VALUE
|
3770
|
+
pgconn_internal_encoding(VALUE self)
|
3771
|
+
{
|
3772
|
+
return rb_enc_from_encoding(pgconn_get_client_encoding_as_rb_encoding(get_pgconn(self)));
|
3773
|
+
}
|
3774
|
+
|
3775
|
+
static VALUE pgconn_external_encoding(VALUE self);
|
3776
|
+
|
3777
|
+
/*
|
3778
|
+
* call-seq:
|
3779
|
+
* conn.internal_encoding = value
|
3780
|
+
*
|
3781
|
+
* A wrapper of +PGconn#set_client_encoding+.
|
3782
|
+
* defined in Ruby 1.9 or later.
|
3783
|
+
*
|
3784
|
+
* +value+ can be one of:
|
3785
|
+
* * an Encoding
|
3786
|
+
* * a String - a name of Encoding
|
3787
|
+
* * +nil+ - sets 'SQL_ASCII' to the client_encoding.
|
3788
|
+
*/
|
3789
|
+
static VALUE
|
3790
|
+
pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
3791
|
+
{
|
3792
|
+
if (NIL_P(enc)) {
|
3793
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("SQL_ASCII"));
|
3794
|
+
return enc;
|
3795
|
+
}
|
3796
|
+
else if (TYPE(enc) == T_STRING && strcasecmp("JOHAB", RSTRING_PTR(enc)) == 0) {
|
3797
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3798
|
+
return enc;
|
3799
|
+
}
|
3800
|
+
else {
|
3801
|
+
int i;
|
3802
|
+
const char *name;
|
3803
|
+
name = rb_enc_name(rb_to_encoding(enc));
|
3804
|
+
|
3805
|
+
/* sequential search becuase rarely called */
|
3806
|
+
for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
|
3807
|
+
if (strcmp(name, enc_pg2ruby_mapping[i][1]) == 0) {
|
3808
|
+
if (PQsetClientEncoding(get_pgconn(self), enc_pg2ruby_mapping[i][0]) == -1) {
|
3809
|
+
VALUE server_encoding = pgconn_external_encoding(self);
|
3810
|
+
rb_raise(rb_eEncCompatError, "imcompatible character encodings: %s and %s",
|
3811
|
+
rb_enc_name(rb_to_encoding(server_encoding)),
|
3812
|
+
enc_pg2ruby_mapping[i][0]);
|
3813
|
+
}
|
3814
|
+
return enc;
|
3815
|
+
}
|
3816
|
+
}
|
3817
|
+
|
3818
|
+
/* Ruby 1.9.1 does not support JOHAB */
|
3819
|
+
if (strcasecmp(name, "JOHAB") == 0) {
|
3820
|
+
pgconn_set_client_encoding(self, rb_usascii_str_new_cstr("JOHAB"));
|
3821
|
+
return enc;
|
3822
|
+
}
|
3823
|
+
}
|
3824
|
+
|
3825
|
+
enc = rb_inspect(enc);
|
3826
|
+
rb_raise(rb_ePGError, "unknown encoding: %s", StringValuePtr(enc));
|
3827
|
+
}
|
3828
|
+
|
3829
|
+
|
3830
|
+
|
3831
|
+
static VALUE enc_server_encoding_getvalue(VALUE pgresult)
|
3832
|
+
{
|
3833
|
+
return pgresult_getvalue(pgresult, INT2FIX(0), INT2FIX(0));
|
3834
|
+
}
|
3835
|
+
|
3836
|
+
/*
|
3837
|
+
* call-seq:
|
3838
|
+
* conn.external_encoding() -> Encoding
|
3839
|
+
*
|
3840
|
+
* defined in Ruby 1.9 or later.
|
3841
|
+
* * Returns the server_encoding of the connected database as a Ruby Encoding object.
|
3842
|
+
* * Maps 'SQL_ASCII' to ASCII-8BIT.
|
3843
|
+
*/
|
3844
|
+
static VALUE
|
3845
|
+
pgconn_external_encoding(VALUE self)
|
3846
|
+
{
|
3847
|
+
VALUE enc;
|
3848
|
+
enc = rb_iv_get(self, "@external_encoding");
|
3849
|
+
if (RTEST(enc)) {
|
3850
|
+
return enc;
|
3851
|
+
}
|
3852
|
+
else {
|
3853
|
+
int i;
|
3854
|
+
VALUE query = rb_usascii_str_new_cstr("SHOW server_encoding");
|
3855
|
+
VALUE pgresult = pgconn_exec(1, &query, self);
|
3856
|
+
VALUE enc_name = rb_ensure(enc_server_encoding_getvalue, pgresult, pgresult_clear, pgresult);
|
3857
|
+
|
3858
|
+
if (strcmp("SQL_ASCII", StringValuePtr(enc_name)) == 0) {
|
3859
|
+
enc = rb_enc_from_encoding(rb_ascii8bit_encoding());
|
3860
|
+
goto cache;
|
3861
|
+
}
|
3862
|
+
for (i = 0; i < sizeof(enc_pg2ruby_mapping)/sizeof(enc_pg2ruby_mapping[0]); ++i) {
|
3863
|
+
if (strcmp(StringValuePtr(enc_name), enc_pg2ruby_mapping[i][0]) == 0) {
|
3864
|
+
enc = rb_enc_from_encoding(rb_enc_find(enc_pg2ruby_mapping[i][1]));
|
3865
|
+
goto cache;
|
3866
|
+
}
|
3867
|
+
}
|
3868
|
+
|
3869
|
+
/* Ruby 1.9.1 does not supoort JOHAB */
|
3870
|
+
if (strcmp(StringValuePtr(enc_name), "JOHAB") == 0) {
|
3871
|
+
enc = rb_enc_from_encoding(find_or_create_johab());
|
3872
|
+
goto cache;
|
3873
|
+
}
|
3874
|
+
|
3875
|
+
/* fallback */
|
3876
|
+
enc = rb_enc_from_encoding(rb_enc_find(StringValuePtr(enc_name)));
|
3877
|
+
}
|
3878
|
+
|
3879
|
+
cache:
|
3880
|
+
rb_iv_set(self, "@external_encoding", enc);
|
3881
|
+
return enc;
|
3882
|
+
}
|
3883
|
+
|
3884
|
+
static void
|
3885
|
+
init_m17n(void)
|
3886
|
+
{
|
3887
|
+
enc_pg2ruby = st_init_numtable();
|
3888
|
+
s_id_index = rb_intern("@encoding");
|
3889
|
+
rb_define_method(rb_cPGconn, "internal_encoding", pgconn_internal_encoding, 0);
|
3890
|
+
rb_define_method(rb_cPGconn, "internal_encoding=", pgconn_internal_encoding_set, 1);
|
3891
|
+
rb_define_method(rb_cPGconn, "external_encoding", pgconn_external_encoding, 0);
|
3892
|
+
}
|
3893
|
+
|
3894
|
+
|
3895
|
+
#endif
|
3896
|
+
/**************************************************************************/
|
3897
|
+
|
3898
|
+
void
|
3899
|
+
Init_pg_ext()
|
3900
|
+
{
|
3901
|
+
rb_ePGError = rb_define_class("PGError", rb_eStandardError);
|
3902
|
+
rb_cPGconn = rb_define_class("PGconn", rb_cObject);
|
3903
|
+
rb_cPGresult = rb_define_class("PGresult", rb_cObject);
|
3904
|
+
|
3905
|
+
/* Library version */
|
3906
|
+
rb_define_const( rb_cPGconn, "VERSION", rb_str_new2(VERSION) );
|
3907
|
+
|
3908
|
+
/*************************
|
3909
|
+
* PGError
|
3910
|
+
*************************/
|
3911
|
+
rb_define_alias(rb_ePGError, "error", "message");
|
3912
|
+
rb_define_attr(rb_ePGError, "connection", 1, 0);
|
3913
|
+
rb_define_attr(rb_ePGError, "result", 1, 0);
|
3914
|
+
|
3915
|
+
/*************************
|
3916
|
+
* PGconn
|
3917
|
+
*************************/
|
3918
|
+
|
3919
|
+
/****** PGconn CLASS METHODS ******/
|
3920
|
+
rb_define_alloc_func(rb_cPGconn, pgconn_alloc);
|
3921
|
+
rb_define_singleton_alias(rb_cPGconn, "connect", "new");
|
3922
|
+
rb_define_singleton_alias(rb_cPGconn, "open", "new");
|
3923
|
+
rb_define_singleton_alias(rb_cPGconn, "setdb", "new");
|
3924
|
+
rb_define_singleton_alias(rb_cPGconn, "setdblogin", "new");
|
3925
|
+
rb_define_singleton_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
3926
|
+
rb_define_singleton_alias(rb_cPGconn, "escape", "escape_string");
|
3927
|
+
rb_define_singleton_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
3928
|
+
rb_define_singleton_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
3929
|
+
rb_define_singleton_method(rb_cPGconn, "isthreadsafe", pgconn_s_isthreadsafe, 0);
|
3930
|
+
rb_define_singleton_method(rb_cPGconn, "encrypt_password", pgconn_s_encrypt_password, 2);
|
3931
|
+
rb_define_singleton_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
3932
|
+
rb_define_singleton_method(rb_cPGconn, "connect_start", pgconn_s_connect_start, -1);
|
3933
|
+
rb_define_singleton_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
3934
|
+
|
3935
|
+
/****** PGconn CLASS CONSTANTS: Connection Status ******/
|
3936
|
+
|
3937
|
+
/* Connection succeeded */
|
3938
|
+
rb_define_const(rb_cPGconn, "CONNECTION_OK", INT2FIX(CONNECTION_OK));
|
3939
|
+
/* Connection failed */
|
3940
|
+
rb_define_const(rb_cPGconn, "CONNECTION_BAD", INT2FIX(CONNECTION_BAD));
|
3941
|
+
|
3942
|
+
/****** PGconn CLASS CONSTANTS: Nonblocking connection status ******/
|
3943
|
+
|
3944
|
+
/* Waiting for connection to be made. */
|
3945
|
+
rb_define_const(rb_cPGconn, "CONNECTION_STARTED", INT2FIX(CONNECTION_STARTED));
|
3946
|
+
/* Connection OK; waiting to send. */
|
3947
|
+
rb_define_const(rb_cPGconn, "CONNECTION_MADE", INT2FIX(CONNECTION_MADE));
|
3948
|
+
/* Waiting for a response from the server. */
|
3949
|
+
rb_define_const(rb_cPGconn, "CONNECTION_AWAITING_RESPONSE", INT2FIX(CONNECTION_AWAITING_RESPONSE));
|
3950
|
+
/* Received authentication; waiting for backend start-up to finish. */
|
3951
|
+
rb_define_const(rb_cPGconn, "CONNECTION_AUTH_OK", INT2FIX(CONNECTION_AUTH_OK));
|
3952
|
+
/* Negotiating SSL encryption. */
|
3953
|
+
rb_define_const(rb_cPGconn, "CONNECTION_SSL_STARTUP", INT2FIX(CONNECTION_SSL_STARTUP));
|
3954
|
+
/* Negotiating environment-driven parameter settings. */
|
3955
|
+
rb_define_const(rb_cPGconn, "CONNECTION_SETENV", INT2FIX(CONNECTION_SETENV));
|
3956
|
+
|
3957
|
+
/****** PGconn CLASS CONSTANTS: Nonblocking connection polling status ******/
|
3958
|
+
|
3959
|
+
/* Async connection is waiting to read */
|
3960
|
+
rb_define_const(rb_cPGconn, "PGRES_POLLING_READING", INT2FIX(PGRES_POLLING_READING));
|
3961
|
+
/* Async connection is waiting to write */
|
3962
|
+
rb_define_const(rb_cPGconn, "PGRES_POLLING_WRITING", INT2FIX(PGRES_POLLING_WRITING));
|
3963
|
+
/* Async connection failed or was reset */
|
3964
|
+
rb_define_const(rb_cPGconn, "PGRES_POLLING_FAILED", INT2FIX(PGRES_POLLING_FAILED));
|
3965
|
+
/* Async connection succeeded */
|
3966
|
+
rb_define_const(rb_cPGconn, "PGRES_POLLING_OK", INT2FIX(PGRES_POLLING_OK));
|
3967
|
+
|
3968
|
+
/****** PGconn CLASS CONSTANTS: Transaction Status ******/
|
3969
|
+
|
3970
|
+
/* Transaction is currently idle (#transaction_status) */
|
3971
|
+
rb_define_const(rb_cPGconn, "PQTRANS_IDLE", INT2FIX(PQTRANS_IDLE));
|
3972
|
+
/* Transaction is currently active; query has been sent to the server, but not yet completed. (#transaction_status) */
|
3973
|
+
rb_define_const(rb_cPGconn, "PQTRANS_ACTIVE", INT2FIX(PQTRANS_ACTIVE));
|
3974
|
+
/* Transaction is currently idle, in a valid transaction block (#transaction_status) */
|
3975
|
+
rb_define_const(rb_cPGconn, "PQTRANS_INTRANS", INT2FIX(PQTRANS_INTRANS));
|
3976
|
+
/* Transaction is currently idle, in a failed transaction block (#transaction_status) */
|
3977
|
+
rb_define_const(rb_cPGconn, "PQTRANS_INERROR", INT2FIX(PQTRANS_INERROR));
|
3978
|
+
/* Transaction's connection is bad (#transaction_status) */
|
3979
|
+
rb_define_const(rb_cPGconn, "PQTRANS_UNKNOWN", INT2FIX(PQTRANS_UNKNOWN));
|
3980
|
+
|
3981
|
+
/****** PGconn CLASS CONSTANTS: Error Verbosity ******/
|
3982
|
+
|
3983
|
+
/* Terse error verbosity level (#set_error_verbosity) */
|
3984
|
+
rb_define_const(rb_cPGconn, "PQERRORS_TERSE", INT2FIX(PQERRORS_TERSE));
|
3985
|
+
/* Default error verbosity level (#set_error_verbosity) */
|
3986
|
+
rb_define_const(rb_cPGconn, "PQERRORS_DEFAULT", INT2FIX(PQERRORS_DEFAULT));
|
3987
|
+
/* Verbose error verbosity level (#set_error_verbosity) */
|
3988
|
+
rb_define_const(rb_cPGconn, "PQERRORS_VERBOSE", INT2FIX(PQERRORS_VERBOSE));
|
3989
|
+
|
3990
|
+
/****** PGconn CLASS CONSTANTS: Large Objects ******/
|
3991
|
+
|
3992
|
+
/* Flag for #lo_creat, #lo_open -- open for writing */
|
3993
|
+
rb_define_const(rb_cPGconn, "INV_WRITE", INT2FIX(INV_WRITE));
|
3994
|
+
/* Flag for #lo_creat, #lo_open -- open for reading */
|
3995
|
+
rb_define_const(rb_cPGconn, "INV_READ", INT2FIX(INV_READ));
|
3996
|
+
/* Flag for #lo_lseek -- seek from object start */
|
3997
|
+
rb_define_const(rb_cPGconn, "SEEK_SET", INT2FIX(SEEK_SET));
|
3998
|
+
/* Flag for #lo_lseek -- seek from current position */
|
3999
|
+
rb_define_const(rb_cPGconn, "SEEK_CUR", INT2FIX(SEEK_CUR));
|
4000
|
+
/* Flag for #lo_lseek -- seek from object end */
|
4001
|
+
rb_define_const(rb_cPGconn, "SEEK_END", INT2FIX(SEEK_END));
|
4002
|
+
|
4003
|
+
/****** PGconn INSTANCE METHODS: Connection Control ******/
|
4004
|
+
rb_define_method(rb_cPGconn, "initialize", pgconn_init, -1);
|
4005
|
+
rb_define_method(rb_cPGconn, "connect_poll", pgconn_connect_poll, 0);
|
4006
|
+
rb_define_method(rb_cPGconn, "finish", pgconn_finish, 0);
|
4007
|
+
rb_define_method(rb_cPGconn, "reset", pgconn_reset, 0);
|
4008
|
+
rb_define_method(rb_cPGconn, "reset_start", pgconn_reset_start, 0);
|
4009
|
+
rb_define_method(rb_cPGconn, "reset_poll", pgconn_reset_poll, 0);
|
4010
|
+
rb_define_method(rb_cPGconn, "conndefaults", pgconn_s_conndefaults, 0);
|
4011
|
+
rb_define_alias(rb_cPGconn, "close", "finish");
|
4012
|
+
|
4013
|
+
/****** PGconn INSTANCE METHODS: Connection Status ******/
|
4014
|
+
rb_define_method(rb_cPGconn, "db", pgconn_db, 0);
|
4015
|
+
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
4016
|
+
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
4017
|
+
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
4018
|
+
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
4019
|
+
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
4020
|
+
rb_define_method(rb_cPGconn, "options", pgconn_options, 0);
|
4021
|
+
rb_define_method(rb_cPGconn, "status", pgconn_status, 0);
|
4022
|
+
rb_define_method(rb_cPGconn, "transaction_status", pgconn_transaction_status, 0);
|
4023
|
+
rb_define_method(rb_cPGconn, "parameter_status", pgconn_parameter_status, 1);
|
4024
|
+
rb_define_method(rb_cPGconn, "protocol_version", pgconn_protocol_version, 0);
|
4025
|
+
rb_define_method(rb_cPGconn, "server_version", pgconn_server_version, 0);
|
4026
|
+
rb_define_method(rb_cPGconn, "error_message", pgconn_error_message, 0);
|
4027
|
+
rb_define_method(rb_cPGconn, "socket", pgconn_socket, 0);
|
4028
|
+
rb_define_method(rb_cPGconn, "backend_pid", pgconn_backend_pid, 0);
|
4029
|
+
rb_define_method(rb_cPGconn, "connection_needs_password", pgconn_connection_needs_password, 0);
|
4030
|
+
rb_define_method(rb_cPGconn, "connection_used_password", pgconn_connection_used_password, 0);
|
4031
|
+
//rb_define_method(rb_cPGconn, "getssl", pgconn_getssl, 0);
|
4032
|
+
|
4033
|
+
/****** PGconn INSTANCE METHODS: Command Execution ******/
|
4034
|
+
rb_define_method(rb_cPGconn, "exec", pgconn_exec, -1);
|
4035
|
+
rb_define_alias(rb_cPGconn, "query", "exec");
|
4036
|
+
rb_define_method(rb_cPGconn, "prepare", pgconn_prepare, -1);
|
4037
|
+
rb_define_method(rb_cPGconn, "exec_prepared", pgconn_exec_prepared, -1);
|
4038
|
+
rb_define_method(rb_cPGconn, "describe_prepared", pgconn_describe_prepared, 1);
|
4039
|
+
rb_define_method(rb_cPGconn, "describe_portal", pgconn_describe_portal, 1);
|
4040
|
+
rb_define_method(rb_cPGconn, "make_empty_pgresult", pgconn_make_empty_pgresult, 1);
|
4041
|
+
rb_define_method(rb_cPGconn, "escape_string", pgconn_s_escape, 1);
|
4042
|
+
rb_define_alias(rb_cPGconn, "escape", "escape_string");
|
4043
|
+
rb_define_method(rb_cPGconn, "escape_bytea", pgconn_s_escape_bytea, 1);
|
4044
|
+
rb_define_method(rb_cPGconn, "unescape_bytea", pgconn_s_unescape_bytea, 1);
|
4045
|
+
|
4046
|
+
/****** PGconn INSTANCE METHODS: Asynchronous Command Processing ******/
|
4047
|
+
rb_define_method(rb_cPGconn, "send_query", pgconn_send_query, -1);
|
4048
|
+
rb_define_method(rb_cPGconn, "send_prepare", pgconn_send_prepare, -1);
|
4049
|
+
rb_define_method(rb_cPGconn, "send_query_prepared", pgconn_send_query_prepared, -1);
|
4050
|
+
rb_define_method(rb_cPGconn, "send_describe_prepared", pgconn_send_describe_prepared, 1);
|
4051
|
+
rb_define_method(rb_cPGconn, "send_describe_portal", pgconn_send_describe_portal, 1);
|
4052
|
+
rb_define_method(rb_cPGconn, "get_result", pgconn_get_result, 0);
|
4053
|
+
rb_define_method(rb_cPGconn, "consume_input", pgconn_consume_input, 0);
|
4054
|
+
rb_define_method(rb_cPGconn, "is_busy", pgconn_is_busy, 0);
|
4055
|
+
rb_define_method(rb_cPGconn, "setnonblocking", pgconn_setnonblocking, 1);
|
4056
|
+
rb_define_method(rb_cPGconn, "isnonblocking", pgconn_isnonblocking, 0);
|
4057
|
+
rb_define_alias(rb_cPGconn, "nonblocking?", "isnonblocking");
|
4058
|
+
rb_define_method(rb_cPGconn, "flush", pgconn_flush, 0);
|
4059
|
+
|
4060
|
+
/****** PGconn INSTANCE METHODS: Cancelling Queries in Progress ******/
|
4061
|
+
rb_define_method(rb_cPGconn, "cancel", pgconn_cancel, 0);
|
4062
|
+
|
4063
|
+
/****** PGconn INSTANCE METHODS: NOTIFY ******/
|
4064
|
+
rb_define_method(rb_cPGconn, "notifies", pgconn_notifies, 0);
|
4065
|
+
|
4066
|
+
/****** PGconn INSTANCE METHODS: COPY ******/
|
4067
|
+
rb_define_method(rb_cPGconn, "put_copy_data", pgconn_put_copy_data, 1);
|
4068
|
+
rb_define_method(rb_cPGconn, "put_copy_end", pgconn_put_copy_end, -1);
|
4069
|
+
rb_define_method(rb_cPGconn, "get_copy_data", pgconn_get_copy_data, -1);
|
4070
|
+
|
4071
|
+
/****** PGconn INSTANCE METHODS: Control Functions ******/
|
4072
|
+
rb_define_method(rb_cPGconn, "set_error_verbosity", pgconn_set_error_verbosity, 1);
|
4073
|
+
rb_define_method(rb_cPGconn, "trace", pgconn_trace, 1);
|
4074
|
+
rb_define_method(rb_cPGconn, "untrace", pgconn_untrace, 0);
|
4075
|
+
|
4076
|
+
/****** PGconn INSTANCE METHODS: Notice Processing ******/
|
4077
|
+
rb_define_method(rb_cPGconn, "set_notice_receiver", pgconn_set_notice_receiver, 0);
|
4078
|
+
rb_define_method(rb_cPGconn, "set_notice_processor", pgconn_set_notice_processor, 0);
|
4079
|
+
|
4080
|
+
/****** PGconn INSTANCE METHODS: Other ******/
|
4081
|
+
rb_define_method(rb_cPGconn, "get_client_encoding", pgconn_get_client_encoding, 0);
|
4082
|
+
rb_define_method(rb_cPGconn, "set_client_encoding", pgconn_set_client_encoding, 1);
|
4083
|
+
rb_define_method(rb_cPGconn, "transaction", pgconn_transaction, 0);
|
4084
|
+
rb_define_method(rb_cPGconn, "block", pgconn_block, -1);
|
4085
|
+
rb_define_method(rb_cPGconn, "wait_for_notify", pgconn_wait_for_notify, -1);
|
4086
|
+
rb_define_alias(rb_cPGconn, "notifies_wait", "wait_for_notify");
|
4087
|
+
rb_define_method(rb_cPGconn, "quote_ident", pgconn_s_quote_ident, 1);
|
4088
|
+
rb_define_method(rb_cPGconn, "async_exec", pgconn_async_exec, -1);
|
4089
|
+
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
4090
|
+
rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
|
4091
|
+
|
4092
|
+
/****** PGconn INSTANCE METHODS: Large Object Support ******/
|
4093
|
+
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
4094
|
+
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|
4095
|
+
rb_define_method(rb_cPGconn, "lo_create", pgconn_locreate, 1);
|
4096
|
+
rb_define_alias(rb_cPGconn, "locreate", "lo_create");
|
4097
|
+
rb_define_method(rb_cPGconn, "lo_import", pgconn_loimport, 1);
|
4098
|
+
rb_define_alias(rb_cPGconn, "loimport", "lo_import");
|
4099
|
+
rb_define_method(rb_cPGconn, "lo_export", pgconn_loexport, 2);
|
4100
|
+
rb_define_alias(rb_cPGconn, "loexport", "lo_export");
|
4101
|
+
rb_define_method(rb_cPGconn, "lo_open", pgconn_loopen, -1);
|
4102
|
+
rb_define_alias(rb_cPGconn, "loopen", "lo_open");
|
4103
|
+
rb_define_method(rb_cPGconn, "lo_write",pgconn_lowrite, 2);
|
4104
|
+
rb_define_alias(rb_cPGconn, "lowrite", "lo_write");
|
4105
|
+
rb_define_method(rb_cPGconn, "lo_read",pgconn_loread, 2);
|
4106
|
+
rb_define_alias(rb_cPGconn, "loread", "lo_read");
|
4107
|
+
rb_define_method(rb_cPGconn, "lo_lseek",pgconn_lolseek, 3);
|
4108
|
+
rb_define_alias(rb_cPGconn, "lolseek", "lo_lseek");
|
4109
|
+
rb_define_alias(rb_cPGconn, "lo_seek", "lo_lseek");
|
4110
|
+
rb_define_alias(rb_cPGconn, "loseek", "lo_lseek");
|
4111
|
+
rb_define_method(rb_cPGconn, "lo_tell",pgconn_lotell, 1);
|
4112
|
+
rb_define_alias(rb_cPGconn, "lotell", "lo_tell");
|
4113
|
+
rb_define_method(rb_cPGconn, "lo_truncate", pgconn_lotruncate, 2);
|
4114
|
+
rb_define_alias(rb_cPGconn, "lotruncate", "lo_truncate");
|
4115
|
+
rb_define_method(rb_cPGconn, "lo_close",pgconn_loclose, 1);
|
4116
|
+
rb_define_alias(rb_cPGconn, "loclose", "lo_close");
|
4117
|
+
rb_define_method(rb_cPGconn, "lo_unlink", pgconn_lounlink, 1);
|
4118
|
+
rb_define_alias(rb_cPGconn, "lounlink", "lo_unlink");
|
4119
|
+
|
4120
|
+
/*************************
|
4121
|
+
* PGresult
|
4122
|
+
*************************/
|
4123
|
+
rb_include_module(rb_cPGresult, rb_mEnumerable);
|
4124
|
+
|
4125
|
+
/****** PGresult CONSTANTS: result status ******/
|
4126
|
+
|
4127
|
+
/* #result_status constant: The string sent to the server was empty. */
|
4128
|
+
rb_define_const(rb_cPGresult, "PGRES_EMPTY_QUERY", INT2FIX(PGRES_EMPTY_QUERY));
|
4129
|
+
/* #result_status constant: Successful completion of a command returning no data. */
|
4130
|
+
rb_define_const(rb_cPGresult, "PGRES_COMMAND_OK", INT2FIX(PGRES_COMMAND_OK));
|
4131
|
+
/* #result_status constant: Successful completion of a command returning data
|
4132
|
+
(such as a SELECT or SHOW). */
|
4133
|
+
rb_define_const(rb_cPGresult, "PGRES_TUPLES_OK", INT2FIX(PGRES_TUPLES_OK));
|
4134
|
+
/* #result_status constant: Copy Out (from server) data transfer started. */
|
4135
|
+
rb_define_const(rb_cPGresult, "PGRES_COPY_OUT", INT2FIX(PGRES_COPY_OUT));
|
4136
|
+
/* #result_status constant: Copy In (to server) data transfer started. */
|
4137
|
+
rb_define_const(rb_cPGresult, "PGRES_COPY_IN", INT2FIX(PGRES_COPY_IN));
|
4138
|
+
/* #result_status constant: The server’s response was not understood. */
|
4139
|
+
rb_define_const(rb_cPGresult, "PGRES_BAD_RESPONSE", INT2FIX(PGRES_BAD_RESPONSE));
|
4140
|
+
/* #result_status constant: A nonfatal error (a notice or warning) occurred. */
|
4141
|
+
rb_define_const(rb_cPGresult, "PGRES_NONFATAL_ERROR",INT2FIX(PGRES_NONFATAL_ERROR));
|
4142
|
+
/* #result_status constant: A fatal error occurred. */
|
4143
|
+
rb_define_const(rb_cPGresult, "PGRES_FATAL_ERROR", INT2FIX(PGRES_FATAL_ERROR));
|
4144
|
+
|
4145
|
+
/****** PGresult CONSTANTS: result error field codes ******/
|
4146
|
+
|
4147
|
+
/* #result_error_field argument constant: The severity; the field contents
|
4148
|
+
* are ERROR, FATAL, or PANIC (in an error message), or WARNING, NOTICE,
|
4149
|
+
* DEBUG, INFO, or LOG (in a notice message), or a localized translation
|
4150
|
+
* of one of these. Always present.
|
4151
|
+
*/
|
4152
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_SEVERITY", INT2FIX(PG_DIAG_SEVERITY));
|
4153
|
+
/* #result_error_field argument constant: The SQLSTATE code for the
|
4154
|
+
* error. The SQLSTATE code identies the type of error that has occurred;
|
4155
|
+
* it can be used by front-end applications to perform specic operations
|
4156
|
+
* (such as er- ror handling) in response to a particular database
|
4157
|
+
* error. For a list of the possible SQLSTATE codes, see Appendix A.
|
4158
|
+
* This eld is not localizable, and is always present.
|
4159
|
+
*/
|
4160
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_SQLSTATE", INT2FIX(PG_DIAG_SQLSTATE));
|
4161
|
+
/* #result_error_field argument constant: The primary human-readable
|
4162
|
+
* error message (typically one line). Always present. */
|
4163
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_MESSAGE_PRIMARY", INT2FIX(PG_DIAG_MESSAGE_PRIMARY));
|
4164
|
+
/* #result_error_field argument constant: Detail: an optional secondary
|
4165
|
+
* error message carrying more detail about the problem. Might run to
|
4166
|
+
* multiple lines.
|
4167
|
+
*/
|
4168
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_MESSAGE_DETAIL", INT2FIX(PG_DIAG_MESSAGE_DETAIL));
|
4169
|
+
/* #result_error_field argument constant: Hint: an optional suggestion
|
4170
|
+
* what to do about the problem. This is intended to differ from detail
|
4171
|
+
* in that it offers advice (potentially inappropriate) rather than
|
4172
|
+
* hard facts. Might run to multiple lines.
|
4173
|
+
*/
|
4174
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_MESSAGE_HINT", INT2FIX(PG_DIAG_MESSAGE_HINT));
|
4175
|
+
/* #result_error_field argument constant: A string containing a decimal
|
4176
|
+
* integer indicating an error cursor position as an index into the
|
4177
|
+
* original statement string. The rst character has index 1, and
|
4178
|
+
* positions are measured in characters not bytes.
|
4179
|
+
*/
|
4180
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_STATEMENT_POSITION", INT2FIX(PG_DIAG_STATEMENT_POSITION));
|
4181
|
+
/* #result_error_field argument constant: This is dened the same as
|
4182
|
+
* the PG_DIAG_STATEMENT_POSITION eld, but it is used when the cursor
|
4183
|
+
* position refers to an internally generated command rather than the
|
4184
|
+
* one submitted by the client. The PG_DIAG_INTERNAL_QUERY eld will
|
4185
|
+
* always appear when this eld appears.
|
4186
|
+
*/
|
4187
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_INTERNAL_POSITION", INT2FIX(PG_DIAG_INTERNAL_POSITION));
|
4188
|
+
/* #result_error_field argument constant: The text of a failed
|
4189
|
+
* internally-generated command. This could be, for example, a SQL
|
4190
|
+
* query issued by a PL/pgSQL function.
|
4191
|
+
*/
|
4192
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_INTERNAL_QUERY", INT2FIX(PG_DIAG_INTERNAL_QUERY));
|
4193
|
+
/* #result_error_field argument constant: An indication of the context
|
4194
|
+
* in which the error occurred. Presently this includes a call stack
|
4195
|
+
* traceback of active procedural language functions and internally-generated
|
4196
|
+
* queries. The trace is one entry per line, most recent rst.
|
4197
|
+
*/
|
4198
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_CONTEXT", INT2FIX(PG_DIAG_CONTEXT));
|
4199
|
+
/* #result_error_field argument constant: The le name of the source-code
|
4200
|
+
* location where the error was reported. */
|
4201
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_SOURCE_FILE", INT2FIX(PG_DIAG_SOURCE_FILE));
|
4202
|
+
/* #result_error_field argument constant: The line number of the
|
4203
|
+
* source-code location where the error was reported. */
|
4204
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_SOURCE_LINE", INT2FIX(PG_DIAG_SOURCE_LINE));
|
4205
|
+
/* #result_error_field argument constant: The name of the source-code
|
4206
|
+
* function reporting the error. */
|
4207
|
+
rb_define_const(rb_cPGresult, "PG_DIAG_SOURCE_FUNCTION", INT2FIX(PG_DIAG_SOURCE_FUNCTION));
|
4208
|
+
|
4209
|
+
/* Invalid OID constant */
|
4210
|
+
rb_define_const(rb_cPGresult, "InvalidOid", INT2FIX(InvalidOid));
|
4211
|
+
|
4212
|
+
/****** PGresult INSTANCE METHODS: libpq ******/
|
4213
|
+
rb_define_method(rb_cPGresult, "result_status", pgresult_result_status, 0);
|
4214
|
+
rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
|
4215
|
+
rb_define_method(rb_cPGresult, "result_error_message", pgresult_result_error_message, 0);
|
4216
|
+
rb_define_method(rb_cPGresult, "result_error_field", pgresult_result_error_field, 1);
|
4217
|
+
rb_define_method(rb_cPGresult, "clear", pgresult_clear, 0);
|
4218
|
+
rb_define_method(rb_cPGresult, "ntuples", pgresult_ntuples, 0);
|
4219
|
+
rb_define_alias(rb_cPGresult, "num_tuples", "ntuples");
|
4220
|
+
rb_define_method(rb_cPGresult, "nfields", pgresult_nfields, 0);
|
4221
|
+
rb_define_alias(rb_cPGresult, "num_fields", "nfields");
|
4222
|
+
rb_define_method(rb_cPGresult, "fname", pgresult_fname, 1);
|
4223
|
+
rb_define_method(rb_cPGresult, "fnumber", pgresult_fnumber, 1);
|
4224
|
+
rb_define_method(rb_cPGresult, "ftable", pgresult_ftable, 1);
|
4225
|
+
rb_define_method(rb_cPGresult, "ftablecol", pgresult_ftablecol, 1);
|
4226
|
+
rb_define_method(rb_cPGresult, "fformat", pgresult_fformat, 1);
|
4227
|
+
rb_define_method(rb_cPGresult, "ftype", pgresult_ftype, 1);
|
4228
|
+
rb_define_method(rb_cPGresult, "fmod", pgresult_fmod, 1);
|
4229
|
+
rb_define_method(rb_cPGresult, "fsize", pgresult_fsize, 1);
|
4230
|
+
rb_define_method(rb_cPGresult, "getvalue", pgresult_getvalue, 2);
|
4231
|
+
rb_define_method(rb_cPGresult, "getisnull", pgresult_getisnull, 2);
|
4232
|
+
rb_define_method(rb_cPGresult, "getlength", pgresult_getlength, 2);
|
4233
|
+
rb_define_method(rb_cPGresult, "nparams", pgresult_nparams, 0);
|
4234
|
+
rb_define_method(rb_cPGresult, "paramtype", pgresult_paramtype, 1);
|
4235
|
+
rb_define_method(rb_cPGresult, "cmd_status", pgresult_cmd_status, 0);
|
4236
|
+
rb_define_method(rb_cPGresult, "cmd_tuples", pgresult_cmd_tuples, 0);
|
4237
|
+
rb_define_alias(rb_cPGresult, "cmdtuples", "cmd_tuples");
|
4238
|
+
rb_define_method(rb_cPGresult, "oid_value", pgresult_oid_value, 0);
|
4239
|
+
|
4240
|
+
/****** PGresult INSTANCE METHODS: other ******/
|
4241
|
+
rb_define_method(rb_cPGresult, "[]", pgresult_aref, 1);
|
4242
|
+
rb_define_method(rb_cPGresult, "each", pgresult_each, 0);
|
4243
|
+
rb_define_method(rb_cPGresult, "fields", pgresult_fields, 0);
|
4244
|
+
rb_define_method(rb_cPGresult, "column_values", pgresult_column_values, 1);
|
4245
|
+
rb_define_method(rb_cPGresult, "field_values", pgresult_field_values, 1);
|
4246
|
+
|
4247
|
+
#ifdef M17N_SUPPORTED
|
4248
|
+
init_m17n();
|
4249
|
+
#endif
|
4250
|
+
}
|