pg 1.1.0.pre20180730171000 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/ChangeLog +6595 -0
  5. data/History.rdoc +3 -8
  6. data/Manifest.txt +70 -2
  7. data/Rakefile +0 -1
  8. data/ext/pg.c +4 -1
  9. data/ext/pg.h +7 -0
  10. data/ext/pg_binary_decoder.c +1 -1
  11. data/ext/pg_binary_encoder.c +1 -1
  12. data/ext/pg_connection.c +8 -8
  13. data/ext/pg_result.c +1 -1
  14. data/ext/pg_text_decoder.c +1 -1
  15. data/ext/pg_text_encoder.c +6 -7
  16. data/ext/pg_tuple.c +4 -3
  17. data/ext/pg_type_map.c +1 -1
  18. data/ext/pg_type_map_all_strings.c +1 -1
  19. data/ext/pg_type_map_by_class.c +1 -1
  20. data/ext/pg_type_map_by_column.c +1 -1
  21. data/ext/pg_type_map_by_mri_type.c +1 -1
  22. data/ext/pg_type_map_by_oid.c +1 -1
  23. data/ext/pg_type_map_in_ruby.c +1 -1
  24. data/ext/util.c +1 -1
  25. data/lib/pg.rb +2 -2
  26. data/spec/pg/basic_type_mapping_spec.rb +4 -4
  27. data/spec/pg/connection_spec.rb +58 -13
  28. data/spec/pg/tuple_spec.rb +16 -2
  29. data/spec/pg/type_spec.rb +6 -0
  30. metadata +35 -69
  31. metadata.gz.sig +0 -0
  32. data/.gems +0 -6
  33. data/.hgignore +0 -21
  34. data/.hgsigs +0 -29
  35. data/.hgtags +0 -36
  36. data/.hoerc +0 -2
  37. data/.irbrc +0 -23
  38. data/.pryrc +0 -23
  39. data/.tm_properties +0 -21
  40. data/.travis.yml +0 -41
  41. data/Gemfile +0 -2
  42. data/appveyor.yml +0 -50
  43. data/certs/ged.pem +0 -26
  44. data/misc/openssl-pg-segfault.rb +0 -31
  45. data/misc/postgres/History.txt +0 -9
  46. data/misc/postgres/Manifest.txt +0 -5
  47. data/misc/postgres/README.txt +0 -21
  48. data/misc/postgres/Rakefile +0 -21
  49. data/misc/postgres/lib/postgres.rb +0 -16
  50. data/misc/ruby-pg/History.txt +0 -9
  51. data/misc/ruby-pg/Manifest.txt +0 -5
  52. data/misc/ruby-pg/README.txt +0 -21
  53. data/misc/ruby-pg/Rakefile +0 -21
  54. data/misc/ruby-pg/lib/ruby/pg.rb +0 -16
  55. data/pg.gemspec +0 -61
  56. data/sample/array_insert.rb +0 -20
  57. data/sample/async_api.rb +0 -106
  58. data/sample/async_copyto.rb +0 -39
  59. data/sample/async_mixed.rb +0 -56
  60. data/sample/check_conn.rb +0 -21
  61. data/sample/copydata.rb +0 -71
  62. data/sample/copyfrom.rb +0 -81
  63. data/sample/copyto.rb +0 -19
  64. data/sample/cursor.rb +0 -21
  65. data/sample/disk_usage_report.rb +0 -177
  66. data/sample/issue-119.rb +0 -94
  67. data/sample/losample.rb +0 -69
  68. data/sample/minimal-testcase.rb +0 -17
  69. data/sample/notify_wait.rb +0 -72
  70. data/sample/pg_statistics.rb +0 -285
  71. data/sample/replication_monitor.rb +0 -222
  72. data/sample/test_binary_values.rb +0 -33
  73. data/sample/wal_shipper.rb +0 -434
  74. data/sample/warehouse_partitions.rb +0 -311
@@ -1,12 +1,6 @@
1
- == v2.0.0 - far from release -
1
+ == v1.1.0 [2018-08-24] Michael Granger <ged@FaerieMUD.org>
2
2
 
