pg 0.18.1 → 0.18.2
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 +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +169 -2
- data/History.rdoc +16 -0
- data/README.rdoc +1 -1
- data/ext/extconf.rb +4 -1
- data/ext/pg.c +3 -3
- data/ext/pg.h +10 -0
- data/ext/pg_connection.c +12 -40
- data/ext/pg_result.c +4 -4
- data/ext/pg_text_decoder.c +7 -10
- data/ext/pg_text_encoder.c +37 -40
- 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 +2 -2
- data/ext/util.h +1 -1
- data/lib/pg.rb +2 -2
- data/lib/pg/connection.rb +37 -27
- data/lib/pg/text_decoder.rb +2 -2
- data/spec/pg/connection_spec.rb +82 -6
- data/spec/pg/type_spec.rb +53 -30
- metadata +32 -32
- metadata.gz.sig +0 -0
data/ext/pg_text_encoder.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_text_encoder.c - PG::TextEncoder module
|
3
|
-
* $Id: pg_text_encoder.c,v
|
3
|
+
* $Id: pg_text_encoder.c,v b859963462b2 2015/03/13 17:39:35 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -299,7 +299,7 @@ quote_array_buffer( void *_this, char *p_in, int strlen, char *p_out ){
|
|
299
299
|
/* count data plus backslashes; detect chars needing quotes */
|
300
300
|
if (strlen == 0)
|
301
301
|
needquote = 1; /* force quotes for empty string */
|
302
|
-
else if (strlen == 4 &&
|
302
|
+
else if (strlen == 4 && rbpg_strncasecmp(p_in, "NULL", strlen) == 0)
|
303
303
|
needquote = 1; /* force quotes for literal NULL */
|
304
304
|
else
|
305
305
|
needquote = 0;
|
@@ -455,39 +455,34 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate)
|
|
455
455
|
}
|
456
456
|
}
|
457
457
|
|
458
|
-
static
|
459
|
-
|
458
|
+
static char *
|
459
|
+
quote_identifier( VALUE value, VALUE out_string, char *current_out ){
|
460
|
+
char *p_in = RSTRING_PTR(value);
|
460
461
|
char *ptr1;
|
461
|
-
|
462
|
-
|
462
|
+
size_t strlen = RSTRING_LEN(value);
|
463
|
+
char *end_capa = current_out;
|
463
464
|
|
464
|
-
|
465
|
+
PG_RB_STR_ENSURE_CAPA( out_string, strlen + 2, current_out, end_capa );
|
466
|
+
*current_out++ = '"';
|
465
467
|
for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
|
466
|
-
|
467
|
-
|
468
|
+
char c = *ptr1;
|
469
|
+
if (c == '"'){
|
470
|
+
strlen++;
|
471
|
+
PG_RB_STR_ENSURE_CAPA( out_string, p_in - ptr1 + strlen + 1, current_out, end_capa );
|
472
|
+
*current_out++ = '"';
|
473
|
+
} else if (c == 0){
|
474
|
+
break;
|
468
475
|
}
|
476
|
+
*current_out++ = c;
|
469
477
|
}
|
478
|
+
PG_RB_STR_ENSURE_CAPA( out_string, 1, current_out, end_capa );
|
479
|
+
*current_out++ = '"';
|
470
480
|
|
471
|
-
|
472
|
-
ptr2 = p_out + strlen + backslashs + 2;
|
473
|
-
/* Write end quote */
|
474
|
-
*--ptr2 = '"';
|
475
|
-
|
476
|
-
/* Then store the escaped string on the final position, walking
|
477
|
-
* right to left, until all backslashs are placed. */
|
478
|
-
while( ptr1 != p_in ) {
|
479
|
-
*--ptr2 = *--ptr1;
|
480
|
-
if(*ptr2 == '"'){
|
481
|
-
*--ptr2 = '"';
|
482
|
-
}
|
483
|
-
}
|
484
|
-
/* Write start quote */
|
485
|
-
*p_out = '"';
|
486
|
-
return strlen + backslashs + 2;
|
481
|
+
return current_out;
|
487
482
|
}
|
488
483
|
|
489
484
|
static char *
|
490
|
-
pg_text_enc_array_identifier(
|
485
|
+
pg_text_enc_array_identifier(VALUE value, VALUE string, char *out)
|
491
486
|
{
|
492
487
|
int i;
|
493
488
|
int nr_elems;
|
@@ -498,7 +493,7 @@ pg_text_enc_array_identifier(t_pg_composite_coder *this, VALUE value, VALUE stri
|
|
498
493
|
for( i=0; i<nr_elems; i++){
|
499
494
|
VALUE entry = rb_ary_entry(value, i);
|
500
495
|
|
501
|
-
out =
|
496
|
+
out = quote_identifier(entry, string, out);
|
502
497
|
if( i < nr_elems-1 ){
|
503
498
|
out = pg_rb_str_ensure_capa( string, 1, out, NULL );
|
504
499
|
*out++ = '.';
|
@@ -508,27 +503,29 @@ pg_text_enc_array_identifier(t_pg_composite_coder *this, VALUE value, VALUE stri
|
|
508
503
|
}
|
509
504
|
|
510
505
|
/*
|
511
|
-
* Document-class: PG::TextEncoder::Identifier < PG::
|
506
|
+
* Document-class: PG::TextEncoder::Identifier < PG::SimpleEncoder
|
512
507
|
*
|
513
508
|
* This is the encoder class for PostgreSQL identifiers.
|
514
509
|
*
|
515
510
|
* An Array value can be used for "schema.table.column" type identifiers:
|
516
511
|
* PG::TextEncoder::Identifier.new.encode(['schema', 'table', 'column'])
|
517
|
-
* => "schema"."table"."column"
|
512
|
+
* => '"schema"."table"."column"'
|
518
513
|
*
|
514
|
+
* This encoder can also be used per PG::Connection#quote_ident .
|
519
515
|
*/
|
520
|
-
|
521
|
-
pg_text_enc_identifier(t_pg_coder *
|
516
|
+
int
|
517
|
+
pg_text_enc_identifier(t_pg_coder *this, VALUE value, char *out, VALUE *intermediate)
|
522
518
|
{
|
523
|
-
|
524
|
-
|
525
|
-
*intermediate = rb_str_new(NULL, 0);
|
526
|
-
out = RSTRING_PTR(*intermediate);
|
527
|
-
|
519
|
+
UNUSED( this );
|
528
520
|
if( TYPE(value) == T_ARRAY){
|
529
|
-
|
521
|
+
*intermediate = rb_str_new(NULL, 0);
|
522
|
+
out = RSTRING_PTR(*intermediate);
|
523
|
+
out = pg_text_enc_array_identifier(value, *intermediate, out);
|
530
524
|
} else {
|
531
|
-
|
525
|
+
StringValue(value);
|
526
|
+
*intermediate = rb_str_new(NULL, RSTRING_LEN(value) + 2);
|
527
|
+
out = RSTRING_PTR(*intermediate);
|
528
|
+
out = quote_identifier(value, *intermediate, out);
|
532
529
|
}
|
533
530
|
rb_str_set_len( *intermediate, out - RSTRING_PTR(*intermediate) );
|
534
531
|
return -1;
|
@@ -651,11 +648,11 @@ init_pg_text_encoder()
|
|
651
648
|
pg_define_coder( "String", pg_coder_enc_to_s, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
652
649
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Bytea", rb_cPG_SimpleEncoder ); */
|
653
650
|
pg_define_coder( "Bytea", pg_text_enc_bytea, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
651
|
+
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Identifier", rb_cPG_SimpleEncoder ); */
|
652
|
+
pg_define_coder( "Identifier", pg_text_enc_identifier, rb_cPG_SimpleEncoder, rb_mPG_TextEncoder );
|
654
653
|
|
655
654
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Array", rb_cPG_CompositeEncoder ); */
|
656
655
|
pg_define_coder( "Array", pg_text_enc_array, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
|
657
|
-
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "Identifier", rb_cPG_CompositeEncoder ); */
|
658
|
-
pg_define_coder( "Identifier", pg_text_enc_identifier, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
|
659
656
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "QuotedLiteral", rb_cPG_CompositeEncoder ); */
|
660
657
|
pg_define_coder( "QuotedLiteral", pg_text_enc_quoted_literal, rb_cPG_CompositeEncoder, rb_mPG_TextEncoder );
|
661
658
|
/* dummy = rb_define_class_under( rb_mPG_TextEncoder, "ToBase64", rb_cPG_CompositeEncoder ); */
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_type_map_by_mri_type.c - PG::TypeMapByMriType class extension
|
3
|
-
* $Id: pg_type_map_by_mri_type.c,v
|
3
|
+
* $Id: pg_type_map_by_mri_type.c,v 1269b8ad77b8 2015/02/06 16:38:23 lars $
|
4
4
|
*
|
5
5
|
* This type map can be used to select value encoders based on the MRI-internal
|
6
6
|
* value type code.
|
@@ -39,7 +39,7 @@ static VALUE rb_cTypeMapByMriType;
|
|
39
39
|
typedef struct {
|
40
40
|
t_typemap typemap;
|
41
41
|
struct pg_tmbmt_converter {
|
42
|
-
FOR_EACH_MRI_TYPE( DECLARE_CODER )
|
42
|
+
FOR_EACH_MRI_TYPE( DECLARE_CODER )
|
43
43
|
} coders;
|
44
44
|
} t_tmbmt;
|
45
45
|
|
data/ext/pg_type_map_in_ruby.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* pg_type_map_in_ruby.c - PG::TypeMapInRuby class extension
|
3
|
-
* $Id: pg_type_map_in_ruby.c,v
|
3
|
+
* $Id: pg_type_map_in_ruby.c,v 3d89d3aae4fd 2015/01/05 16:19:41 kanis $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -212,12 +212,9 @@ pg_tmir_copy_get( t_typemap *p_typemap, VALUE field_str, int fieldno, int format
|
|
212
212
|
rb_encoding *p_encoding = rb_enc_from_index(enc_idx);
|
213
213
|
VALUE enc = rb_enc_from_encoding(p_encoding);
|
214
214
|
/* field_str is reused in-place by pg_text_dec_copy_row(), so we need to make
|
215
|
-
* a copy of the string buffer
|
216
|
-
|
217
|
-
|
218
|
-
VALUE field_str_copy = rb_str_new(RSTRING_PTR(field_str), RSTRING_LEN(field_str));
|
219
|
-
PG_ENCODING_SET_NOCHECK(field_str_copy, ENCODING_GET(field_str));
|
220
|
-
OBJ_INFECT(field_str_copy, field_str);
|
215
|
+
* a copy of the string buffer for use in ruby space. */
|
216
|
+
VALUE field_str_copy = rb_str_dup(field_str);
|
217
|
+
rb_str_modify(field_str_copy);
|
221
218
|
|
222
219
|
return rb_funcall( this->self, s_id_typecast_copy_get, 4, field_str_copy, INT2NUM(fieldno), INT2NUM(format), enc );
|
223
220
|
}
|
data/ext/util.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* util.c - Utils for ruby-pg
|
3
|
-
* $Id: util.c,v
|
3
|
+
* $Id: util.c,v b859963462b2 2015/03/13 17:39:35 lars $
|
4
4
|
*
|
5
5
|
*/
|
6
6
|
|
@@ -124,7 +124,7 @@ base64_decode( char *out, char *in, unsigned int len)
|
|
124
124
|
* At most n bytes will be examined from each string.
|
125
125
|
*/
|
126
126
|
int
|
127
|
-
|
127
|
+
rbpg_strncasecmp(const char *s1, const char *s2, size_t n)
|
128
128
|
{
|
129
129
|
while (n-- > 0)
|
130
130
|
{
|
data/ext/util.h
CHANGED
@@ -60,6 +60,6 @@
|
|
60
60
|
void base64_encode( char *out, char *in, int len);
|
61
61
|
int base64_decode( char *out, char *in, unsigned int len);
|
62
62
|
|
63
|
-
int
|
63
|
+
int rbpg_strncasecmp(const char *s1, const char *s2, size_t n);
|
64
64
|
|
65
65
|
#endif /* end __utils_h */
|
data/lib/pg.rb
CHANGED
data/lib/pg/connection.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'pg' unless defined?( PG )
|
4
|
+
require 'uri'
|
4
5
|
|
5
6
|
# The PostgreSQL connection class. The interface for this class is based on
|
6
7
|
# {libpq}[http://www.postgresql.org/docs/9.2/interactive/libpq.html], the C
|
@@ -34,46 +35,55 @@ class PG::Connection
|
|
34
35
|
def self::parse_connect_args( *args )
|
35
36
|
return '' if args.empty?
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
hash_arg = args.last.is_a?( Hash ) ? args.pop : {}
|
39
|
+
option_string = ''
|
40
|
+
options = {}
|
40
41
|
|
41
42
|
# Parameter 'fallback_application_name' was introduced in PostgreSQL 9.0
|
42
43
|
# together with PQescapeLiteral().
|
43
|
-
if PG::Connection.instance_methods.find{|m| m.to_sym == :escape_literal }
|
44
|
-
|
45
|
-
appname = PG::Connection.quote_connstr( appname )
|
46
|
-
connopts = ["fallback_application_name=#{appname}"]
|
47
|
-
else
|
48
|
-
connopts = []
|
44
|
+
if PG::Connection.instance_methods.find {|m| m.to_sym == :escape_literal }
|
45
|
+
options[:fallback_application_name] = $0.sub( /^(.{30}).{4,}(.{30})$/ ){ $1+"..."+$2 }
|
49
46
|
end
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
if args.length == 1
|
49
|
+
case args.first
|
50
|
+
when URI, URI.regexp
|
51
|
+
uri = URI(args.first)
|
52
|
+
options.merge!( Hash[URI.decode_www_form( uri.query )] ) if uri.query
|
53
|
+
when /=/
|
54
|
+
# Option string style
|
55
|
+
option_string = args.first.to_s
|
56
|
+
else
|
57
|
+
# Positional parameters
|
58
|
+
options[CONNECT_ARGUMENT_ORDER.first.to_sym] = args.first
|
56
59
|
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# Option string style
|
60
|
-
if args.length == 1 && args.first.to_s.index( '=' )
|
61
|
-
connopts.unshift( args.first )
|
62
|
-
|
63
|
-
# Append positional parameters
|
64
60
|
else
|
65
|
-
|
66
|
-
|
61
|
+
max = CONNECT_ARGUMENT_ORDER.length
|
62
|
+
raise ArgumentError,
|
63
|
+
"Extra positional parameter %d: %p" % [ max + 1, args[max] ] if args.length > max
|
67
64
|
|
68
|
-
|
69
|
-
|
70
|
-
connopts.push( "%s=%s" % [key, PG::Connection.quote_connstr(val.to_s)] )
|
65
|
+
CONNECT_ARGUMENT_ORDER.zip( args ) do |(k,v)|
|
66
|
+
options[ k.to_sym ] = v if v
|
71
67
|
end
|
72
68
|
end
|
73
69
|
|
74
|
-
|
70
|
+
options.merge!( hash_arg )
|
71
|
+
|
72
|
+
if uri
|
73
|
+
uri.host = nil if options[:host]
|
74
|
+
uri.port = nil if options[:port]
|
75
|
+
uri.user = nil if options[:user]
|
76
|
+
uri.password = nil if options[:password]
|
77
|
+
uri.path = '' if options[:dbname]
|
78
|
+
uri.query = URI.encode_www_form( options )
|
79
|
+
return uri.to_s.sub( /^#{uri.scheme}:(?!\/\/)/, "#{uri.scheme}://" )
|
80
|
+
else
|
81
|
+
option_string += ' ' unless option_string.empty? && options.empty?
|
82
|
+
return option_string + options.map { |k,v| "#{k}=#{quote_connstr(v)}" }.join( ' ' )
|
83
|
+
end
|
75
84
|
end
|
76
85
|
|
86
|
+
|
77
87
|
# call-seq:
|
78
88
|
# conn.copy_data( sql ) {|sql_result| ... } -> PG::Result
|
79
89
|
#
|
data/lib/pg/text_decoder.rb
CHANGED
@@ -27,11 +27,11 @@ module PG
|
|
27
27
|
end
|
28
28
|
|
29
29
|
class TimestampWithTimeZone < SimpleDecoder
|
30
|
-
ISO_DATETIME_WITH_TIMEZONE = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?([-\+]\d\d)\z/
|
30
|
+
ISO_DATETIME_WITH_TIMEZONE = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?([-\+]\d\d):?(\d\d)?:?(\d\d)?\z/
|
31
31
|
|
32
32
|
def decode(string, tuple=nil, field=nil)
|
33
33
|
if string =~ ISO_DATETIME_WITH_TIMEZONE
|
34
|
-
Time.new $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, "#{$6}#{$7}".to_r, "#{$8}
|
34
|
+
Time.new $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, "#{$6}#{$7}".to_r, "#{$8}:#{$9 || '00'}:#{$10 || '00'}"
|
35
35
|
else
|
36
36
|
string
|
37
37
|
end
|
data/spec/pg/connection_spec.rb
CHANGED
@@ -45,6 +45,14 @@ describe PG::Connection do
|
|
45
45
|
expect( optstring ).to match( /(^|\s)user='jrandom'/ )
|
46
46
|
end
|
47
47
|
|
48
|
+
it "can create a connection option string from an option string and a hash" do
|
49
|
+
optstring = described_class.parse_connect_args( 'dbname=original', :user => 'jrandom' )
|
50
|
+
|
51
|
+
expect( optstring ).to be_a( String )
|
52
|
+
expect( optstring ).to match( /(^|\s)dbname=original/ )
|
53
|
+
expect( optstring ).to match( /(^|\s)user='jrandom'/ )
|
54
|
+
end
|
55
|
+
|
48
56
|
it "escapes single quotes and backslashes in connection parameters" do
|
49
57
|
expect(
|
50
58
|
described_class.parse_connect_args( "DB 'browser' \\" )
|
@@ -52,18 +60,72 @@ describe PG::Connection do
|
|
52
60
|
|
53
61
|
end
|
54
62
|
|
63
|
+
let(:uri) { 'postgresql://user:pass@pgsql.example.com:222/db01?sslmode=require' }
|
64
|
+
|
65
|
+
it "can connect using a URI" do
|
66
|
+
string = described_class.parse_connect_args( uri )
|
67
|
+
|
68
|
+
expect( string ).to be_a( String )
|
69
|
+
expect( string ).to match( %r{^postgresql://user:pass@pgsql.example.com:222/db01\?} )
|
70
|
+
expect( string ).to match( %r{\?.*sslmode=require} )
|
71
|
+
|
72
|
+
string = described_class.parse_connect_args( URI.parse(uri) )
|
73
|
+
|
74
|
+
expect( string ).to be_a( String )
|
75
|
+
expect( string ).to match( %r{^postgresql://user:pass@pgsql.example.com:222/db01\?} )
|
76
|
+
expect( string ).to match( %r{\?.*sslmode=require} )
|
77
|
+
end
|
78
|
+
|
79
|
+
it "can create a connection URI from a URI and a hash" do
|
80
|
+
string = described_class.parse_connect_args( uri, :connect_timeout => 2 )
|
81
|
+
|
82
|
+
expect( string ).to be_a( String )
|
83
|
+
expect( string ).to match( %r{^postgresql://user:pass@pgsql.example.com:222/db01\?} )
|
84
|
+
expect( string ).to match( %r{\?.*sslmode=require} )
|
85
|
+
expect( string ).to match( %r{\?.*connect_timeout=2} )
|
86
|
+
|
87
|
+
string = described_class.parse_connect_args( uri,
|
88
|
+
:user => 'a',
|
89
|
+
:password => 'b',
|
90
|
+
:host => 'localhost',
|
91
|
+
:port => 555,
|
92
|
+
:dbname => 'x' )
|
93
|
+
|
94
|
+
expect( string ).to be_a( String )
|
95
|
+
expect( string ).to match( %r{^postgresql://\?} )
|
96
|
+
expect( string ).to match( %r{\?.*user=a} )
|
97
|
+
expect( string ).to match( %r{\?.*password=b} )
|
98
|
+
expect( string ).to match( %r{\?.*host=localhost} )
|
99
|
+
expect( string ).to match( %r{\?.*port=555} )
|
100
|
+
expect( string ).to match( %r{\?.*dbname=x} )
|
101
|
+
end
|
102
|
+
|
103
|
+
it "can create a connection URI with a non-standard domain socket directory" do
|
104
|
+
string = described_class.parse_connect_args( 'postgresql://%2Fvar%2Flib%2Fpostgresql/dbname' )
|
105
|
+
|
106
|
+
expect( string ).to be_a( String )
|
107
|
+
expect( string ).to match( %r{^postgresql://%2Fvar%2Flib%2Fpostgresql/dbname} )
|
108
|
+
|
109
|
+
string = described_class.
|
110
|
+
parse_connect_args( 'postgresql:///dbname', :host => '/var/lib/postgresql' )
|
111
|
+
|
112
|
+
expect( string ).to be_a( String )
|
113
|
+
expect( string ).to match( %r{^postgresql:///dbname\?} )
|
114
|
+
expect( string ).to match( %r{\?.*host=%2Fvar%2Flib%2Fpostgresql} )
|
115
|
+
end
|
116
|
+
|
55
117
|
it "connects with defaults if no connection parameters are given" do
|
56
118
|
expect( described_class.parse_connect_args ).to eq( '' )
|
57
119
|
end
|
58
120
|
|
59
121
|
it "connects successfully with connection string" do
|
60
|
-
tmpconn = described_class.connect(@conninfo)
|
122
|
+
tmpconn = described_class.connect( @conninfo )
|
61
123
|
expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
|
62
124
|
tmpconn.finish
|
63
125
|
end
|
64
126
|
|
65
127
|
it "connects using 7 arguments converted to strings" do
|
66
|
-
tmpconn = described_class.connect('localhost', @port, nil, nil, :test, nil, nil)
|
128
|
+
tmpconn = described_class.connect( 'localhost', @port, nil, nil, :test, nil, nil )
|
67
129
|
expect( tmpconn.status ).to eq( PG::CONNECTION_OK )
|
68
130
|
tmpconn.finish
|
69
131
|
end
|
@@ -89,8 +151,13 @@ describe PG::Connection do
|
|
89
151
|
|
90
152
|
it "raises an exception when connecting with an invalid number of arguments" do
|
91
153
|
expect {
|
92
|
-
described_class.connect( 1, 2, 3, 4, 5, 6, 7, 'extra' )
|
93
|
-
}.to raise_error
|
154
|
+
described_class.connect( 1, 2, 3, 4, 5, 6, 7, 'the-extra-arg' )
|
155
|
+
}.to raise_error do |error|
|
156
|
+
expect( error ).to be_an( ArgumentError )
|
157
|
+
expect( error.message ).to match( /extra positional parameter/i )
|
158
|
+
expect( error.message ).to match( /8/ )
|
159
|
+
expect( error.message ).to match( /the-extra-arg/ )
|
160
|
+
end
|
94
161
|
end
|
95
162
|
|
96
163
|
it "can connect asynchronously", :socket_io do
|
@@ -162,8 +229,6 @@ describe PG::Connection do
|
|
162
229
|
expect( @conn.user ).to be_a_kind_of( String )
|
163
230
|
expect( @conn.pass ).to eq( "" )
|
164
231
|
expect( @conn.host ).to eq( "localhost" )
|
165
|
-
# TODO: Not sure why libpq returns a NULL ptr instead of "127.0.0.1"
|
166
|
-
expect( @conn.hostaddr ).to eq( nil ) if @conn.server_version >= 9_04_00
|
167
232
|
expect( @conn.port ).to eq( 54321 )
|
168
233
|
expect( @conn.tty ).to eq( "" )
|
169
234
|
expect( @conn.options ).to eq( "" )
|
@@ -1128,9 +1193,20 @@ describe PG::Connection do
|
|
1128
1193
|
expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
|
1129
1194
|
expect( escaped ).to eq( "\"string to\"" )
|
1130
1195
|
end
|
1196
|
+
end
|
1131
1197
|
|
1198
|
+
it "can quote bigger strings with quote_ident" do
|
1199
|
+
original = "'01234567\"" * 100
|
1200
|
+
escaped = described_class.quote_ident( original + "\0afterzero" )
|
1201
|
+
expect( escaped ).to eq( "\"" + original.gsub("\"", "\"\"") + "\"" )
|
1132
1202
|
end
|
1133
1203
|
|
1204
|
+
it "can quote Arrays with quote_ident" do
|
1205
|
+
original = "'01234567\""
|
1206
|
+
escaped = described_class.quote_ident( [original]*3 )
|
1207
|
+
expected = ["\"" + original.gsub("\"", "\"\"") + "\""] * 3
|
1208
|
+
expect( escaped ).to eq( expected.join(".") )
|
1209
|
+
end
|
1134
1210
|
|
1135
1211
|
describe "Ruby 1.9.x default_internal encoding" do
|
1136
1212
|
|