pg 0.18.1 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -3
- data.tar.gz.sig +0 -0
- data/BSDL +2 -2
- data/ChangeLog +1004 -4
- data/History.rdoc +66 -0
- data/README-Windows.rdoc +15 -26
- data/README.rdoc +16 -9
- data/Rakefile +26 -16
- data/Rakefile.cross +42 -21
- data/ext/errorcodes.def +16 -0
- data/ext/errorcodes.txt +5 -1
- data/ext/extconf.rb +14 -2
- data/ext/gvl_wrappers.h +4 -0
- data/ext/pg.c +5 -4
- data/ext/pg.h +15 -2
- data/ext/pg_binary_decoder.c +3 -1
- data/ext/pg_binary_encoder.c +14 -12
- data/ext/pg_coder.c +30 -9
- data/ext/pg_connection.c +241 -115
- data/ext/pg_copy_coder.c +34 -4
- data/ext/pg_result.c +5 -5
- data/ext/pg_text_decoder.c +9 -10
- data/ext/pg_text_encoder.c +93 -73
- data/ext/pg_type_map.c +7 -7
- data/ext/pg_type_map_by_column.c +7 -7
- data/ext/pg_type_map_by_mri_type.c +2 -2
- data/ext/pg_type_map_in_ruby.c +4 -7
- data/ext/util.c +3 -3
- data/ext/util.h +1 -1
- data/lib/pg.rb +3 -3
- data/lib/pg/basic_type_mapping.rb +69 -42
- data/lib/pg/connection.rb +84 -34
- data/lib/pg/result.rb +6 -2
- data/lib/pg/text_decoder.rb +12 -3
- data/lib/pg/text_encoder.rb +8 -0
- data/spec/helpers.rb +7 -10
- data/spec/pg/basic_type_mapping_spec.rb +58 -4
- data/spec/pg/connection_spec.rb +251 -34
- data/spec/pg/type_map_by_class_spec.rb +1 -1
- data/spec/pg/type_map_by_mri_type_spec.rb +1 -1
- data/spec/pg/type_spec.rb +144 -32
- metadata +65 -52
- metadata.gz.sig +0 -0
data/ext/errorcodes.txt
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# errcodes.txt
|
3
3
|
# PostgreSQL error codes
|
4
4
|
#
|
5
|
-
# Copyright (c) 2003-
|
5
|
+
# Copyright (c) 2003-2016, PostgreSQL Global Development Group
|
6
6
|
#
|
7
7
|
# This list serves as the basis for generating source files containing error
|
8
8
|
# codes. It is kept in a common format to make sure all these source files have
|
@@ -177,6 +177,8 @@ Section: Class 22 - Data Exception
|
|
177
177
|
2201B E ERRCODE_INVALID_REGULAR_EXPRESSION invalid_regular_expression
|
178
178
|
2201W E ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE invalid_row_count_in_limit_clause
|
179
179
|
2201X E ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE invalid_row_count_in_result_offset_clause
|
180
|
+
2202H E ERRCODE_INVALID_TABLESAMPLE_ARGUMENT invalid_tablesample_argument
|
181
|
+
2202G E ERRCODE_INVALID_TABLESAMPLE_REPEAT invalid_tablesample_repeat
|
180
182
|
22009 E ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE invalid_time_zone_displacement_value
|
181
183
|
2200C E ERRCODE_INVALID_USE_OF_ESCAPE_CHARACTER invalid_use_of_escape_character
|
182
184
|
2200G E ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH most_specific_type_mismatch
|
@@ -278,6 +280,7 @@ Section: Class 39 - External Routine Invocation Exception
|
|
278
280
|
39004 E ERRCODE_E_R_I_E_NULL_VALUE_NOT_ALLOWED null_value_not_allowed
|
279
281
|
39P01 E ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED trigger_protocol_violated
|
280
282
|
39P02 E ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED srf_protocol_violated
|
283
|
+
39P03 E ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED event_trigger_protocol_violated
|
281
284
|
|
282
285
|
Section: Class 3B - Savepoint Exception
|
283
286
|
|
@@ -454,6 +457,7 @@ P0000 E ERRCODE_PLPGSQL_ERROR plp
|
|
454
457
|
P0001 E ERRCODE_RAISE_EXCEPTION raise_exception
|
455
458
|
P0002 E ERRCODE_NO_DATA_FOUND no_data_found
|
456
459
|
P0003 E ERRCODE_TOO_MANY_ROWS too_many_rows
|
460
|
+
P0004 E ERRCODE_ASSERT_FAILURE assert_failure
|
457
461
|
|
458
462
|
Section: Class XX - Internal Error
|
459
463
|
|
data/ext/extconf.rb
CHANGED
@@ -24,7 +24,11 @@ if enable_config("windows-cross")
|
|
24
24
|
else
|
25
25
|
# Native build
|
26
26
|
|
27
|
-
|
27
|
+
pgconfig = with_config('pg-config') ||
|
28
|
+
with_config('pg_config') ||
|
29
|
+
find_executable('pg_config')
|
30
|
+
|
31
|
+
if pgconfig && pgconfig != 'ignore'
|
28
32
|
$stderr.puts "Using config values from %s" % [ pgconfig ]
|
29
33
|
incdir = `"#{pgconfig}" --includedir`.chomp
|
30
34
|
libdir = `"#{pgconfig}" --libdir`.chomp
|
@@ -43,6 +47,9 @@ else
|
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
50
|
+
if RUBY_VERSION >= '2.3.0' && /solaris/ =~ RUBY_PLATFORM
|
51
|
+
append_cppflags( '-D__EXTENSIONS__' )
|
52
|
+
end
|
46
53
|
|
47
54
|
find_header( 'libpq-fe.h' ) or abort "Can't find the 'libpq-fe.h header"
|
48
55
|
find_header( 'libpq/libpq-fs.h' ) or abort "Can't find the 'libpq/libpq-fs.h header"
|
@@ -73,7 +80,7 @@ have_func 'PQlibVersion'
|
|
73
80
|
have_func 'PQping'
|
74
81
|
have_func 'PQsetSingleRowMode'
|
75
82
|
have_func 'PQconninfo'
|
76
|
-
have_func '
|
83
|
+
have_func 'PQsslAttribute'
|
77
84
|
|
78
85
|
have_func 'rb_encdb_alias'
|
79
86
|
have_func 'rb_enc_alias'
|
@@ -93,8 +100,13 @@ $defs.push( "-DHAVE_ST_NOTIFY_EXTRA" ) if
|
|
93
100
|
|
94
101
|
# unistd.h confilicts with ruby/win32.h when cross compiling for win32 and ruby 1.9.1
|
95
102
|
have_header 'unistd.h'
|
103
|
+
have_header 'inttypes.h'
|
96
104
|
have_header 'ruby/st.h' or have_header 'st.h' or abort "pg currently requires the ruby/st.h header"
|
97
105
|
|
106
|
+
checking_for "C99 variable length arrays" do
|
107
|
+
$defs.push( "-DHAVE_VARIABLE_LENGTH_ARRAYS" ) if try_compile('void test_vla(int l){ int vla[l]; }')
|
108
|
+
end
|
109
|
+
|
98
110
|
create_header()
|
99
111
|
create_makefile( "pg_ext" )
|
100
112
|
|
data/ext/gvl_wrappers.h
CHANGED
@@ -195,6 +195,9 @@ extern void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1,
|
|
195
195
|
#define FOR_EACH_PARAM_OF_PQsendDescribePortal(param) \
|
196
196
|
param(PGconn *, conn)
|
197
197
|
|
198
|
+
#define FOR_EACH_PARAM_OF_PQsetClientEncoding(param) \
|
199
|
+
param(PGconn *, conn)
|
200
|
+
|
198
201
|
#define FOR_EACH_PARAM_OF_PQisBusy(param)
|
199
202
|
|
200
203
|
#define FOR_EACH_PARAM_OF_PQcancel(param) \
|
@@ -226,6 +229,7 @@ extern void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1,
|
|
226
229
|
function(PQsendQueryPrepared, GVL_TYPE_NONVOID, int, int, resultFormat) \
|
227
230
|
function(PQsendDescribePrepared, GVL_TYPE_NONVOID, int, const char *, stmt) \
|
228
231
|
function(PQsendDescribePortal, GVL_TYPE_NONVOID, int, const char *, portal) \
|
232
|
+
function(PQsetClientEncoding, GVL_TYPE_NONVOID, int, const char *, encoding) \
|
229
233
|
function(PQisBusy, GVL_TYPE_NONVOID, int, PGconn *, conn) \
|
230
234
|
function(PQcancel, GVL_TYPE_NONVOID, int, int, errbufsize);
|
231
235
|
|
data/ext/pg.c
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
/*
|
2
2
|
* pg.c - Toplevel extension
|
3
|
-
* $Id: pg.c,v
|
3
|
+
* $Id: pg.c,v c77d0997b4e4 2016/08/20 17:30:03 ged $
|
4
4
|
*
|
5
5
|
* Author/s:
|
6
6
|
*
|
7
7
|
* - Jeff Davis <ruby-pg@j-davis.com>
|
8
8
|
* - Guy Decoux (ts) <decoux@moulon.inra.fr>
|
9
9
|
* - Michael Granger <ged@FaerieMUD.org>
|
10
|
+
* - Lars Kanis <lars@greiz-reinsdorf.de>
|
10
11
|
* - Dave Lee
|
11
12
|
* - Eiji Matsumoto <usagi@ruby.club.or.jp>
|
12
13
|
* - Yukihiro Matsumoto <matz@ruby-lang.org>
|
@@ -15,10 +16,10 @@
|
|
15
16
|
* See Contributors.rdoc for the many additional fine people that have contributed
|
16
17
|
* to this library over the years.
|
17
18
|
*
|
18
|
-
* Copyright (c) 1997-
|
19
|
+
* Copyright (c) 1997-2016 by the authors.
|
19
20
|
*
|
20
21
|
* You may redistribute this software under the same terms as Ruby itself; see
|
21
|
-
*
|
22
|
+
* https://www.ruby-lang.org/en/about/license.txt or the BSDL file in the source
|
22
23
|
* for details.
|
23
24
|
*
|
24
25
|
* Portions of the code are from the PostgreSQL project, and are distributed
|
@@ -252,7 +253,7 @@ pg_get_rb_encoding_as_pg_encoding( rb_encoding *enc )
|
|
252
253
|
* char *current_out, *end_capa;
|
253
254
|
* PG_RB_STR_NEW( string, current_out, end_capa );
|
254
255
|
* while( data_is_going_to_be_processed ){
|
255
|
-
* PG_RB_STR_ENSURE_CAPA( string, 2 current_out, end_capa );
|
256
|
+
* PG_RB_STR_ENSURE_CAPA( string, 2, current_out, end_capa );
|
256
257
|
* *current_out++ = databyte1;
|
257
258
|
* *current_out++ = databyte2;
|
258
259
|
* }
|
data/ext/pg.h
CHANGED
@@ -9,6 +9,9 @@
|
|
9
9
|
#include <stdio.h>
|
10
10
|
#include <stdlib.h>
|
11
11
|
#include <sys/types.h>
|
12
|
+
#if !defined(_WIN32)
|
13
|
+
# include <sys/time.h>
|
14
|
+
#endif
|
12
15
|
#if defined(HAVE_UNISTD_H) && !defined(_WIN32)
|
13
16
|
# include <unistd.h>
|
14
17
|
#endif /* HAVE_UNISTD_H */
|
@@ -133,6 +136,15 @@
|
|
133
136
|
typedef long suseconds_t;
|
134
137
|
#endif
|
135
138
|
|
139
|
+
#if defined(HAVE_VARIABLE_LENGTH_ARRAYS)
|
140
|
+
#define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) type name[(len)];
|
141
|
+
#else
|
142
|
+
#define PG_VARIABLE_LENGTH_ARRAY(type, name, len, maxlen) \
|
143
|
+
type name[(maxlen)] = {(len)>(maxlen) ? (rb_raise(rb_eArgError, "Number of " #name " (%d) exceeds allowed maximum of " #maxlen, (len) ), (type)1) : (type)0};
|
144
|
+
|
145
|
+
#define PG_MAX_COLUMNS 4000
|
146
|
+
#endif
|
147
|
+
|
136
148
|
/* The data behind each PG::Connection object */
|
137
149
|
typedef struct {
|
138
150
|
PGconn *pgconn;
|
@@ -196,7 +208,7 @@ typedef struct {
|
|
196
208
|
} t_pg_result;
|
197
209
|
|
198
210
|
|
199
|
-
typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE
|
211
|
+
typedef int (* t_pg_coder_enc_func)(t_pg_coder *, VALUE, char *, VALUE *, int);
|
200
212
|
typedef VALUE (* t_pg_coder_dec_func)(t_pg_coder *, char *, int, int, int, int);
|
201
213
|
typedef VALUE (* t_pg_fit_to_result)(VALUE, VALUE);
|
202
214
|
typedef VALUE (* t_pg_fit_to_query)(VALUE, VALUE);
|
@@ -312,7 +324,8 @@ void init_pg_binary_decoder _(( void ));
|
|
312
324
|
VALUE lookup_error_class _(( const char * ));
|
313
325
|
VALUE pg_bin_dec_bytea _(( t_pg_coder*, char *, int, int, int, int ));
|
314
326
|
VALUE pg_text_dec_string _(( t_pg_coder*, char *, int, int, int, int ));
|
315
|
-
int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE
|
327
|
+
int pg_coder_enc_to_s _(( t_pg_coder*, VALUE, char *, VALUE *, int));
|
328
|
+
int pg_text_enc_identifier _(( t_pg_coder*, VALUE, char *, VALUE *, int));
|
316
329
|
t_pg_coder_enc_func pg_coder_enc_func _(( t_pg_coder* ));
|
317
330
|
t_pg_coder_dec_func pg_coder_dec_func _(( t_pg_coder*, int ));
|
318
331
|
void pg_define_coder _(( const char *, void *, VALUE, VALUE ));
|
data/ext/pg_binary_decoder.c
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
/*
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
3
|
-
* $Id: pg_binary_decoder.c,v
|
3
|
+
* $Id: pg_binary_decoder.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
7
7
|
#include "pg.h"
|
8
8
|
#include "util.h"
|
9
|
+
#ifdef HAVE_INTTYPES_H
|
9
10
|
#include <inttypes.h>
|
11
|
+
#endif
|
10
12
|
|
11
13
|
VALUE rb_mPG_BinaryDecoder;
|
12
14
|
|
data/ext/pg_binary_encoder.c
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
/*
|
2
2
|
* pg_column_map.c - PG::ColumnMap class extension
|
3
|
-
* $Id: pg_binary_encoder.c,v
|
3
|
+
* $Id: pg_binary_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
7
7
|
#include "pg.h"
|
8
8
|
#include "util.h"
|
9
|
+
#ifdef HAVE_INTTYPES_H
|
9
10
|
#include <inttypes.h>
|
11
|
+
#endif
|
10
12
|
|
11
13
|
VALUE rb_mPG_BinaryEncoder;
|
12
14
|
|
@@ -20,16 +22,16 @@ VALUE rb_mPG_BinaryEncoder;
|
|
20
22
|
*
|
21
23
|
*/
|
22
24
|
static int
|
23
|
-
pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
25
|
+
pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
24
26
|
{
|
25
|
-
char
|
27
|
+
char mybool;
|
26
28
|
switch(value){
|
27
|
-
case Qtrue :
|
28
|
-
case Qfalse :
|
29
|
+
case Qtrue : mybool = 1; break;
|
30
|
+
case Qfalse : mybool = 0; break;
|
29
31
|
default :
|
30
32
|
rb_raise( rb_eTypeError, "wrong data for binary boolean converter" );
|
31
33
|
}
|
32
|
-
if(out) *out =
|
34
|
+
if(out) *out = mybool;
|
33
35
|
return 1;
|
34
36
|
}
|
35
37
|
|
@@ -42,7 +44,7 @@ pg_bin_enc_boolean(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate
|
|
42
44
|
*
|
43
45
|
*/
|
44
46
|
static int
|
45
|
-
pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
47
|
+
pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
46
48
|
{
|
47
49
|
if(out){
|
48
50
|
write_nbo16(NUM2INT(*intermediate), out);
|
@@ -61,7 +63,7 @@ pg_bin_enc_int2(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
61
63
|
*
|
62
64
|
*/
|
63
65
|
static int
|
64
|
-
pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
66
|
+
pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
65
67
|
{
|
66
68
|
if(out){
|
67
69
|
write_nbo32(NUM2LONG(*intermediate), out);
|
@@ -80,7 +82,7 @@ pg_bin_enc_int4(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
80
82
|
*
|
81
83
|
*/
|
82
84
|
static int
|
83
|
-
pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
85
|
+
pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
84
86
|
{
|
85
87
|
if(out){
|
86
88
|
write_nbo64(NUM2LL(*intermediate), out);
|
@@ -98,7 +100,7 @@ pg_bin_enc_int8(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
98
100
|
*
|
99
101
|
*/
|
100
102
|
static int
|
101
|
-
pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
103
|
+
pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
102
104
|
{
|
103
105
|
int strlen;
|
104
106
|
VALUE subint;
|
@@ -107,13 +109,13 @@ pg_bin_enc_from_base64(t_pg_coder *conv, VALUE value, char *out, VALUE *intermed
|
|
107
109
|
|
108
110
|
if(out){
|
109
111
|
/* Second encoder pass, if required */
|
110
|
-
strlen = enc_func(this->elem, value, out, intermediate);
|
112
|
+
strlen = enc_func(this->elem, value, out, intermediate, enc_idx);
|
111
113
|
strlen = base64_decode( out, out, strlen );
|
112
114
|
|
113
115
|
return strlen;
|
114
116
|
} else {
|
115
117
|
/* First encoder pass */
|
116
|
-
strlen = enc_func(this->elem, value, NULL, &subint);
|
118
|
+
strlen = enc_func(this->elem, value, NULL, &subint, enc_idx);
|
117
119
|
|
118
120
|
if( strlen == -1 ){
|
119
121
|
/* Encoded string is returned in subint */
|
data/ext/pg_coder.c
CHANGED
@@ -114,13 +114,24 @@ pg_composite_decoder_allocate( VALUE klass )
|
|
114
114
|
*
|
115
115
|
*/
|
116
116
|
static VALUE
|
117
|
-
pg_coder_encode(VALUE
|
117
|
+
pg_coder_encode(int argc, VALUE *argv, VALUE self)
|
118
118
|
{
|
119
119
|
VALUE res;
|
120
120
|
VALUE intermediate;
|
121
|
+
VALUE value;
|
121
122
|
int len, len2;
|
123
|
+
int enc_idx;
|
122
124
|
t_pg_coder *this = DATA_PTR(self);
|
123
125
|
|
126
|
+
if(argc < 1 || argc > 2){
|
127
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%i for 1..2)", argc);
|
128
|
+
}else if(argc == 1){
|
129
|
+
enc_idx = rb_ascii8bit_encindex();
|
130
|
+
}else{
|
131
|
+
enc_idx = rb_to_encoding_index(argv[1]);
|
132
|
+
}
|
133
|
+
value = argv[0];
|
134
|
+
|
124
135
|
if( NIL_P(value) )
|
125
136
|
return Qnil;
|
126
137
|
|
@@ -128,7 +139,7 @@ pg_coder_encode(VALUE self, VALUE value)
|
|
128
139
|
rb_raise(rb_eRuntimeError, "no encoder function defined");
|
129
140
|
}
|
130
141
|
|
131
|
-
len = this->enc_func( this, value, NULL, &intermediate );
|
142
|
+
len = this->enc_func( this, value, NULL, &intermediate, enc_idx );
|
132
143
|
|
133
144
|
if( len == -1 ){
|
134
145
|
/* The intermediate value is a String that can be used directly. */
|
@@ -137,7 +148,8 @@ pg_coder_encode(VALUE self, VALUE value)
|
|
137
148
|
}
|
138
149
|
|
139
150
|
res = rb_str_new(NULL, len);
|
140
|
-
|
151
|
+
PG_ENCODING_SET_NOCHECK(res, enc_idx);
|
152
|
+
len2 = this->enc_func( this, value, RSTRING_PTR(res), &intermediate, enc_idx );
|
141
153
|
if( len < len2 ){
|
142
154
|
rb_bug("%s: result length of first encoder run (%i) is less than second run (%i)",
|
143
155
|
rb_obj_classname( self ), len, len2 );
|
@@ -165,8 +177,8 @@ static VALUE
|
|
165
177
|
pg_coder_decode(int argc, VALUE *argv, VALUE self)
|
166
178
|
{
|
167
179
|
char *val;
|
168
|
-
|
169
|
-
|
180
|
+
int tuple = -1;
|
181
|
+
int field = -1;
|
170
182
|
VALUE res;
|
171
183
|
t_pg_coder *this = DATA_PTR(self);
|
172
184
|
|
@@ -359,10 +371,19 @@ pg_define_coder( const char *name, void *func, VALUE base_klass, VALUE nsp )
|
|
359
371
|
|
360
372
|
|
361
373
|
static int
|
362
|
-
pg_text_enc_in_ruby(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
374
|
+
pg_text_enc_in_ruby(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate, int enc_idx)
|
363
375
|
{
|
364
|
-
|
365
|
-
|
376
|
+
int arity = rb_obj_method_arity(conv->coder_obj, s_id_encode);
|
377
|
+
if( arity == 1 ){
|
378
|
+
VALUE out_str = rb_funcall( conv->coder_obj, s_id_encode, 1, value );
|
379
|
+
StringValue( out_str );
|
380
|
+
*intermediate = rb_str_export_to_enc(out_str, rb_enc_from_index(enc_idx));
|
381
|
+
}else{
|
382
|
+
VALUE enc = rb_enc_from_encoding(rb_enc_from_index(enc_idx));
|
383
|
+
VALUE out_str = rb_funcall( conv->coder_obj, s_id_encode, 2, value, enc );
|
384
|
+
StringValue( out_str );
|
385
|
+
*intermediate = out_str;
|
386
|
+
}
|
366
387
|
return -1;
|
367
388
|
}
|
368
389
|
|
@@ -442,7 +463,7 @@ init_pg_coder()
|
|
442
463
|
* This accessor is only used in PG::Coder#inspect .
|
443
464
|
*/
|
444
465
|
rb_define_attr( rb_cPG_Coder, "name", 1, 1 );
|
445
|
-
rb_define_method( rb_cPG_Coder, "encode", pg_coder_encode, 1 );
|
466
|
+
rb_define_method( rb_cPG_Coder, "encode", pg_coder_encode, -1 );
|
446
467
|
rb_define_method( rb_cPG_Coder, "decode", pg_coder_decode, -1 );
|
447
468
|
|
448
469
|
/* Document-class: PG::SimpleCoder < PG::Coder */
|
data/ext/pg_connection.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_connection.c - PG::Connection class extension
|
3
|
-
* $Id: pg_connection.c,v
|
3
|
+
* $Id: pg_connection.c,v 4d9c4ee44d11 2016/09/04 17:32:03 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -52,7 +52,7 @@ pg_get_connection( VALUE self )
|
|
52
52
|
* Fetch the PG::Connection object data pointer and check it's
|
53
53
|
* PGconn data pointer for sanity.
|
54
54
|
*/
|
55
|
-
t_pg_connection *
|
55
|
+
static t_pg_connection *
|
56
56
|
pg_get_connection_safe( VALUE self )
|
57
57
|
{
|
58
58
|
t_pg_connection *this;
|
@@ -88,7 +88,7 @@ pg_get_pgconn( VALUE self )
|
|
88
88
|
/*
|
89
89
|
* Close the associated socket IO object if there is one.
|
90
90
|
*/
|
91
|
-
void
|
91
|
+
static void
|
92
92
|
pgconn_close_socket_io( VALUE self )
|
93
93
|
{
|
94
94
|
t_pg_connection *this = pg_get_connection( self );
|
@@ -141,6 +141,16 @@ pgconn_make_conninfo_array( const PQconninfoOption *options )
|
|
141
141
|
return ary;
|
142
142
|
}
|
143
143
|
|
144
|
+
static const char *pg_cstr_enc(VALUE str, int enc_idx){
|
145
|
+
const char *ptr = StringValueCStr(str);
|
146
|
+
if( ENCODING_GET(str) == enc_idx ){
|
147
|
+
return ptr;
|
148
|
+
} else {
|
149
|
+
str = rb_str_export_to_enc(str, rb_enc_from_index(enc_idx));
|
150
|
+
return StringValueCStr(str);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
144
154
|
|
145
155
|
/*
|
146
156
|
* GC Mark function
|
@@ -373,7 +383,7 @@ pgconn_s_ping( int argc, VALUE *argv, VALUE klass )
|
|
373
383
|
|
374
384
|
|
375
385
|
/*
|
376
|
-
* Document-method: conndefaults
|
386
|
+
* Document-method: PG::Connection.conndefaults
|
377
387
|
*
|
378
388
|
* call-seq:
|
379
389
|
* PG::Connection.conndefaults() -> Array
|
@@ -627,22 +637,6 @@ pgconn_host(VALUE self)
|
|
627
637
|
return rb_tainted_str_new2(host);
|
628
638
|
}
|
629
639
|
|
630
|
-
#ifdef HAVE_PQHOSTADDR
|
631
|
-
/*
|
632
|
-
* call-seq:
|
633
|
-
* conn.hostaddr()
|
634
|
-
*
|
635
|
-
* Returns the server numeric IP address of the connection.
|
636
|
-
*/
|
637
|
-
static VALUE
|
638
|
-
pgconn_hostaddr(VALUE self)
|
639
|
-
{
|
640
|
-
char *hostaddr = PQhostaddr(pg_get_pgconn(self));
|
641
|
-
if (!hostaddr) return Qnil;
|
642
|
-
return rb_tainted_str_new2(hostaddr);
|
643
|
-
}
|
644
|
-
#endif
|
645
|
-
|
646
640
|
/*
|
647
641
|
* call-seq:
|
648
642
|
* conn.port()
|
@@ -963,9 +957,9 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
|
|
963
957
|
|
964
958
|
/* If called with no parameters, use PQexec */
|
965
959
|
if ( argc == 1 ) {
|
966
|
-
|
960
|
+
VALUE query_str = argv[0];
|
967
961
|
|
968
|
-
result = gvl_PQexec(conn,
|
962
|
+
result = gvl_PQexec(conn, pg_cstr_enc(query_str, ENCODING_GET(self)));
|
969
963
|
rb_pgresult = pg_new_result(result, self);
|
970
964
|
pg_result_check(rb_pgresult);
|
971
965
|
if (rb_block_given_p()) {
|
@@ -994,6 +988,10 @@ struct query_params_data {
|
|
994
988
|
* Filled by caller
|
995
989
|
*/
|
996
990
|
|
991
|
+
/* The character encoding index of the connection. Any strings
|
992
|
+
* given as query parameters are converted to this encoding.
|
993
|
+
*/
|
994
|
+
int enc_idx;
|
997
995
|
/* Is the query function to execute one with types array? */
|
998
996
|
int with_types;
|
999
997
|
/* Array of query params from user space */
|
@@ -1154,7 +1152,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1154
1152
|
VALUE intermediate;
|
1155
1153
|
|
1156
1154
|
/* 1st pass for retiving the required memory space */
|
1157
|
-
int len = enc_func(conv, param_value, NULL, &intermediate);
|
1155
|
+
int len = enc_func(conv, param_value, NULL, &intermediate, paramsData->enc_idx);
|
1158
1156
|
|
1159
1157
|
if( len == -1 ){
|
1160
1158
|
/* The intermediate value is a String that can be used directly. */
|
@@ -1178,7 +1176,7 @@ alloc_query_params(struct query_params_data *paramsData)
|
|
1178
1176
|
}
|
1179
1177
|
|
1180
1178
|
/* 2nd pass for writing the data to prepared buffer */
|
1181
|
-
len = enc_func(conv, param_value, typecast_buf, &intermediate);
|
1179
|
+
len = enc_func(conv, param_value, typecast_buf, &intermediate, paramsData->enc_idx);
|
1182
1180
|
paramsData->values[i] = typecast_buf;
|
1183
1181
|
if( paramsData->formats[i] == 0 ){
|
1184
1182
|
/* text format strings must be zero terminated and lengths are ignored */
|
@@ -1274,7 +1272,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1274
1272
|
VALUE command, in_res_fmt;
|
1275
1273
|
int nParams;
|
1276
1274
|
int resultFormat;
|
1277
|
-
struct query_params_data paramsData;
|
1275
|
+
struct query_params_data paramsData = { ENCODING_GET(self) };
|
1278
1276
|
|
1279
1277
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1280
1278
|
paramsData.with_types = 1;
|
@@ -1291,7 +1289,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
|
|
1291
1289
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1292
1290
|
nParams = alloc_query_params( ¶msData );
|
1293
1291
|
|
1294
|
-
result = gvl_PQexecParams(conn,
|
1292
|
+
result = gvl_PQexecParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1295
1293
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1296
1294
|
|
1297
1295
|
free_query_params( ¶msData );
|
@@ -1337,10 +1335,13 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1337
1335
|
int i = 0;
|
1338
1336
|
int nParams = 0;
|
1339
1337
|
Oid *paramTypes = NULL;
|
1338
|
+
const char *name_cstr;
|
1339
|
+
const char *command_cstr;
|
1340
|
+
int enc_idx = ENCODING_GET(self);
|
1340
1341
|
|
1341
1342
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1342
|
-
|
1343
|
-
|
1343
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1344
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1344
1345
|
|
1345
1346
|
if(! NIL_P(in_paramtypes)) {
|
1346
1347
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1354,8 +1355,7 @@ pgconn_prepare(int argc, VALUE *argv, VALUE self)
|
|
1354
1355
|
paramTypes[i] = NUM2UINT(param);
|
1355
1356
|
}
|
1356
1357
|
}
|
1357
|
-
result = gvl_PQprepare(conn,
|
1358
|
-
nParams, paramTypes);
|
1358
|
+
result = gvl_PQprepare(conn, name_cstr, command_cstr, nParams, paramTypes);
|
1359
1359
|
|
1360
1360
|
xfree(paramTypes);
|
1361
1361
|
|
@@ -1408,11 +1408,10 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1408
1408
|
VALUE name, in_res_fmt;
|
1409
1409
|
int nParams;
|
1410
1410
|
int resultFormat;
|
1411
|
-
struct query_params_data paramsData;
|
1411
|
+
struct query_params_data paramsData = { ENCODING_GET(self) };
|
1412
1412
|
|
1413
1413
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1414
1414
|
paramsData.with_types = 0;
|
1415
|
-
Check_Type(name, T_STRING);
|
1416
1415
|
|
1417
1416
|
if(NIL_P(paramsData.params)) {
|
1418
1417
|
paramsData.params = rb_ary_new2(0);
|
@@ -1422,7 +1421,7 @@ pgconn_exec_prepared(int argc, VALUE *argv, VALUE self)
|
|
1422
1421
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1423
1422
|
nParams = alloc_query_params( ¶msData );
|
1424
1423
|
|
1425
|
-
result = gvl_PQexecPrepared(conn,
|
1424
|
+
result = gvl_PQexecPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1426
1425
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1427
1426
|
resultFormat);
|
1428
1427
|
|
@@ -1450,13 +1449,12 @@ pgconn_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1450
1449
|
PGresult *result;
|
1451
1450
|
VALUE rb_pgresult;
|
1452
1451
|
PGconn *conn = pg_get_pgconn(self);
|
1453
|
-
char *stmt;
|
1454
|
-
if(stmt_name
|
1452
|
+
const char *stmt;
|
1453
|
+
if(NIL_P(stmt_name)) {
|
1455
1454
|
stmt = NULL;
|
1456
1455
|
}
|
1457
1456
|
else {
|
1458
|
-
|
1459
|
-
stmt = StringValueCStr(stmt_name);
|
1457
|
+
stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
|
1460
1458
|
}
|
1461
1459
|
result = gvl_PQdescribePrepared(conn, stmt);
|
1462
1460
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1478,13 +1476,12 @@ pgconn_describe_portal(self, stmt_name)
|
|
1478
1476
|
PGresult *result;
|
1479
1477
|
VALUE rb_pgresult;
|
1480
1478
|
PGconn *conn = pg_get_pgconn(self);
|
1481
|
-
char *stmt;
|
1482
|
-
if(stmt_name
|
1479
|
+
const char *stmt;
|
1480
|
+
if(NIL_P(stmt_name)) {
|
1483
1481
|
stmt = NULL;
|
1484
1482
|
}
|
1485
1483
|
else {
|
1486
|
-
|
1487
|
-
stmt = StringValueCStr(stmt_name);
|
1484
|
+
stmt = pg_cstr_enc(stmt_name, ENCODING_GET(self));
|
1488
1485
|
}
|
1489
1486
|
result = gvl_PQdescribePortal(conn, stmt);
|
1490
1487
|
rb_pgresult = pg_new_result(result, self);
|
@@ -1526,10 +1523,6 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1526
1523
|
* call-seq:
|
1527
1524
|
* conn.escape_string( str ) -> String
|
1528
1525
|
*
|
1529
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1530
|
-
* uses PQescapeStringConn, which is safer. Avoid calling as a class method,
|
1531
|
-
* the class method uses the deprecated PQescapeString() API function.
|
1532
|
-
*
|
1533
1526
|
* Returns a SQL-safe version of the String _str_.
|
1534
1527
|
* This is the preferred way to make strings safe for inclusion in
|
1535
1528
|
* SQL queries.
|
@@ -1538,32 +1531,41 @@ pgconn_make_empty_pgresult(VALUE self, VALUE status)
|
|
1538
1531
|
* inside of SQL commands.
|
1539
1532
|
*
|
1540
1533
|
* Encoding of escaped string will be equal to client encoding of connection.
|
1534
|
+
*
|
1535
|
+
* NOTE: This class version of this method can only be used safely in client
|
1536
|
+
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1537
|
+
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1538
|
+
* results if used in programs that use multiple database connections; use the
|
1539
|
+
* same method on the connection object in such cases.
|
1541
1540
|
*/
|
1542
1541
|
static VALUE
|
1543
1542
|
pgconn_s_escape(VALUE self, VALUE string)
|
1544
1543
|
{
|
1545
|
-
char *escaped;
|
1546
1544
|
size_t size;
|
1547
1545
|
int error;
|
1548
1546
|
VALUE result;
|
1547
|
+
int enc_idx;
|
1548
|
+
int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
|
1549
1549
|
|
1550
1550
|
Check_Type(string, T_STRING);
|
1551
|
+
enc_idx = ENCODING_GET( singleton ? string : self );
|
1552
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1553
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1554
|
+
}
|
1551
1555
|
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1556
|
+
result = rb_str_new(NULL, RSTRING_LEN(string) * 2 + 1);
|
1557
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1558
|
+
if( !singleton ) {
|
1559
|
+
size = PQescapeStringConn(pg_get_pgconn(self), RSTRING_PTR(result),
|
1555
1560
|
RSTRING_PTR(string), RSTRING_LEN(string), &error);
|
1556
1561
|
if(error) {
|
1557
|
-
xfree(escaped);
|
1558
1562
|
rb_raise(rb_ePGerror, "%s", PQerrorMessage(pg_get_pgconn(self)));
|
1559
1563
|
}
|
1560
1564
|
} else {
|
1561
|
-
size = PQescapeString(
|
1565
|
+
size = PQescapeString(RSTRING_PTR(result), RSTRING_PTR(string), RSTRING_LEN(string));
|
1562
1566
|
}
|
1563
|
-
result
|
1564
|
-
xfree(escaped);
|
1567
|
+
rb_str_set_len(result, size);
|
1565
1568
|
OBJ_INFECT(result, string);
|
1566
|
-
PG_ENCODING_SET_NOCHECK(result, ENCODING_GET( rb_obj_class(self) == rb_cPGconn ? self : string ));
|
1567
1569
|
|
1568
1570
|
return result;
|
1569
1571
|
}
|
@@ -1572,13 +1574,6 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1572
1574
|
* call-seq:
|
1573
1575
|
* conn.escape_bytea( string ) -> String
|
1574
1576
|
*
|
1575
|
-
* Connection instance method for versions of 8.1 and higher of libpq
|
1576
|
-
* uses PQescapeByteaConn, which is safer. Avoid calling as a class method,
|
1577
|
-
* the class method uses the deprecated PQescapeBytea() API function.
|
1578
|
-
*
|
1579
|
-
* Use the instance method version of this function, it is safer than the
|
1580
|
-
* class method.
|
1581
|
-
*
|
1582
1577
|
* Escapes binary data for use within an SQL command with the type +bytea+.
|
1583
1578
|
*
|
1584
1579
|
* Certain byte values must be escaped (but all byte values may be escaped)
|
@@ -1591,6 +1586,12 @@ pgconn_s_escape(VALUE self, VALUE string)
|
|
1591
1586
|
*
|
1592
1587
|
* Consider using exec_params, which avoids the need for passing values inside of
|
1593
1588
|
* SQL commands.
|
1589
|
+
*
|
1590
|
+
* NOTE: This class version of this method can only be used safely in client
|
1591
|
+
* programs that use a single PostgreSQL connection at a time (in this case it can
|
1592
|
+
* find out what it needs to know "behind the scenes"). It might give the wrong
|
1593
|
+
* results if used in programs that use multiple database connections; use the
|
1594
|
+
* same method on the connection object in such cases.
|
1594
1595
|
*/
|
1595
1596
|
static VALUE
|
1596
1597
|
pgconn_s_escape_bytea(VALUE self, VALUE str)
|
@@ -1603,7 +1604,7 @@ pgconn_s_escape_bytea(VALUE self, VALUE str)
|
|
1603
1604
|
from = (unsigned char*)RSTRING_PTR(str);
|
1604
1605
|
from_len = RSTRING_LEN(str);
|
1605
1606
|
|
1606
|
-
if(
|
1607
|
+
if ( rb_obj_is_kind_of(self, rb_cPGconn) ) {
|
1607
1608
|
to = PQescapeByteaConn(pg_get_pgconn(self), from, from_len, &to_len);
|
1608
1609
|
} else {
|
1609
1610
|
to = PQescapeBytea( from, from_len, &to_len);
|
@@ -1659,8 +1660,12 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1659
1660
|
char *escaped = NULL;
|
1660
1661
|
VALUE error;
|
1661
1662
|
VALUE result = Qnil;
|
1663
|
+
int enc_idx = ENCODING_GET(self);
|
1662
1664
|
|
1663
1665
|
Check_Type(string, T_STRING);
|
1666
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1667
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1668
|
+
}
|
1664
1669
|
|
1665
1670
|
escaped = PQescapeLiteral(conn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1666
1671
|
if (escaped == NULL)
|
@@ -1673,7 +1678,7 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1673
1678
|
result = rb_str_new2(escaped);
|
1674
1679
|
PQfreemem(escaped);
|
1675
1680
|
OBJ_INFECT(result, string);
|
1676
|
-
PG_ENCODING_SET_NOCHECK(result,
|
1681
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1677
1682
|
|
1678
1683
|
return result;
|
1679
1684
|
}
|
@@ -1686,8 +1691,9 @@ pgconn_escape_literal(VALUE self, VALUE string)
|
|
1686
1691
|
*
|
1687
1692
|
* Escape an arbitrary String +str+ as an identifier.
|
1688
1693
|
*
|
1689
|
-
* This method does the same as #quote_ident
|
1690
|
-
*
|
1694
|
+
* This method does the same as #quote_ident with a String argument,
|
1695
|
+
* but it doesn't support an Array argument and it makes use of libpq
|
1696
|
+
* to process the string.
|
1691
1697
|
*/
|
1692
1698
|
static VALUE
|
1693
1699
|
pgconn_escape_identifier(VALUE self, VALUE string)
|
@@ -1696,8 +1702,12 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1696
1702
|
char *escaped = NULL;
|
1697
1703
|
VALUE error;
|
1698
1704
|
VALUE result = Qnil;
|
1705
|
+
int enc_idx = ENCODING_GET(self);
|
1699
1706
|
|
1700
1707
|
Check_Type(string, T_STRING);
|
1708
|
+
if( ENCODING_GET(string) != enc_idx ){
|
1709
|
+
string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
|
1710
|
+
}
|
1701
1711
|
|
1702
1712
|
escaped = PQescapeIdentifier(conn, RSTRING_PTR(string), RSTRING_LEN(string));
|
1703
1713
|
if (escaped == NULL)
|
@@ -1710,7 +1720,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
|
|
1710
1720
|
result = rb_str_new2(escaped);
|
1711
1721
|
PQfreemem(escaped);
|
1712
1722
|
OBJ_INFECT(result, string);
|
1713
|
-
PG_ENCODING_SET_NOCHECK(result,
|
1723
|
+
PG_ENCODING_SET_NOCHECK(result, enc_idx);
|
1714
1724
|
|
1715
1725
|
return result;
|
1716
1726
|
}
|
@@ -1818,15 +1828,14 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1818
1828
|
VALUE error;
|
1819
1829
|
int nParams;
|
1820
1830
|
int resultFormat;
|
1821
|
-
struct query_params_data paramsData;
|
1831
|
+
struct query_params_data paramsData = { ENCODING_GET(self) };
|
1822
1832
|
|
1823
1833
|
rb_scan_args(argc, argv, "13", &command, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1824
1834
|
paramsData.with_types = 1;
|
1825
|
-
Check_Type(command, T_STRING);
|
1826
1835
|
|
1827
1836
|
/* If called with no parameters, use PQsendQuery */
|
1828
1837
|
if(NIL_P(paramsData.params)) {
|
1829
|
-
if(gvl_PQsendQuery(conn,
|
1838
|
+
if(gvl_PQsendQuery(conn, pg_cstr_enc(command, paramsData.enc_idx)) == 0) {
|
1830
1839
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
1831
1840
|
rb_iv_set(error, "@connection", self);
|
1832
1841
|
rb_exc_raise(error);
|
@@ -1842,7 +1851,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
|
|
1842
1851
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1843
1852
|
nParams = alloc_query_params( ¶msData );
|
1844
1853
|
|
1845
|
-
result = gvl_PQsendQueryParams(conn,
|
1854
|
+
result = gvl_PQsendQueryParams(conn, pg_cstr_enc(command, paramsData.enc_idx), nParams, paramsData.types,
|
1846
1855
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats, resultFormat);
|
1847
1856
|
|
1848
1857
|
free_query_params( ¶msData );
|
@@ -1886,10 +1895,13 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1886
1895
|
int i = 0;
|
1887
1896
|
int nParams = 0;
|
1888
1897
|
Oid *paramTypes = NULL;
|
1898
|
+
const char *name_cstr;
|
1899
|
+
const char *command_cstr;
|
1900
|
+
int enc_idx = ENCODING_GET(self);
|
1889
1901
|
|
1890
1902
|
rb_scan_args(argc, argv, "21", &name, &command, &in_paramtypes);
|
1891
|
-
|
1892
|
-
|
1903
|
+
name_cstr = pg_cstr_enc(name, enc_idx);
|
1904
|
+
command_cstr = pg_cstr_enc(command, enc_idx);
|
1893
1905
|
|
1894
1906
|
if(! NIL_P(in_paramtypes)) {
|
1895
1907
|
Check_Type(in_paramtypes, T_ARRAY);
|
@@ -1903,8 +1915,7 @@ pgconn_send_prepare(int argc, VALUE *argv, VALUE self)
|
|
1903
1915
|
paramTypes[i] = NUM2UINT(param);
|
1904
1916
|
}
|
1905
1917
|
}
|
1906
|
-
result = gvl_PQsendPrepare(conn,
|
1907
|
-
nParams, paramTypes);
|
1918
|
+
result = gvl_PQsendPrepare(conn, name_cstr, command_cstr, nParams, paramTypes);
|
1908
1919
|
|
1909
1920
|
xfree(paramTypes);
|
1910
1921
|
|
@@ -1957,11 +1968,10 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1957
1968
|
VALUE error;
|
1958
1969
|
int nParams;
|
1959
1970
|
int resultFormat;
|
1960
|
-
struct query_params_data paramsData;
|
1971
|
+
struct query_params_data paramsData = { ENCODING_GET(self) };
|
1961
1972
|
|
1962
1973
|
rb_scan_args(argc, argv, "13", &name, ¶msData.params, &in_res_fmt, ¶msData.typemap);
|
1963
1974
|
paramsData.with_types = 0;
|
1964
|
-
Check_Type(name, T_STRING);
|
1965
1975
|
|
1966
1976
|
if(NIL_P(paramsData.params)) {
|
1967
1977
|
paramsData.params = rb_ary_new2(0);
|
@@ -1972,7 +1982,7 @@ pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
|
|
1972
1982
|
resultFormat = NIL_P(in_res_fmt) ? 0 : NUM2INT(in_res_fmt);
|
1973
1983
|
nParams = alloc_query_params( ¶msData );
|
1974
1984
|
|
1975
|
-
result = gvl_PQsendQueryPrepared(conn,
|
1985
|
+
result = gvl_PQsendQueryPrepared(conn, pg_cstr_enc(name, paramsData.enc_idx), nParams,
|
1976
1986
|
(const char * const *)paramsData.values, paramsData.lengths, paramsData.formats,
|
1977
1987
|
resultFormat);
|
1978
1988
|
|
@@ -1999,7 +2009,7 @@ pgconn_send_describe_prepared(VALUE self, VALUE stmt_name)
|
|
1999
2009
|
VALUE error;
|
2000
2010
|
PGconn *conn = pg_get_pgconn(self);
|
2001
2011
|
/* returns 0 on failure */
|
2002
|
-
if(gvl_PQsendDescribePrepared(conn,
|
2012
|
+
if(gvl_PQsendDescribePrepared(conn, pg_cstr_enc(stmt_name, ENCODING_GET(self))) == 0) {
|
2003
2013
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
2004
2014
|
rb_iv_set(error, "@connection", self);
|
2005
2015
|
rb_exc_raise(error);
|
@@ -2021,7 +2031,7 @@ pgconn_send_describe_portal(VALUE self, VALUE portal)
|
|
2021
2031
|
VALUE error;
|
2022
2032
|
PGconn *conn = pg_get_pgconn(self);
|
2023
2033
|
/* returns 0 on failure */
|
2024
|
-
if(gvl_PQsendDescribePortal(conn,
|
2034
|
+
if(gvl_PQsendDescribePortal(conn, pg_cstr_enc(portal, ENCODING_GET(self))) == 0) {
|
2025
2035
|
error = rb_exc_new2(rb_eUnableToSend, PQerrorMessage(conn));
|
2026
2036
|
rb_iv_set(error, "@connection", self);
|
2027
2037
|
rb_exc_raise(error);
|
@@ -2581,16 +2591,17 @@ pgconn_put_copy_data(int argc, VALUE *argv, VALUE self)
|
|
2581
2591
|
|
2582
2592
|
if( p_coder ){
|
2583
2593
|
t_pg_coder_enc_func enc_func;
|
2594
|
+
int enc_idx = ENCODING_GET(self);
|
2584
2595
|
|
2585
2596
|
enc_func = pg_coder_enc_func( p_coder );
|
2586
|
-
len = enc_func( p_coder, value, NULL, &intermediate );
|
2597
|
+
len = enc_func( p_coder, value, NULL, &intermediate, enc_idx);
|
2587
2598
|
|
2588
2599
|
if( len == -1 ){
|
2589
2600
|
/* The intermediate value is a String that can be used directly. */
|
2590
2601
|
buffer = intermediate;
|
2591
2602
|
} else {
|
2592
2603
|
buffer = rb_str_new(NULL, len);
|
2593
|
-
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate);
|
2604
|
+
len = enc_func( p_coder, value, RSTRING_PTR(buffer), &intermediate, enc_idx);
|
2594
2605
|
rb_str_set_len( buffer, len );
|
2595
2606
|
}
|
2596
2607
|
}
|
@@ -2629,13 +2640,13 @@ pgconn_put_copy_end(int argc, VALUE *argv, VALUE self)
|
|
2629
2640
|
VALUE str;
|
2630
2641
|
VALUE error;
|
2631
2642
|
int ret;
|
2632
|
-
char *error_message = NULL;
|
2643
|
+
const char *error_message = NULL;
|
2633
2644
|
PGconn *conn = pg_get_pgconn(self);
|
2634
2645
|
|
2635
2646
|
if (rb_scan_args(argc, argv, "01", &str) == 0)
|
2636
2647
|
error_message = NULL;
|
2637
2648
|
else
|
2638
|
-
error_message =
|
2649
|
+
error_message = pg_cstr_enc(str, ENCODING_GET(self));
|
2639
2650
|
|
2640
2651
|
ret = gvl_PQputCopyEnd(conn, error_message);
|
2641
2652
|
if(ret == -1) {
|
@@ -2956,7 +2967,7 @@ pgconn_set_client_encoding(VALUE self, VALUE str)
|
|
2956
2967
|
|
2957
2968
|
Check_Type(str, T_STRING);
|
2958
2969
|
|
2959
|
-
if ( (
|
2970
|
+
if ( (gvl_PQsetClientEncoding(conn, StringValueCStr(str))) == -1 ) {
|
2960
2971
|
rb_raise(rb_ePGerror, "invalid encoding name: %s",StringValueCStr(str));
|
2961
2972
|
}
|
2962
2973
|
#ifdef M17N_SUPPORTED
|
@@ -3012,8 +3023,10 @@ pgconn_transaction(VALUE self)
|
|
3012
3023
|
|
3013
3024
|
/*
|
3014
3025
|
* call-seq:
|
3015
|
-
* PG::Connection.quote_ident( str ) -> String
|
3016
3026
|
* conn.quote_ident( str ) -> String
|
3027
|
+
* conn.quote_ident( array ) -> String
|
3028
|
+
* PG::Connection.quote_ident( str ) -> String
|
3029
|
+
* PG::Connection.quote_ident( array ) -> String
|
3017
3030
|
*
|
3018
3031
|
* Returns a string that is safe for inclusion in a SQL query as an
|
3019
3032
|
* identifier. Note: this is not a quote function for values, but for
|
@@ -3023,40 +3036,41 @@ pgconn_transaction(VALUE self)
|
|
3023
3036
|
* The identifier <tt>FOO</tt> is folded to lower case, so it actually
|
3024
3037
|
* means <tt>foo</tt>. If you really want to access the case-sensitive
|
3025
3038
|
* field name <tt>FOO</tt>, use this function like
|
3026
|
-
* <tt>
|
3039
|
+
* <tt>conn.quote_ident('FOO')</tt>, which will return <tt>"FOO"</tt>
|
3027
3040
|
* (with double-quotes). PostgreSQL will see the double-quotes, and
|
3028
3041
|
* it will not fold to lower case.
|
3029
3042
|
*
|
3030
3043
|
* Similarly, this function also protects against special characters,
|
3031
3044
|
* and other things that might allow SQL injection if the identifier
|
3032
3045
|
* comes from an untrusted source.
|
3046
|
+
*
|
3047
|
+
* If the parameter is an Array, then all it's values are separately quoted
|
3048
|
+
* and then joined by a "." character. This can be used for identifiers in
|
3049
|
+
* the form "schema"."table"."column" .
|
3050
|
+
*
|
3051
|
+
* This method is functional identical to the encoder PG::TextEncoder::Identifier .
|
3052
|
+
*
|
3053
|
+
* If the instance method form is used and the input string character encoding
|
3054
|
+
* is different to the connection encoding, then the string is converted to this
|
3055
|
+
* encoding, so that the returned string is always encoded as PG::Connection#internal_encoding .
|
3056
|
+
*
|
3057
|
+
* In the singleton form (PG::Connection.quote_ident) the character encoding
|
3058
|
+
* of the result string is set to the character encoding of the input string.
|
3033
3059
|
*/
|
3034
3060
|
static VALUE
|
3035
|
-
pgconn_s_quote_ident(VALUE self, VALUE
|
3061
|
+
pgconn_s_quote_ident(VALUE self, VALUE str_or_array)
|
3036
3062
|
{
|
3037
3063
|
VALUE ret;
|
3038
|
-
|
3039
|
-
|
3040
|
-
|
3041
|
-
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3045
|
-
|
3046
|
-
|
3047
|
-
|
3048
|
-
NAMEDATALEN-1);
|
3049
|
-
}
|
3050
|
-
buffer[j++] = '"';
|
3051
|
-
for(i = 0; i < str_len && str[i]; i++) {
|
3052
|
-
if(str[i] == '"')
|
3053
|
-
buffer[j++] = '"';
|
3054
|
-
buffer[j++] = str[i];
|
3055
|
-
}
|
3056
|
-
buffer[j++] = '"';
|
3057
|
-
ret = rb_str_new(buffer,j);
|
3058
|
-
OBJ_INFECT(ret, in_str);
|
3059
|
-
PG_ENCODING_SET_NOCHECK(ret, ENCODING_GET( rb_obj_class(self) == rb_cPGconn ? self : in_str ));
|
3064
|
+
int enc_idx;
|
3065
|
+
|
3066
|
+
if( rb_obj_is_kind_of(self, rb_cPGconn) ){
|
3067
|
+
enc_idx = ENCODING_GET( self );
|
3068
|
+
}else{
|
3069
|
+
enc_idx = RB_TYPE_P(str_or_array, T_STRING) ? ENCODING_GET( str_or_array ) : rb_ascii8bit_encindex();
|
3070
|
+
}
|
3071
|
+
pg_text_enc_identifier(NULL, str_or_array, NULL, &ret, enc_idx);
|
3072
|
+
|
3073
|
+
OBJ_INFECT(ret, str_or_array);
|
3060
3074
|
|
3061
3075
|
return ret;
|
3062
3076
|
}
|
@@ -3182,6 +3196,84 @@ pgconn_async_exec(int argc, VALUE *argv, VALUE self)
|
|
3182
3196
|
return rb_pgresult;
|
3183
3197
|
}
|
3184
3198
|
|
3199
|
+
|
3200
|
+
#ifdef HAVE_PQSSLATTRIBUTE
|
3201
|
+
/* Since PostgreSQL-9.5: */
|
3202
|
+
|
3203
|
+
/*
|
3204
|
+
* call-seq:
|
3205
|
+
* conn.ssl_in_use? -> Boolean
|
3206
|
+
*
|
3207
|
+
* Returns +true+ if the connection uses SSL, +false+ if not.
|
3208
|
+
*
|
3209
|
+
*/
|
3210
|
+
static VALUE
|
3211
|
+
pgconn_ssl_in_use(VALUE self)
|
3212
|
+
{
|
3213
|
+
return PQsslInUse(pg_get_pgconn(self)) ? Qtrue : Qfalse;
|
3214
|
+
}
|
3215
|
+
|
3216
|
+
|
3217
|
+
/*
|
3218
|
+
* call-seq:
|
3219
|
+
* conn.ssl_attribute(attribute_name) -> String
|
3220
|
+
*
|
3221
|
+
* Returns SSL-related information about the connection.
|
3222
|
+
*
|
3223
|
+
* The list of available attributes varies depending on the SSL library being used,
|
3224
|
+
* and the type of connection. If an attribute is not available, returns nil.
|
3225
|
+
*
|
3226
|
+
* The following attributes are commonly available:
|
3227
|
+
*
|
3228
|
+
* [+library+]
|
3229
|
+
* Name of the SSL implementation in use. (Currently, only "OpenSSL" is implemented)
|
3230
|
+
* [+protocol+]
|
3231
|
+
* SSL/TLS version in use. Common values are "SSLv2", "SSLv3", "TLSv1", "TLSv1.1" and "TLSv1.2", but an implementation may return other strings if some other protocol is used.
|
3232
|
+
* [+key_bits+]
|
3233
|
+
* Number of key bits used by the encryption algorithm.
|
3234
|
+
* [+cipher+]
|
3235
|
+
* A short name of the ciphersuite used, e.g. "DHE-RSA-DES-CBC3-SHA". The names are specific to each SSL implementation.
|
3236
|
+
* [+compression+]
|
3237
|
+
* If SSL compression is in use, returns the name of the compression algorithm, or "on" if compression is used but the algorithm is not known. If compression is not in use, returns "off".
|
3238
|
+
*
|
3239
|
+
*
|
3240
|
+
* See also #ssl_attribute_names and http://www.postgresql.org/docs/current/interactive/libpq-status.html#LIBPQ-PQSSLATTRIBUTE
|
3241
|
+
*/
|
3242
|
+
static VALUE
|
3243
|
+
pgconn_ssl_attribute(VALUE self, VALUE attribute_name)
|
3244
|
+
{
|
3245
|
+
const char *p_attr;
|
3246
|
+
|
3247
|
+
p_attr = PQsslAttribute(pg_get_pgconn(self), StringValueCStr(attribute_name));
|
3248
|
+
return p_attr ? rb_str_new_cstr(p_attr) : Qnil;
|
3249
|
+
}
|
3250
|
+
|
3251
|
+
/*
|
3252
|
+
* call-seq:
|
3253
|
+
* conn.ssl_attribute_names -> Array<String>
|
3254
|
+
*
|
3255
|
+
* Return an array of SSL attribute names available.
|
3256
|
+
*
|
3257
|
+
* See also #ssl_attribute
|
3258
|
+
*
|
3259
|
+
*/
|
3260
|
+
static VALUE
|
3261
|
+
pgconn_ssl_attribute_names(VALUE self)
|
3262
|
+
{
|
3263
|
+
int i;
|
3264
|
+
const char * const * p_list = PQsslAttributeNames(pg_get_pgconn(self));
|
3265
|
+
VALUE ary = rb_ary_new();
|
3266
|
+
|
3267
|
+
for ( i = 0; p_list[i]; i++ ) {
|
3268
|
+
rb_ary_push( ary, rb_str_new_cstr( p_list[i] ));
|
3269
|
+
}
|
3270
|
+
return ary;
|
3271
|
+
}
|
3272
|
+
|
3273
|
+
|
3274
|
+
#endif
|
3275
|
+
|
3276
|
+
|
3185
3277
|
/**************************************************************************
|
3186
3278
|
* LARGE OBJECT SUPPORT
|
3187
3279
|
**************************************************************************/
|
@@ -3537,7 +3629,7 @@ pgconn_internal_encoding_set(VALUE self, VALUE enc)
|
|
3537
3629
|
rb_encoding *rbenc = rb_to_encoding( enc );
|
3538
3630
|
const char *name = pg_get_rb_encoding_as_pg_encoding( rbenc );
|
3539
3631
|
|
3540
|
-
if (
|
3632
|
+
if ( gvl_PQsetClientEncoding(pg_get_pgconn( self ), name) == -1 ) {
|
3541
3633
|
VALUE server_encoding = pgconn_external_encoding( self );
|
3542
3634
|
rb_raise( rb_eEncCompatError, "incompatible character encodings: %s and %s",
|
3543
3635
|
rb_enc_name(rb_to_encoding(server_encoding)), name );
|
@@ -3579,6 +3671,34 @@ pgconn_external_encoding(VALUE self)
|
|
3579
3671
|
}
|
3580
3672
|
|
3581
3673
|
|
3674
|
+
static VALUE
|
3675
|
+
pgconn_set_client_encoding_async1( VALUE args )
|
3676
|
+
{
|
3677
|
+
VALUE self = ((VALUE*)args)[0];
|
3678
|
+
VALUE encname = ((VALUE*)args)[1];
|
3679
|
+
VALUE query_format = rb_str_new_cstr("set client_encoding to '%s'");
|
3680
|
+
VALUE query = rb_funcall(query_format, rb_intern("%"), 1, encname);
|
3681
|
+
|
3682
|
+
pgconn_async_exec(1, &query, self);
|
3683
|
+
return 0;
|
3684
|
+
}
|
3685
|
+
|
3686
|
+
|
3687
|
+
static VALUE
|
3688
|
+
pgconn_set_client_encoding_async2( VALUE arg )
|
3689
|
+
{
|
3690
|
+
UNUSED(arg);
|
3691
|
+
return 1;
|
3692
|
+
}
|
3693
|
+
|
3694
|
+
|
3695
|
+
static VALUE
|
3696
|
+
pgconn_set_client_encoding_async( VALUE self, const char *encname )
|
3697
|
+
{
|
3698
|
+
VALUE args[] = { self, rb_str_new_cstr(encname) };
|
3699
|
+
return rb_rescue(pgconn_set_client_encoding_async1, (VALUE)&args, pgconn_set_client_encoding_async2, Qnil);
|
3700
|
+
}
|
3701
|
+
|
3582
3702
|
|
3583
3703
|
/*
|
3584
3704
|
* call-seq:
|
@@ -3597,7 +3717,7 @@ pgconn_set_default_encoding( VALUE self )
|
|
3597
3717
|
|
3598
3718
|
if (( enc = rb_default_internal_encoding() )) {
|
3599
3719
|
encname = pg_get_rb_encoding_as_pg_encoding( enc );
|
3600
|
-
if (
|
3720
|
+
if ( pgconn_set_client_encoding_async(self, encname) != 0 )
|
3601
3721
|
rb_warn( "Failed to set the default_internal encoding to %s: '%s'",
|
3602
3722
|
encname, PQerrorMessage(conn) );
|
3603
3723
|
pgconn_set_internal_encoding_index( self );
|
@@ -3729,7 +3849,7 @@ pgconn_encoder_for_put_copy_data_set(VALUE self, VALUE typemap)
|
|
3729
3849
|
*
|
3730
3850
|
* Returns either:
|
3731
3851
|
* * a kind of PG::Coder
|
3732
|
-
* * +nil+ - type encoding is disabled,
|
3852
|
+
* * +nil+ - type encoding is disabled, data must be a String.
|
3733
3853
|
*
|
3734
3854
|
*/
|
3735
3855
|
static VALUE
|
@@ -3790,6 +3910,9 @@ pgconn_decoder_for_get_copy_data_get(VALUE self)
|
|
3790
3910
|
}
|
3791
3911
|
|
3792
3912
|
|
3913
|
+
/*
|
3914
|
+
* Document-class: PG::Connection
|
3915
|
+
*/
|
3793
3916
|
void
|
3794
3917
|
init_pg_connection()
|
3795
3918
|
{
|
@@ -3835,9 +3958,6 @@ init_pg_connection()
|
|
3835
3958
|
rb_define_method(rb_cPGconn, "user", pgconn_user, 0);
|
3836
3959
|
rb_define_method(rb_cPGconn, "pass", pgconn_pass, 0);
|
3837
3960
|
rb_define_method(rb_cPGconn, "host", pgconn_host, 0);
|
3838
|
-
#ifdef HAVE_PQHOSTADDR
|
3839
|
-
rb_define_method(rb_cPGconn, "hostaddr", pgconn_hostaddr, 0);
|
3840
|
-
#endif
|
3841
3961
|
rb_define_method(rb_cPGconn, "port", pgconn_port, 0);
|
3842
3962
|
rb_define_method(rb_cPGconn, "tty", pgconn_tty, 0);
|
3843
3963
|
#ifdef HAVE_PQCONNINFO
|
@@ -3929,6 +4049,12 @@ init_pg_connection()
|
|
3929
4049
|
rb_define_alias(rb_cPGconn, "async_query", "async_exec");
|
3930
4050
|
rb_define_method(rb_cPGconn, "get_last_result", pgconn_get_last_result, 0);
|
3931
4051
|
|
4052
|
+
#ifdef HAVE_PQSSLATTRIBUTE
|
4053
|
+
rb_define_method(rb_cPGconn, "ssl_in_use?", pgconn_ssl_in_use, 0);
|
4054
|
+
rb_define_method(rb_cPGconn, "ssl_attribute", pgconn_ssl_attribute, 1);
|
4055
|
+
rb_define_method(rb_cPGconn, "ssl_attribute_names", pgconn_ssl_attribute_names, 0);
|
4056
|
+
#endif
|
4057
|
+
|
3932
4058
|
/****** PG::Connection INSTANCE METHODS: Large Object Support ******/
|
3933
4059
|
rb_define_method(rb_cPGconn, "lo_creat", pgconn_locreat, -1);
|
3934
4060
|
rb_define_alias(rb_cPGconn, "locreat", "lo_creat");
|