3
- Removed:
4
- - Removed query method variants deprecated in pg-1.1.0.
5
-
6
-
7
- == v1.1.0 [YYYY-MM-DD] Michael Granger <ged@FaerieMUD.org>
8
-
9
- Deprecated:
3
+ Deprecated (disable warnings per PG_SKIP_DEPRECATION_WARNING=1):
10
4
  - Forwarding conn.exec to conn.exec_params is deprecated.
11
5
  - Forwarding conn.exec_params to conn.exec is deprecated.
12
6
  - Forwarding conn.async_exec to conn.async_exec_params.
@@ -20,6 +14,7 @@ PG::Connection enhancements:
20
14
  They are identical to their syncronous counterpart, but make use of PostgreSQL's async API.
21
15
  - Replace `rb_thread_fd_select()` by faster `rb_wait_for_single_fd()` in `conn.block` and `conn.async_exec` .
22
16
  - Add PG::Connection#discard_results .
17
+ - Raise an ArgumentError for strings containing zero bytes by #escape, #escape_literal, #escape_identifier, #quote_ident and PG::TextEncoder::Identifier. These methods previously truncated strings.
23
18
 
24
19
  Result retrieval enhancements:
25
20
  - Add PG::Result#tuple_values to retrieve all field values of a row as array.
@@ -1,4 +1,72 @@
1
- # Manifest is built per Rakefile as part of `rake gem`.
2
- # These files are required to satisfy Hoe:
1
+ .gemtest
2
+ BSDL
3
+ ChangeLog
4
+ Contributors.rdoc
5
+ History.rdoc
6
+ LICENSE
7
+ Manifest.txt
8
+ POSTGRES
9
+ README-OS_X.rdoc
10
+ README-Windows.rdoc
11
+ README.ja.rdoc
3
12
  README.rdoc
13
+ Rakefile
14
+ Rakefile.cross
15
+ ext/errorcodes.def
16
+ ext/errorcodes.rb
17
+ ext/errorcodes.txt
18
+ ext/extconf.rb
19
+ ext/gvl_wrappers.c
20
+ ext/gvl_wrappers.h
21
+ ext/pg.c
22
+ ext/pg.h
23
+ ext/pg_binary_decoder.c
24
+ ext/pg_binary_encoder.c
25
+ ext/pg_coder.c
26
+ ext/pg_connection.c
27
+ ext/pg_copy_coder.c
28
+ ext/pg_errors.c
29
+ ext/pg_result.c
30
+ ext/pg_text_decoder.c
31
+ ext/pg_text_encoder.c
32
+ ext/pg_tuple.c
33
+ ext/pg_type_map.c
34
+ ext/pg_type_map_all_strings.c
35
+ ext/pg_type_map_by_class.c
36
+ ext/pg_type_map_by_column.c
37
+ ext/pg_type_map_by_mri_type.c
38
+ ext/pg_type_map_by_oid.c
39
+ ext/pg_type_map_in_ruby.c
40
+ ext/util.c
41
+ ext/util.h
42
+ ext/vc/pg.sln
43
+ ext/vc/pg_18/pg.vcproj
44
+ ext/vc/pg_19/pg_19.vcproj
4
45
  lib/pg.rb
46
+ lib/pg/basic_type_mapping.rb
47
+ lib/pg/binary_decoder.rb
48
+ lib/pg/coder.rb
49
+ lib/pg/connection.rb
50
+ lib/pg/constants.rb
51
+ lib/pg/exceptions.rb
52
+ lib/pg/result.rb
53
+ lib/pg/text_decoder.rb
54
+ lib/pg/text_encoder.rb
55
+ lib/pg/tuple.rb
56
+ lib/pg/type_map_by_column.rb
57
+ spec/data/expected_trace.out
58
+ spec/data/random_binary_data
59
+ spec/helpers.rb
60
+ spec/pg/basic_type_mapping_spec.rb
61
+ spec/pg/connection_spec.rb
62
+ spec/pg/connection_sync_spec.rb
63
+ spec/pg/result_spec.rb
64
+ spec/pg/tuple_spec.rb
65
+ spec/pg/type_map_by_class_spec.rb
66
+ spec/pg/type_map_by_column_spec.rb
67
+ spec/pg/type_map_by_mri_type_spec.rb
68
+ spec/pg/type_map_by_oid_spec.rb
69
+ spec/pg/type_map_in_ruby_spec.rb
70
+ spec/pg/type_map_spec.rb
71
+ spec/pg/type_spec.rb
72
+ spec/pg_spec.rb
data/Rakefile CHANGED
@@ -55,7 +55,6 @@ $hoespec = Hoe.spec 'pg' do
55
55
  self.extra_rdoc_files = Rake::FileList[ '*.rdoc' ]
56
56
  self.extra_rdoc_files.include( 'POSTGRES', 'LICENSE' )
57
57
  self.extra_rdoc_files.include( 'ext/*.c' )
58
- self.spec_extras[:files] = `hg manifest || git ls-files`.split
59
58
  self.license 'BSD-3-Clause'
60
59
 
61
60
  self.developer 'Michael Granger', 'ged@FaerieMUD.org'
data/ext/pg.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg.c - Toplevel extension
3
- * $Id$
3
+ * $Id: pg.c,v 0d4acc8a0bc5 2018/08/05 09:07:58 lars $
4
4
  *
5
5
  * Author/s:
6
6
  *
@@ -48,6 +48,7 @@
48
48
 
49
49
  #include "pg.h"
50
50
 
51
+ int pg_skip_deprecation_warning;
51
52
  VALUE rb_mPG;
52
53
  VALUE rb_mPGconstants;
53
54
 
@@ -381,6 +382,8 @@ pg_s_init_ssl(VALUE self, VALUE do_ssl)
381
382
  void
382
383
  Init_pg_ext()
383
384
  {
385
+ pg_skip_deprecation_warning = RTEST(rb_eval_string("ENV['PG_SKIP_DEPRECATION_WARNING']"));
386
+
384
387
  rb_mPG = rb_define_module( "PG" );
385
388
  rb_mPGconstants = rb_define_module_under( rb_mPG, "Constants" );
386
389
 
data/ext/pg.h CHANGED
@@ -217,6 +217,7 @@ typedef struct {
217
217
  * Globals
218
218
  **************************************************************************/
219
219
 
220
+ extern int pg_skip_deprecation_warning;
220
221
  extern VALUE rb_mPG;
221
222
  extern VALUE rb_ePGerror;
222
223
  extern VALUE rb_eServerError;
@@ -350,4 +351,10 @@ rb_encoding *pg_conn_enc_get _(( PGconn * ));
350
351
  void notice_receiver_proxy(void *arg, const PGresult *result);
351
352
  void notice_processor_proxy(void *arg, const char *message);
352
353
 
354
+ /* reports if `-W' specified and PG_SKIP_DEPRECATION_WARNING environment variable isn't set */
355
+ #define pg_deprecated(x) \
356
+ do { \
357
+ if( !pg_skip_deprecation_warning ) rb_warning x; \
358
+ } while(0);
359
+
353
360
  #endif /* end __pg_h */
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id$
3
+ * $Id: pg_binary_decoder.c,v 5d166a4d0441 2018/07/29 12:03:00 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id$
3
+ * $Id: pg_binary_encoder.c,v e61a06f1f5ed 2015/12/25 21:14:21 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_connection.c - PG::Connection class extension
3
- * $Id$
3
+ * $Id: pg_connection.c,v e57f6b452eb3 2018/08/18 10:58:52 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1006,7 +1006,7 @@ pgconn_exec(int argc, VALUE *argv, VALUE self)
1006
1006
  }
1007
1007
  return rb_pgresult;
1008
1008
  }
1009
- rb_warning("forwarding exec to exec_params is deprecated");
1009
+ pg_deprecated(("forwarding exec to exec_params is deprecated"));
1010
1010
 
1011
1011
  /* Otherwise, just call #exec_params instead for backward-compatibility */
1012
1012
  return pgconn_exec_params( argc, argv, self );
@@ -1321,7 +1321,7 @@ pgconn_exec_params( int argc, VALUE *argv, VALUE self )
1321
1321
  * is passed to #exec
1322
1322
  */
1323
1323
  if ( NIL_P(paramsData.params) ) {
1324
- rb_warning("forwarding exec_params to exec is deprecated");
1324
+ pg_deprecated(("forwarding exec_params to exec is deprecated"));
1325
1325
  return pgconn_exec( 1, argv, self );
1326
1326
  }
1327
1327
  pgconn_query_assign_typemap( self, &paramsData );
@@ -1587,7 +1587,7 @@ pgconn_s_escape(VALUE self, VALUE string)
1587
1587
  int enc_idx;
1588
1588
  int singleton = !rb_obj_is_kind_of(self, rb_cPGconn);
1589
1589
 
1590
- Check_Type(string, T_STRING);
1590
+ StringValueCStr(string);
1591
1591
  enc_idx = ENCODING_GET( singleton ? string : self );
1592
1592
  if( ENCODING_GET(string) != enc_idx ){
1593
1593
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
@@ -1703,7 +1703,7 @@ pgconn_escape_literal(VALUE self, VALUE string)
1703
1703
  VALUE result = Qnil;
1704
1704
  int enc_idx = ENCODING_GET(self);
1705
1705
 
1706
- Check_Type(string, T_STRING);
1706
+ StringValueCStr(string);
1707
1707
  if( ENCODING_GET(string) != enc_idx ){
1708
1708
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1709
1709
  }
@@ -1745,7 +1745,7 @@ pgconn_escape_identifier(VALUE self, VALUE string)
1745
1745
  VALUE result = Qnil;
1746
1746
  int enc_idx = ENCODING_GET(self);
1747
1747
 
1748
- Check_Type(string, T_STRING);
1748
+ StringValueCStr(string);
1749
1749
  if( ENCODING_GET(string) != enc_idx ){
1750
1750
  string = rb_str_export_to_enc(string, rb_enc_from_index(enc_idx));
1751
1751
  }
@@ -1851,7 +1851,7 @@ pgconn_send_query(int argc, VALUE *argv, VALUE self)
1851
1851
  return Qnil;
1852
1852
  }
1853
1853
 
1854
- rb_warning("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated");
1854
+ pg_deprecated(("forwarding async_exec to async_exec_params and send_query to send_query_params is deprecated"));
1855
1855
 
1856
1856
  /* If called with parameters, and optionally result_format,
1857
1857
  * use PQsendQueryParams
@@ -3223,7 +3223,7 @@ pgconn_async_exec_params(int argc, VALUE *argv, VALUE self)
3223
3223
  pgconn_discard_results( self );
3224
3224
  /* If called with no or nil parameters, use PQsendQuery for compatibility */
3225
3225
  if ( argc == 1 || (argc >= 2 && argc <= 4 && NIL_P(argv[1]) )) {
3226
- rb_warning("forwarding async_exec_params to async_exec is deprecated");
3226
+ pg_deprecated(("forwarding async_exec_params to async_exec is deprecated"));
3227
3227
  pgconn_send_query( argc, argv, self );
3228
3228
  } else {
3229
3229
  pgconn_send_query_params( argc, argv, self );
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_result.c - PG::Result class extension
3
- * $Id$
3
+ * $Id: pg_result.c,v a8b70c42b3e8 2018/07/30 14:09:38 kanis $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_decoder.c - PG::TextDecoder module
3
- * $Id$
3
+ * $Id: pg_text_decoder.c,v cee615e0ea2c 2018/07/30 05:27:05 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_text_encoder.c - PG::TextEncoder module
3
- * $Id$
3
+ * $Id: pg_text_encoder.c,v e57f6b452eb3 2018/08/18 10:58:52 lars $
4
4
  *
5
5
  */
6
6
 
@@ -468,20 +468,19 @@ pg_text_enc_array(t_pg_coder *conv, VALUE value, char *out, VALUE *intermediate,
468
468
  static char *
469
469
  quote_identifier( VALUE value, VALUE out_string, char *current_out ){
470
470
  char *p_in = RSTRING_PTR(value);
471
- char *ptr1;
472
471
  size_t strlen = RSTRING_LEN(value);
472
+ char *p_inend = p_in + strlen;
473
473
  char *end_capa = current_out;
474
474
 
475
475
  PG_RB_STR_ENSURE_CAPA( out_string, strlen + 2, current_out, end_capa );
476
476
  *current_out++ = '"';
477
- for(ptr1 = p_in; ptr1 != p_in + strlen; ptr1++) {
478
- char c = *ptr1;
477
+ for(; p_in != p_inend; p_in++) {
478
+ char c = *p_in;
479
479
  if (c == '"'){
480
- strlen++;
481
- PG_RB_STR_ENSURE_CAPA( out_string, p_in - ptr1 + strlen + 1, current_out, end_capa );
480
+ PG_RB_STR_ENSURE_CAPA( out_string, p_inend - p_in + 2, current_out, end_capa );
482
481
  *current_out++ = '"';
483
482
  } else if (c == 0){
484
- break;
483
+ rb_raise(rb_eArgError, "string contains null byte");
485
484
  }
486
485
  *current_out++ = c;
487
486
  }
@@ -311,9 +311,9 @@ pg_tuple_yield_key_value(VALUE key, VALUE index, VALUE _this)
311
311
 
312
312
  /*
313
313
  * call-seq:
314
- * tup.each{ |value| ... }
314
+ * tup.each{ |key, value| ... }
315
315
  *
316
- * Invokes block for each field value in the tuple.
316
+ * Invokes block for each field name and value in the tuple.
317
317
  */
318
318
  static VALUE
319
319
  pg_tuple_each(VALUE self)
@@ -354,7 +354,8 @@ pg_tuple_each_value(VALUE self)
354
354
  RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);
355
355
 
356
356
  for(field_num = 0; field_num < this->num_fields; field_num++) {
357
- rb_yield(pg_tuple_aref(self, INT2NUM(field_num)));
357
+ VALUE value = pg_tuple_materialize_field(this, field_num);
358
+ rb_yield(value);
358
359
  }
359
360
 
360
361
  pg_tuple_detach(this);
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id$
3
+ * $Id: pg_type_map.c,v 2af122820861 2017/01/14 19:56:36 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
3
- * $Id$
3
+ * $Id: pg_type_map_all_strings.c,v c53f993a4254 2014/12/12 21:57:29 lars $
4
4
  *
5
5
  * This is the default typemap.
6
6
  *
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_class.c - PG::TypeMapByClass class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_class.c,v eeb8a82c5328 2014/11/10 19:34:02 lars $
4
4
  *
5
5
  * This type map can be used to select value encoders based on the class
6
6
  * of the given value to be send.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_column_map.c - PG::ColumnMap class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_column.c,v fcf731d3dff7 2015/09/08 12:25:06 jfali $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_mri_type.c - PG::TypeMapByMriType class extension
3
- * $Id$
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.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_by_oid.c - PG::TypeMapByOid class extension
3
- * $Id$
3
+ * $Id: pg_type_map_by_oid.c,v c99d26015e3c 2014/12/12 20:58:25 lars $
4
4
  *
5
5
  */
6
6
 
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * pg_type_map_in_ruby.c - PG::TypeMapInRuby class extension
3
- * $Id$
3
+ * $Id: pg_type_map_in_ruby.c,v 3d89d3aae4fd 2015/01/05 16:19:41 kanis $
4
4
  *
5
5
  */
6
6
 
data/ext/util.c CHANGED
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * util.c - Utils for ruby-pg
3
- * $Id$
3
+ * $Id: util.c,v fc1c4deb1398 2018/06/25 12:02:09 kanis $
4
4
  *
5
5
  */
6
6
 
data/lib/pg.rb CHANGED
@@ -35,10 +35,10 @@ end
35
35
  module PG
36
36
 
37
37
  # Library version
38
- VERSION = '1.1.0.pre20180730171000'
38
+ VERSION = '1.1.0'
39
39
 
40
40
  # VCS revision
41
- REVISION = %q$Revision$
41
+ REVISION = %q$Revision: ca83074366ac $
42
42
 
43
43
  class NotAllCopyDataRetrieved < PG::Error
44
44
  end
@@ -256,10 +256,10 @@ describe 'Basic type mapping' do
256
256
  CAST('294276-12-31 23:58:59.1231+03' AS TIMESTAMP WITH TIME ZONE),
257
257
  CAST('infinity' AS TIMESTAMP WITH TIME ZONE),
258
258
  CAST('-infinity' AS TIMESTAMP WITH TIME ZONE)", [], format )
259
- expect( res.getvalue(0,0).iso8601(3) ).to eq( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal.iso8601(3) )
260
- expect( res.getvalue(0,1).iso8601(3) ).to eq( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal.iso8601(3) )
261
- expect( res.getvalue(0,2).iso8601(3) ).to eq( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal.iso8601(3) )
262
- expect( res.getvalue(0,3).iso8601(3) ).to eq( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal.iso8601(3) )
259
+ expect( res.getvalue(0,0) ).to be_within(1e-3).of( Time.new(2013, 12, 31, 23, 58, 59, "+02:00").getlocal )
260
+ expect( res.getvalue(0,1) ).to be_within(1e-3).of( Time.new(1913, 12, 31, 23, 58, 59.1231, "-03:00").getlocal )
261
+ expect( res.getvalue(0,2) ).to be_within(1e-3).of( Time.new(-4713, 11, 24, 23, 58, 59.1231, "-03:00").getlocal )
262
+ expect( res.getvalue(0,3) ).to be_within(1e-3).of( Time.new(294276, 12, 31, 23, 58, 59.1231, "+03:00").getlocal )
263
263
  expect( res.getvalue(0,4) ).to eq( 'infinity' )
264
264
  expect( res.getvalue(0,5) ).to eq( '-infinity' )
265
265
  end
@@ -1237,51 +1237,51 @@ describe PG::Connection do
1237
1237
  end
1238
1238
 
1239
1239
  it "uses the client encoding for escaped string" do
1240
- original = "Möhre to\0 escape".encode( "utf-16be" )
1240
+ original = "Möhre to 'scape".encode( "utf-16be" )
1241
1241
  @conn.set_client_encoding( "euc_jp" )
1242
1242
  escaped = @conn.escape( original )
1243
1243
  expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1244
- expect( escaped ).to eq( "Möhre to".encode(Encoding::EUC_JP) )
1244
+ expect( escaped ).to eq( "Möhre to ''scape".encode(Encoding::EUC_JP) )
1245
1245
  end
1246
1246
 
1247
1247
  it "uses the client encoding for escaped literal" do
1248
- original = "Möhre to\0 escape".encode( "utf-16be" )
1248
+ original = "Möhre to 'scape".encode( "utf-16be" )
1249
1249
  @conn.set_client_encoding( "euc_jp" )
1250
1250
  escaped = @conn.escape_literal( original )
1251
1251
  expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1252
- expect( escaped ).to eq( "'Möhre to'".encode(Encoding::EUC_JP) )
1252
+ expect( escaped ).to eq( "'Möhre to ''scape'".encode(Encoding::EUC_JP) )
1253
1253
  end
1254
1254
 
1255
1255
  it "uses the client encoding for escaped identifier" do
1256
- original = "Möhre to\0 escape".encode( "utf-16le" )
1256
+ original = "Möhre to 'scape".encode( "utf-16le" )
1257
1257
  @conn.set_client_encoding( "euc_jp" )
1258
1258
  escaped = @conn.escape_identifier( original )
1259
1259
  expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1260
- expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
1260
+ expect( escaped ).to eq( "\"Möhre to 'scape\"".encode(Encoding::EUC_JP) )
1261
1261
  end
1262
1262
 
1263
1263
  it "uses the client encoding for quote_ident" do
1264
- original = "Möhre to\0 escape".encode( "utf-16le" )
1264
+ original = "Möhre to 'scape".encode( "utf-16le" )
1265
1265
  @conn.set_client_encoding( "euc_jp" )
1266
1266
  escaped = @conn.quote_ident( original )
1267
1267
  expect( escaped.encoding ).to eq( Encoding::EUC_JP )
1268
- expect( escaped ).to eq( "\"Möhre to\"".encode(Encoding::EUC_JP) )
1268
+ expect( escaped ).to eq( "\"Möhre to 'scape\"".encode(Encoding::EUC_JP) )
1269
1269
  end
1270
1270
 
1271
1271
  it "uses the previous string encoding for escaped string" do
1272
- original = "Möhre to\0 escape".encode( "iso-8859-1" )
1272
+ original = "Möhre to 'scape".encode( "iso-8859-1" )
1273
1273
  @conn.set_client_encoding( "euc_jp" )
1274
1274
  escaped = described_class.escape( original )
1275
1275
  expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
1276
- expect( escaped ).to eq( "Möhre to".encode(Encoding::ISO8859_1) )
1276
+ expect( escaped ).to eq( "Möhre to ''scape".encode(Encoding::ISO8859_1) )
1277
1277
  end
1278
1278
 
1279
1279
  it "uses the previous string encoding for quote_ident" do
1280
- original = "Möhre to\0 escape".encode( "iso-8859-1" )
1280
+ original = "Möhre to 'scape".encode( "iso-8859-1" )
1281
1281
  @conn.set_client_encoding( "euc_jp" )
1282
1282
  escaped = described_class.quote_ident( original )
1283
1283
  expect( escaped.encoding ).to eq( Encoding::ISO8859_1 )
1284
- expect( escaped.encode ).to eq( "\"Möhre to\"".encode(Encoding::ISO8859_1) )
1284
+ expect( escaped.encode ).to eq( "\"Möhre to 'scape\"".encode(Encoding::ISO8859_1) )
1285
1285
  end
1286
1286
 
1287
1287
  it "raises appropriate error if set_client_encoding is called with invalid arguments" do
@@ -1366,9 +1366,54 @@ describe PG::Connection do
1366
1366
  end
1367
1367
  end
1368
1368
 
1369
+ it "rejects command strings with zero bytes" do
1370
+ expect{ @conn.exec( "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
1371
+ expect{ @conn.exec_params( "SELECT 1;\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
1372
+ expect{ @conn.prepare( "abc\x00", "SELECT 1;" ) }.to raise_error(ArgumentError, /null byte/)
1373
+ expect{ @conn.prepare( "abc", "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
1374
+ expect{ @conn.exec_prepared( "abc\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
1375
+ expect{ @conn.describe_prepared( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
1376
+ expect{ @conn.describe_portal( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
1377
+ expect{ @conn.send_query( "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
1378
+ expect{ @conn.send_query_params( "SELECT 1;\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
1379
+ expect{ @conn.send_prepare( "abc\x00", "SELECT 1;" ) }.to raise_error(ArgumentError, /null byte/)
1380
+ expect{ @conn.send_prepare( "abc", "SELECT 1;\x00" ) }.to raise_error(ArgumentError, /null byte/)
1381
+ expect{ @conn.send_query_prepared( "abc\x00", [] ) }.to raise_error(ArgumentError, /null byte/)
1382
+ expect{ @conn.send_describe_prepared( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
1383
+ expect{ @conn.send_describe_portal( "abc\x00" ) }.to raise_error(ArgumentError, /null byte/)
1384
+ end
1385
+
1386
+ it "rejects query params with zero bytes" do
1387
+ expect{ @conn.exec_params( "SELECT 1;\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
1388
+ expect{ @conn.exec_prepared( "abc\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
1389
+ expect{ @conn.send_query_params( "SELECT 1;\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
1390
+ expect{ @conn.send_query_prepared( "abc\x00", ["ab\x00"] ) }.to raise_error(ArgumentError, /null byte/)
1391
+ end
1392
+
1393
+ it "rejects string with zero bytes in escape" do
1394
+ expect{ @conn.escape( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
1395
+ end
1396
+
1397
+ it "rejects string with zero bytes in escape_literal" do
1398
+ expect{ @conn.escape_literal( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
1399
+ end
1400
+
1401
+ it "rejects string with zero bytes in escape_identifier" do
1402
+ expect{ @conn.escape_identifier( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
1403
+ end
1404
+
1405
+ it "rejects string with zero bytes in quote_ident" do
1406
+ expect{ described_class.quote_ident( "ab\x00cd" ) }.to raise_error(ArgumentError, /null byte/)
1407
+ end
1408
+
1409
+ it "rejects Array with string with zero bytes" do
1410
+ original = ["xyz", "2\x00"]
1411
+ expect{ described_class.quote_ident( original ) }.to raise_error(ArgumentError, /null byte/)
1412
+ end
1413
+
1369
1414
  it "can quote bigger strings with quote_ident" do
1370
1415
  original = "'01234567\"" * 100
1371
- escaped = described_class.quote_ident( original + "\0afterzero" )
1416
+ escaped = described_class.quote_ident( original )
1372
1417
  expect( escaped ).to eq( "\"" + original.gsub("\"", "\"\"") + "\"" )
1373
1418
  end
1374
1419