pg 1.1.4 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - checksums.yaml.gz.sig +0 -0
 - data.tar.gz.sig +0 -0
 - data/ChangeLog +0 -6595
 - data/History.rdoc +86 -0
 - data/Manifest.txt +3 -2
 - data/README-Windows.rdoc +4 -4
 - data/README.ja.rdoc +1 -2
 - data/README.rdoc +44 -9
 - data/Rakefile +8 -6
 - data/Rakefile.cross +57 -56
 - data/ext/errorcodes.def +64 -0
 - data/ext/errorcodes.txt +18 -2
 - data/ext/extconf.rb +6 -6
 - data/ext/pg.c +132 -95
 - data/ext/pg.h +21 -18
 - data/ext/pg_binary_decoder.c +9 -9
 - data/ext/pg_binary_encoder.c +13 -12
 - data/ext/pg_coder.c +21 -9
 - data/ext/pg_connection.c +388 -298
 - data/ext/pg_copy_coder.c +6 -3
 - data/ext/pg_record_coder.c +491 -0
 - data/ext/pg_result.c +279 -127
 - data/ext/pg_text_decoder.c +14 -8
 - data/ext/pg_text_encoder.c +180 -48
 - data/ext/pg_tuple.c +14 -6
 - data/ext/pg_type_map.c +1 -1
 - data/ext/pg_type_map_all_strings.c +4 -4
 - data/ext/pg_type_map_by_class.c +9 -4
 - data/ext/pg_type_map_by_column.c +7 -6
 - data/ext/pg_type_map_by_mri_type.c +1 -1
 - data/ext/pg_type_map_by_oid.c +3 -2
 - data/ext/pg_type_map_in_ruby.c +1 -1
 - data/ext/{util.c → pg_util.c} +5 -5
 - data/ext/{util.h → pg_util.h} +0 -0
 - data/lib/pg.rb +4 -4
 - data/lib/pg/basic_type_mapping.rb +81 -18
 - data/lib/pg/binary_decoder.rb +1 -0
 - data/lib/pg/coder.rb +22 -1
 - data/lib/pg/connection.rb +2 -2
 - data/lib/pg/constants.rb +1 -0
 - data/lib/pg/exceptions.rb +1 -0
 - data/lib/pg/result.rb +13 -1
 - data/lib/pg/text_decoder.rb +2 -3
 - data/lib/pg/text_encoder.rb +8 -18
 - data/lib/pg/type_map_by_column.rb +2 -1
 - data/spec/helpers.rb +11 -11
 - data/spec/pg/basic_type_mapping_spec.rb +140 -18
 - data/spec/pg/connection_spec.rb +166 -89
 - data/spec/pg/result_spec.rb +194 -4
 - data/spec/pg/tuple_spec.rb +55 -2
 - data/spec/pg/type_map_by_class_spec.rb +1 -1
 - data/spec/pg/type_map_by_column_spec.rb +5 -1
 - data/spec/pg/type_map_by_oid_spec.rb +2 -2
 - data/spec/pg/type_spec.rb +180 -6
 - metadata +31 -30
 - metadata.gz.sig +0 -0
 
    
        data/ext/pg_type_map.c
    CHANGED
    
    
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * pg_type_map_all_strings.c - PG::TypeMapAllStrings class extension
         
     | 
| 
       3 
     | 
    
         
            -
             * $Id 
     | 
| 
      
 3 
     | 
    
         
            +
             * $Id$
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             * This is the default typemap.
         
     | 
| 
       6 
6 
     | 
    
         
             
             *
         
     | 
| 
         @@ -33,9 +33,9 @@ pg_tmas_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field ) 
     | 
|
| 
       33 
33 
     | 
    
         
             
            	len = PQgetlength( p_result->pgresult, tuple, field );
         
     | 
| 
       34 
34 
     | 
    
         | 
| 
       35 
35 
     | 
    
         
             
            	if ( 0 == PQfformat(p_result->pgresult, field) ) {
         
     | 
| 
       36 
     | 
    
         
            -
            		ret = pg_text_dec_string(NULL, val, len, tuple, field,  
     | 
| 
      
 36 
     | 
    
         
            +
            		ret = pg_text_dec_string(NULL, val, len, tuple, field, p_result->enc_idx);
         
     | 
| 
       37 
37 
     | 
    
         
             
            	} else {
         
     | 
| 
       38 
     | 
    
         
            -
            		ret = pg_bin_dec_bytea(NULL, val, len, tuple, field,  
     | 
| 
      
 38 
     | 
    
         
            +
            		ret = pg_bin_dec_bytea(NULL, val, len, tuple, field, p_result->enc_idx);
         
     | 
| 
       39 
39 
     | 
    
         
             
            	}
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
            	return ret;
         
     | 
| 
         @@ -99,7 +99,7 @@ init_pg_type_map_all_strings() 
     | 
|
| 
       99 
99 
     | 
    
         
             
            	 * This type map casts all values received from the database server to Strings
         
     | 
| 
       100 
100 
     | 
    
         
             
            	 * and sends all values to the server after conversion to String by +#to_s+ .
         
     | 
| 
       101 
101 
     | 
    
         
             
            	 * That means, it is hard coded to PG::TextEncoder::String for value encoding
         
     | 
| 
       102 
     | 
    
         
            -
            	 * and to PG::TextDecoder::String for text format  
     | 
| 
      
 102 
     | 
    
         
            +
            	 * and to PG::TextDecoder::String for text format respectively PG::BinaryDecoder::Bytea
         
     | 
| 
       103 
103 
     | 
    
         
             
            	 * for binary format received from the server.
         
     | 
| 
       104 
104 
     | 
    
         
             
            	 *
         
     | 
| 
       105 
105 
     | 
    
         
             
            	 * It is suitable for type casting query bind parameters, result values and
         
     | 
    
        data/ext/pg_type_map_by_class.c
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * pg_type_map_by_class.c - PG::TypeMapByClass class extension
         
     | 
| 
       3 
     | 
    
         
            -
             * $Id 
     | 
| 
      
 3 
     | 
    
         
            +
             * $Id$
         
     | 
| 
       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.
         
     | 
| 
         @@ -28,7 +28,7 @@ typedef struct { 
     | 
|
| 
       28 
28 
     | 
    
         
             
             * We use 8 Bits of the klass object id as index to a 256 entry cache.
         
     | 
| 
       29 
29 
     | 
    
         
             
             * This avoids full lookups in most cases.
         
     | 
| 
       30 
30 
     | 
    
         
             
             */
         
     | 
| 
       31 
     | 
    
         
            -
            #define CACHE_LOOKUP(this, klass) ( &this->cache_row[(klass >> 8) & 0xff] )
         
     | 
| 
      
 31 
     | 
    
         
            +
            #define CACHE_LOOKUP(this, klass) ( &this->cache_row[(((unsigned long)klass) >> 8) & 0xff] )
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
            static t_pg_coder *
         
     | 
| 
         @@ -66,7 +66,7 @@ pg_tmbk_lookup_klass(t_tmbk *this, VALUE klass, VALUE param_value) 
     | 
|
| 
       66 
66 
     | 
    
         
             
            			Data_Get_Struct(obj, t_pg_coder, p_coder);
         
     | 
| 
       67 
67 
     | 
    
         
             
            		}else{
         
     | 
| 
       68 
68 
     | 
    
         
             
            			if( RB_TYPE_P(obj, T_SYMBOL) ){
         
     | 
| 
       69 
     | 
    
         
            -
            				/* A  
     | 
| 
      
 69 
     | 
    
         
            +
            				/* A Symbol: Call the method with this name. */
         
     | 
| 
       70 
70 
     | 
    
         
             
            				obj = rb_funcall(this->self, SYM2ID(obj), 1, param_value);
         
     | 
| 
       71 
71 
     | 
    
         
             
            			}else{
         
     | 
| 
       72 
72 
     | 
    
         
             
            				/* A Proc object (or something that responds to #call). */
         
     | 
| 
         @@ -126,7 +126,11 @@ pg_tmbk_mark( t_tmbk *this ) 
     | 
|
| 
       126 
126 
     | 
    
         
             
            {
         
     | 
| 
       127 
127 
     | 
    
         
             
            	rb_gc_mark(this->typemap.default_typemap);
         
     | 
| 
       128 
128 
     | 
    
         
             
            	rb_gc_mark(this->klass_to_coder);
         
     | 
| 
       129 
     | 
    
         
            -
            	 
     | 
| 
      
 129 
     | 
    
         
            +
            	rb_gc_mark(this->self);
         
     | 
| 
      
 130 
     | 
    
         
            +
            	/* Clear the cache, to be safe from changes of klass VALUE by GC.compact.
         
     | 
| 
      
 131 
     | 
    
         
            +
            	 * TODO: Move cache clearing to compactation callback provided by Ruby-2.7+.
         
     | 
| 
      
 132 
     | 
    
         
            +
            	 */
         
     | 
| 
      
 133 
     | 
    
         
            +
            	memset(&this->cache_row, 0, sizeof(this->cache_row));
         
     | 
| 
       130 
134 
     | 
    
         
             
            }
         
     | 
| 
       131 
135 
     | 
    
         | 
| 
       132 
136 
     | 
    
         
             
            static VALUE
         
     | 
| 
         @@ -235,5 +239,6 @@ init_pg_type_map_by_class() 
     | 
|
| 
       235 
239 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByClass, "[]=", pg_tmbk_aset, 2 );
         
     | 
| 
       236 
240 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByClass, "[]", pg_tmbk_aref, 1 );
         
     | 
| 
       237 
241 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByClass, "coders", pg_tmbk_coders, 0 );
         
     | 
| 
      
 242 
     | 
    
         
            +
            	/* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
         
     | 
| 
       238 
243 
     | 
    
         
             
            	rb_include_module( rb_cTypeMapByClass, rb_mDefaultTypeMappable );
         
     | 
| 
       239 
244 
     | 
    
         
             
            }
         
     | 
    
        data/ext/pg_type_map_by_column.c
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * pg_column_map.c - PG::ColumnMap class extension
         
     | 
| 
       3 
     | 
    
         
            -
             * $Id 
     | 
| 
      
 3 
     | 
    
         
            +
             * $Id$
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             */
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -99,11 +99,11 @@ pg_tmbc_result_value( t_typemap *p_typemap, VALUE result, int tuple, int field ) 
     | 
|
| 
       99 
99 
     | 
    
         
             
            		int len = PQgetlength( p_result->pgresult, tuple, field );
         
     | 
| 
       100 
100 
     | 
    
         | 
| 
       101 
101 
     | 
    
         
             
            		if( p_coder->dec_func ){
         
     | 
| 
       102 
     | 
    
         
            -
            			return p_coder->dec_func(p_coder, val, len, tuple, field,  
     | 
| 
      
 102 
     | 
    
         
            +
            			return p_coder->dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
         
     | 
| 
       103 
103 
     | 
    
         
             
            		} else {
         
     | 
| 
       104 
104 
     | 
    
         
             
            			t_pg_coder_dec_func dec_func;
         
     | 
| 
       105 
105 
     | 
    
         
             
            			dec_func = pg_coder_dec_func( p_coder, PQfformat(p_result->pgresult, field) );
         
     | 
| 
       106 
     | 
    
         
            -
            			return dec_func(p_coder, val, len, tuple, field,  
     | 
| 
      
 106 
     | 
    
         
            +
            			return dec_func(p_coder, val, len, tuple, field, p_result->enc_idx);
         
     | 
| 
       107 
107 
     | 
    
         
             
            		}
         
     | 
| 
       108 
108 
     | 
    
         
             
            	}
         
     | 
| 
       109 
109 
     | 
    
         | 
| 
         @@ -292,13 +292,13 @@ init_pg_type_map_by_column() 
     | 
|
| 
       292 
292 
     | 
    
         
             
            	 *
         
     | 
| 
       293 
293 
     | 
    
         
             
            	 * This type map casts values by a coder assigned per field/column.
         
     | 
| 
       294 
294 
     | 
    
         
             
            	 *
         
     | 
| 
       295 
     | 
    
         
            -
            	 * Each PG 
     | 
| 
       296 
     | 
    
         
            -
            	 * that is defined at  
     | 
| 
      
 295 
     | 
    
         
            +
            	 * Each PG::TypeMapByColumn has a fixed list of either encoders or decoders,
         
     | 
| 
      
 296 
     | 
    
         
            +
            	 * that is defined at TypeMapByColumn.new . A type map with encoders is usable for type casting
         
     | 
| 
       297 
297 
     | 
    
         
             
            	 * query bind parameters and COPY data for PG::Connection#put_copy_data .
         
     | 
| 
       298 
298 
     | 
    
         
             
            	 * A type map with decoders is usable for type casting of result values and
         
     | 
| 
       299 
299 
     | 
    
         
             
            	 * COPY data from PG::Connection#get_copy_data .
         
     | 
| 
       300 
300 
     | 
    
         
             
            	 *
         
     | 
| 
       301 
     | 
    
         
            -
            	 * PG:: 
     | 
| 
      
 301 
     | 
    
         
            +
            	 * PG::TypeMapByColumn objects are in particular useful in conjunction with prepared statements,
         
     | 
| 
       302 
302 
     | 
    
         
             
            	 * since they can be cached alongside with the statement handle.
         
     | 
| 
       303 
303 
     | 
    
         
             
            	 *
         
     | 
| 
       304 
304 
     | 
    
         
             
            	 * This type map strategy is also used internally by PG::TypeMapByOid, when the
         
     | 
| 
         @@ -308,5 +308,6 @@ init_pg_type_map_by_column() 
     | 
|
| 
       308 
308 
     | 
    
         
             
            	rb_define_alloc_func( rb_cTypeMapByColumn, pg_tmbc_s_allocate );
         
     | 
| 
       309 
309 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByColumn, "initialize", pg_tmbc_init, 1 );
         
     | 
| 
       310 
310 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByColumn, "coders", pg_tmbc_coders, 0 );
         
     | 
| 
      
 311 
     | 
    
         
            +
            	/* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
         
     | 
| 
       311 
312 
     | 
    
         
             
            	rb_include_module( rb_cTypeMapByColumn, rb_mDefaultTypeMappable );
         
     | 
| 
       312 
313 
     | 
    
         
             
            }
         
     | 
    
        data/ext/pg_type_map_by_oid.c
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
2 
     | 
    
         
             
             * pg_type_map_by_oid.c - PG::TypeMapByOid class extension
         
     | 
| 
       3 
     | 
    
         
            -
             * $Id 
     | 
| 
      
 3 
     | 
    
         
            +
             * $Id$
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             */
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
         @@ -110,7 +110,7 @@ pg_tmbo_result_value(t_typemap *p_typemap, VALUE result, int tuple, int field) 
     | 
|
| 
       110 
110 
     | 
    
         
             
            		char * val = PQgetvalue( p_result->pgresult, tuple, field );
         
     | 
| 
       111 
111 
     | 
    
         
             
            		int len = PQgetlength( p_result->pgresult, tuple, field );
         
     | 
| 
       112 
112 
     | 
    
         
             
            		t_pg_coder_dec_func dec_func = pg_coder_dec_func( p_coder, format );
         
     | 
| 
       113 
     | 
    
         
            -
            		return dec_func( p_coder, val, len, tuple, field,  
     | 
| 
      
 113 
     | 
    
         
            +
            		return dec_func( p_coder, val, len, tuple, field, p_result->enc_idx );
         
     | 
| 
       114 
114 
     | 
    
         
             
            	}
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
116 
     | 
    
         
             
            	default_tm = DATA_PTR( this->typemap.default_typemap );
         
     | 
| 
         @@ -351,5 +351,6 @@ init_pg_type_map_by_oid() 
     | 
|
| 
       351 
351 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByOid, "max_rows_for_online_lookup=", pg_tmbo_max_rows_for_online_lookup_set, 1 );
         
     | 
| 
       352 
352 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByOid, "max_rows_for_online_lookup", pg_tmbo_max_rows_for_online_lookup_get, 0 );
         
     | 
| 
       353 
353 
     | 
    
         
             
            	rb_define_method( rb_cTypeMapByOid, "build_column_map", pg_tmbo_build_column_map, 1 );
         
     | 
| 
      
 354 
     | 
    
         
            +
            	/* rb_mDefaultTypeMappable = rb_define_module_under( rb_cTypeMap, "DefaultTypeMappable"); */
         
     | 
| 
       354 
355 
     | 
    
         
             
            	rb_include_module( rb_cTypeMapByOid, rb_mDefaultTypeMappable );
         
     | 
| 
       355 
356 
     | 
    
         
             
            }
         
     | 
    
        data/ext/pg_type_map_in_ruby.c
    CHANGED
    
    
    
        data/ext/{util.c → pg_util.c}
    RENAMED
    
    | 
         @@ -1,11 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            /*
         
     | 
| 
       2 
     | 
    
         
            -
             *  
     | 
| 
       3 
     | 
    
         
            -
             * $Id 
     | 
| 
      
 2 
     | 
    
         
            +
             * pg_util.c - Utils for ruby-pg
         
     | 
| 
      
 3 
     | 
    
         
            +
             * $Id$
         
     | 
| 
       4 
4 
     | 
    
         
             
             *
         
     | 
| 
       5 
5 
     | 
    
         
             
             */
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            #include "pg.h"
         
     | 
| 
       8 
     | 
    
         
            -
            #include " 
     | 
| 
      
 8 
     | 
    
         
            +
            #include "pg_util.h"
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
       10 
10 
     | 
    
         
             
            static const char base64_encode_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
         @@ -22,12 +22,12 @@ base64_encode( char *out, const char *in, int len) 
     | 
|
| 
       22 
22 
     | 
    
         
             
            	int part_len = len % 3;
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
       24 
24 
     | 
    
         
             
            	if( part_len > 0 ){
         
     | 
| 
       25 
     | 
    
         
            -
            		long byte2 =  
     | 
| 
      
 25 
     | 
    
         
            +
            		long byte2 = 0;
         
     | 
| 
       26 
26 
     | 
    
         
             
            		long byte1 = part_len > 1 ? *--in_ptr : 0;
         
     | 
| 
       27 
27 
     | 
    
         
             
            		long byte0 = *--in_ptr;
         
     | 
| 
       28 
28 
     | 
    
         
             
            		long triple = (byte0 << 16) + (byte1 << 8) + byte2;
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
            		*--out_ptr =  
     | 
| 
      
 30 
     | 
    
         
            +
            		*--out_ptr = '=';
         
     | 
| 
       31 
31 
     | 
    
         
             
            		*--out_ptr = part_len > 1 ? base64_encode_table[(triple >> 1 * 6) & 0x3F] : '=';
         
     | 
| 
       32 
32 
     | 
    
         
             
            		*--out_ptr = base64_encode_table[(triple >> 2 * 6) & 0x3F];
         
     | 
| 
       33 
33 
     | 
    
         
             
            		*--out_ptr = base64_encode_table[(triple >> 3 * 6) & 0x3F];
         
     | 
    
        data/ext/{util.h → pg_util.h}
    RENAMED
    
    | 
         
            File without changes
         
     | 
    
        data/lib/pg.rb
    CHANGED
    
    | 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # -*- ruby -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            begin
         
     | 
| 
       4 
5 
     | 
    
         
             
            	require 'pg_ext'
         
     | 
| 
         @@ -21,7 +22,8 @@ rescue LoadError 
     | 
|
| 
       21 
22 
     | 
    
         
             
            		end
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
            		# Temporary add this directory for DLL search, so that libpq.dll can be found.
         
     | 
| 
       24 
     | 
    
         
            -
            		 
     | 
| 
      
 25 
     | 
    
         
            +
            		# mingw32-platform strings differ (RUBY_PLATFORM=i386-mingw32 vs. x86-mingw32 for rubygems)
         
     | 
| 
      
 26 
     | 
    
         
            +
            		add_dll_path.call(File.join(__dir__, RUBY_PLATFORM.gsub(/^i386-/, "x86-"))) do
         
     | 
| 
       25 
27 
     | 
    
         
             
            			require "#{major_minor}/pg_ext"
         
     | 
| 
       26 
28 
     | 
    
         
             
            		end
         
     | 
| 
       27 
29 
     | 
    
         
             
            	else
         
     | 
| 
         @@ -35,7 +37,7 @@ end 
     | 
|
| 
       35 
37 
     | 
    
         
             
            module PG
         
     | 
| 
       36 
38 
     | 
    
         | 
| 
       37 
39 
     | 
    
         
             
            	# Library version
         
     | 
| 
       38 
     | 
    
         
            -
            	VERSION = '1. 
     | 
| 
      
 40 
     | 
    
         
            +
            	VERSION = '1.2.3'
         
     | 
| 
       39 
41 
     | 
    
         | 
| 
       40 
42 
     | 
    
         
             
            	# VCS revision
         
     | 
| 
       41 
43 
     | 
    
         
             
            	REVISION = %q$Revision: 6f611e78845a $
         
     | 
| 
         @@ -70,5 +72,3 @@ module PG 
     | 
|
| 
       70 
72 
     | 
    
         
             
            	require 'pg/tuple'
         
     | 
| 
       71 
73 
     | 
    
         | 
| 
       72 
74 
     | 
    
         
             
            end # module PG
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # -*- ruby -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            require 'pg' unless defined?( PG )
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
         @@ -117,13 +118,13 @@ module PG::BasicTypeRegistry 
     | 
|
| 
       117 
118 
     | 
    
         
             
            	def build_coder_maps(connection)
         
     | 
| 
       118 
119 
     | 
    
         
             
            		if supports_ranges?(connection)
         
     | 
| 
       119 
120 
     | 
    
         
             
            			result = connection.exec <<-SQL
         
     | 
| 
       120 
     | 
    
         
            -
            				SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput, r.rngsubtype
         
     | 
| 
      
 121 
     | 
    
         
            +
            				SELECT t.oid, t.typname::text, t.typelem, t.typdelim, t.typinput::text, r.rngsubtype
         
     | 
| 
       121 
122 
     | 
    
         
             
            				FROM pg_type as t
         
     | 
| 
       122 
123 
     | 
    
         
             
            				LEFT JOIN pg_range as r ON oid = rngtypid
         
     | 
| 
       123 
124 
     | 
    
         
             
            			SQL
         
     | 
| 
       124 
125 
     | 
    
         
             
            		else
         
     | 
| 
       125 
126 
     | 
    
         
             
            			result = connection.exec <<-SQL
         
     | 
| 
       126 
     | 
    
         
            -
            				SELECT t.oid, t.typname, t.typelem, t.typdelim, t.typinput
         
     | 
| 
      
 127 
     | 
    
         
            +
            				SELECT t.oid, t.typname::text, t.typelem, t.typdelim, t.typinput::text
         
     | 
| 
       127 
128 
     | 
    
         
             
            				FROM pg_type as t
         
     | 
| 
       128 
129 
     | 
    
         
             
            			SQL
         
     | 
| 
       129 
130 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -154,14 +155,26 @@ module PG::BasicTypeRegistry 
     | 
|
| 
       154 
155 
     | 
    
         
             
            	# objects as values.
         
     | 
| 
       155 
156 
     | 
    
         
             
            	CODERS_BY_NAME = []
         
     | 
| 
       156 
157 
     | 
    
         | 
| 
       157 
     | 
    
         
            -
            	 
     | 
| 
       158 
     | 
    
         
            -
             
     | 
| 
       159 
     | 
    
         
            -
            	#  
     | 
| 
      
 158 
     | 
    
         
            +
            	public
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
            	# Register an encoder or decoder instance for casting a PostgreSQL type.
         
     | 
| 
      
 161 
     | 
    
         
            +
            	#
         
     | 
| 
      
 162 
     | 
    
         
            +
            	# Coder#name must correspond to the +typname+ column in the +pg_type+ table.
         
     | 
| 
      
 163 
     | 
    
         
            +
            	# Coder#format can be 0 for text format and 1 for binary.
         
     | 
| 
      
 164 
     | 
    
         
            +
            	def self.register_coder(coder)
         
     | 
| 
      
 165 
     | 
    
         
            +
            		h = CODERS_BY_NAME[coder.format] ||= { encoder: {}, decoder: {} }
         
     | 
| 
      
 166 
     | 
    
         
            +
            		name = coder.name || raise(ArgumentError, "name of #{coder.inspect} must be defined")
         
     | 
| 
      
 167 
     | 
    
         
            +
            		h[:encoder][name] = coder if coder.respond_to?(:encode)
         
     | 
| 
      
 168 
     | 
    
         
            +
            		h[:decoder][name] = coder if coder.respond_to?(:decode)
         
     | 
| 
      
 169 
     | 
    
         
            +
            	end
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            	# Register the given +encoder_class+ and/or +decoder_class+ for casting a PostgreSQL type.
         
     | 
| 
      
 172 
     | 
    
         
            +
            	#
         
     | 
| 
      
 173 
     | 
    
         
            +
            	# +name+ must correspond to the +typname+ column in the +pg_type+ table.
         
     | 
| 
       160 
174 
     | 
    
         
             
            	# +format+ can be 0 for text format and 1 for binary.
         
     | 
| 
       161 
175 
     | 
    
         
             
            	def self.register_type(format, name, encoder_class, decoder_class)
         
     | 
| 
       162 
     | 
    
         
            -
            		 
     | 
| 
       163 
     | 
    
         
            -
            		 
     | 
| 
       164 
     | 
    
         
            -
            		CODERS_BY_NAME[format][:decoder][name] = decoder_class.new(name: name, format: format) if decoder_class
         
     | 
| 
      
 176 
     | 
    
         
            +
            		register_coder(encoder_class.new(name: name, format: format)) if encoder_class
         
     | 
| 
      
 177 
     | 
    
         
            +
            		register_coder(decoder_class.new(name: name, format: format)) if decoder_class
         
     | 
| 
       165 
178 
     | 
    
         
             
            	end
         
     | 
| 
       166 
179 
     | 
    
         | 
| 
       167 
180 
     | 
    
         
             
            	# Alias the +old+ type to the +new+ type.
         
     | 
| 
         @@ -247,7 +260,7 @@ end 
     | 
|
| 
       247 
260 
     | 
    
         
             
            # Simple set of rules for type casting common PostgreSQL types to Ruby.
         
     | 
| 
       248 
261 
     | 
    
         
             
            #
         
     | 
| 
       249 
262 
     | 
    
         
             
            # OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
         
     | 
| 
       250 
     | 
    
         
            -
            # PostgreSQL's pg_type table in PG::BasicTypeMapForResults.new .
         
     | 
| 
      
 263 
     | 
    
         
            +
            # PostgreSQL's +pg_type+ table in PG::BasicTypeMapForResults.new .
         
     | 
| 
       251 
264 
     | 
    
         
             
            #
         
     | 
| 
       252 
265 
     | 
    
         
             
            # Result values are type casted based on the type OID of the given result column.
         
     | 
| 
       253 
266 
     | 
    
         
             
            #
         
     | 
| 
         @@ -264,7 +277,7 @@ end 
     | 
|
| 
       264 
277 
     | 
    
         
             
            #   # is done by PG::TextDecoder::Integer internally for all value retrieval methods.
         
     | 
| 
       265 
278 
     | 
    
         
             
            #   res.values  # => [[5]]
         
     | 
| 
       266 
279 
     | 
    
         
             
            #
         
     | 
| 
       267 
     | 
    
         
            -
            # PG::TypeMapByOid# 
     | 
| 
      
 280 
     | 
    
         
            +
            # PG::TypeMapByOid#build_column_map(result) can be used to generate
         
     | 
| 
       268 
281 
     | 
    
         
             
            # a result independent PG::TypeMapByColumn type map, which can subsequently be used
         
     | 
| 
       269 
282 
     | 
    
         
             
            # to cast #get_copy_data fields:
         
     | 
| 
       270 
283 
     | 
    
         
             
            #
         
     | 
| 
         @@ -301,7 +314,7 @@ class PG::BasicTypeMapForResults < PG::TypeMapByOid 
     | 
|
| 
       301 
314 
     | 
    
         
             
            			format = result.fformat(field)
         
     | 
| 
       302 
315 
     | 
    
         
             
            			oid = result.ftype(field)
         
     | 
| 
       303 
316 
     | 
    
         
             
            			unless @already_warned[format][oid]
         
     | 
| 
       304 
     | 
    
         
            -
            				 
     | 
| 
      
 317 
     | 
    
         
            +
            				$stderr.puts "Warning: no type cast defined for type #{@typenames_by_oid[format][oid].inspect} with oid #{oid}. Please cast this type explicitly to TEXT to be safe for future changes."
         
     | 
| 
       305 
318 
     | 
    
         
             
            				 @already_warned[format][oid] = true
         
     | 
| 
       306 
319 
     | 
    
         
             
            			end
         
     | 
| 
       307 
320 
     | 
    
         
             
            			super
         
     | 
| 
         @@ -325,7 +338,7 @@ end 
     | 
|
| 
       325 
338 
     | 
    
         
             
            # to PostgreSQL.
         
     | 
| 
       326 
339 
     | 
    
         
             
            #
         
     | 
| 
       327 
340 
     | 
    
         
             
            # OIDs of supported type casts are not hard-coded in the sources, but are retrieved from the
         
     | 
| 
       328 
     | 
    
         
            -
            # PostgreSQL's pg_type table in PG::BasicTypeMapBasedOnResult.new .
         
     | 
| 
      
 341 
     | 
    
         
            +
            # PostgreSQL's +pg_type+ table in PG::BasicTypeMapBasedOnResult.new .
         
     | 
| 
       329 
342 
     | 
    
         
             
            #
         
     | 
| 
       330 
343 
     | 
    
         
             
            # This class works equal to PG::BasicTypeMapForResults, but does not define decoders for
         
     | 
| 
       331 
344 
     | 
    
         
             
            # the given result OIDs, but encoders. So it can be used to type cast field values based on
         
     | 
| 
         @@ -380,21 +393,54 @@ end 
     | 
|
| 
       380 
393 
     | 
    
         
             
            #   # Assign a default ruleset for type casts of input and output values.
         
     | 
| 
       381 
394 
     | 
    
         
             
            #   conn.type_map_for_queries = PG::BasicTypeMapForQueries.new(conn)
         
     | 
| 
       382 
395 
     | 
    
         
             
            #   # Execute a query. The Integer param value is typecasted internally by PG::BinaryEncoder::Int8.
         
     | 
| 
       383 
     | 
    
         
            -
            #   # The format of the parameter is set to  
     | 
| 
      
 396 
     | 
    
         
            +
            #   # The format of the parameter is set to 0 (text) and the OID of this parameter is set to 20 (int8).
         
     | 
| 
       384 
397 
     | 
    
         
             
            #   res = conn.exec_params( "SELECT $1", [5] )
         
     | 
| 
       385 
398 
     | 
    
         
             
            class PG::BasicTypeMapForQueries < PG::TypeMapByClass
         
     | 
| 
       386 
399 
     | 
    
         
             
            	include PG::BasicTypeRegistry
         
     | 
| 
       387 
400 
     | 
    
         | 
| 
       388 
401 
     | 
    
         
             
            	def initialize(connection)
         
     | 
| 
       389 
402 
     | 
    
         
             
            		@coder_maps = build_coder_maps(connection)
         
     | 
| 
       390 
     | 
    
         
            -
             
     | 
| 
       391 
     | 
    
         
            -
            		populate_encoder_list
         
     | 
| 
       392 
403 
     | 
    
         
             
            		@array_encoders_by_klass = array_encoders_by_klass
         
     | 
| 
       393 
     | 
    
         
            -
            		@ 
     | 
| 
      
 404 
     | 
    
         
            +
            		@encode_array_as = :array
         
     | 
| 
      
 405 
     | 
    
         
            +
            		init_encoders
         
     | 
| 
      
 406 
     | 
    
         
            +
            	end
         
     | 
| 
      
 407 
     | 
    
         
            +
             
     | 
| 
      
 408 
     | 
    
         
            +
            	# Change the mechanism that is used to encode ruby array values
         
     | 
| 
      
 409 
     | 
    
         
            +
            	#
         
     | 
| 
      
 410 
     | 
    
         
            +
            	# Possible values:
         
     | 
| 
      
 411 
     | 
    
         
            +
            	# * +:array+ : Encode the ruby array as a PostgreSQL array.
         
     | 
| 
      
 412 
     | 
    
         
            +
            	#   The array element type is inferred from the class of the first array element. This is the default.
         
     | 
| 
      
 413 
     | 
    
         
            +
            	# * +:json+ : Encode the ruby array as a JSON document.
         
     | 
| 
      
 414 
     | 
    
         
            +
            	# * +:record+ : Encode the ruby array as a composite type row.
         
     | 
| 
      
 415 
     | 
    
         
            +
            	# * <code>"_type"</code> : Encode the ruby array as a particular PostgreSQL type.
         
     | 
| 
      
 416 
     | 
    
         
            +
            	#   All PostgreSQL array types are supported.
         
     | 
| 
      
 417 
     | 
    
         
            +
            	#   If there's an encoder registered for the elements +type+, it will be used.
         
     | 
| 
      
 418 
     | 
    
         
            +
            	#   Otherwise a string conversion (by +value.to_s+) is done.
         
     | 
| 
      
 419 
     | 
    
         
            +
            	def encode_array_as=(pg_type)
         
     | 
| 
      
 420 
     | 
    
         
            +
            		case pg_type
         
     | 
| 
      
 421 
     | 
    
         
            +
            			when :array
         
     | 
| 
      
 422 
     | 
    
         
            +
            			when :json
         
     | 
| 
      
 423 
     | 
    
         
            +
            			when :record
         
     | 
| 
      
 424 
     | 
    
         
            +
            			when /\A_/
         
     | 
| 
      
 425 
     | 
    
         
            +
            			else
         
     | 
| 
      
 426 
     | 
    
         
            +
            				raise ArgumentError, "invalid pg_type #{pg_type.inspect}"
         
     | 
| 
      
 427 
     | 
    
         
            +
            		end
         
     | 
| 
      
 428 
     | 
    
         
            +
             
     | 
| 
      
 429 
     | 
    
         
            +
            		@encode_array_as = pg_type
         
     | 
| 
      
 430 
     | 
    
         
            +
             
     | 
| 
      
 431 
     | 
    
         
            +
            		init_encoders
         
     | 
| 
       394 
432 
     | 
    
         
             
            	end
         
     | 
| 
       395 
433 
     | 
    
         | 
| 
      
 434 
     | 
    
         
            +
            	attr_reader :encode_array_as
         
     | 
| 
      
 435 
     | 
    
         
            +
             
     | 
| 
       396 
436 
     | 
    
         
             
            	private
         
     | 
| 
       397 
437 
     | 
    
         | 
| 
      
 438 
     | 
    
         
            +
            	def init_encoders
         
     | 
| 
      
 439 
     | 
    
         
            +
            		coders.each { |kl, c| self[kl] = nil } # Clear type map
         
     | 
| 
      
 440 
     | 
    
         
            +
            		populate_encoder_list
         
     | 
| 
      
 441 
     | 
    
         
            +
            		@textarray_encoder = coder_by_name(0, :encoder, '_text')
         
     | 
| 
      
 442 
     | 
    
         
            +
            	end
         
     | 
| 
      
 443 
     | 
    
         
            +
             
     | 
| 
       398 
444 
     | 
    
         
             
            	def coder_by_name(format, direction, name)
         
     | 
| 
       399 
445 
     | 
    
         
             
            		check_format_and_direction(format, direction)
         
     | 
| 
       400 
446 
     | 
    
         
             
            		@coder_maps[format][direction].coder_by_name(name)
         
     | 
| 
         @@ -412,7 +458,19 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass 
     | 
|
| 
       412 
458 
     | 
    
         
             
            				end
         
     | 
| 
       413 
459 
     | 
    
         
             
            				self[klass] = coder
         
     | 
| 
       414 
460 
     | 
    
         
             
            			else
         
     | 
| 
       415 
     | 
    
         
            -
             
     | 
| 
      
 461 
     | 
    
         
            +
             
     | 
| 
      
 462 
     | 
    
         
            +
            				case @encode_array_as
         
     | 
| 
      
 463 
     | 
    
         
            +
            					when :array
         
     | 
| 
      
 464 
     | 
    
         
            +
            						self[klass] = selector
         
     | 
| 
      
 465 
     | 
    
         
            +
            					when :json
         
     | 
| 
      
 466 
     | 
    
         
            +
            						self[klass] = PG::TextEncoder::JSON.new
         
     | 
| 
      
 467 
     | 
    
         
            +
            					when :record
         
     | 
| 
      
 468 
     | 
    
         
            +
            						self[klass] = PG::TextEncoder::Record.new type_map: self
         
     | 
| 
      
 469 
     | 
    
         
            +
            					when /\A_/
         
     | 
| 
      
 470 
     | 
    
         
            +
            						self[klass] = coder_by_name(0, :encoder, @encode_array_as) || raise(ArgumentError, "unknown array type #{@encode_array_as.inspect}")
         
     | 
| 
      
 471 
     | 
    
         
            +
            					else
         
     | 
| 
      
 472 
     | 
    
         
            +
            						raise ArgumentError, "invalid pg_type #{@encode_array_as.inspect}"
         
     | 
| 
      
 473 
     | 
    
         
            +
            				end
         
     | 
| 
       416 
474 
     | 
    
         
             
            			end
         
     | 
| 
       417 
475 
     | 
    
         
             
            		end
         
     | 
| 
       418 
476 
     | 
    
         
             
            	end
         
     | 
| 
         @@ -431,7 +489,7 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass 
     | 
|
| 
       431 
489 
     | 
    
         
             
            		end
         
     | 
| 
       432 
490 
     | 
    
         
             
            		@array_encoders_by_klass[elem.class] ||
         
     | 
| 
       433 
491 
     | 
    
         
             
            				elem.class.ancestors.lazy.map{|ancestor| @array_encoders_by_klass[ancestor] }.find{|a| a } ||
         
     | 
| 
       434 
     | 
    
         
            -
            				@ 
     | 
| 
      
 492 
     | 
    
         
            +
            				@textarray_encoder
         
     | 
| 
       435 
493 
     | 
    
         
             
            	end
         
     | 
| 
       436 
494 
     | 
    
         | 
| 
       437 
495 
     | 
    
         
             
            	DEFAULT_TYPE_MAP = {
         
     | 
| 
         @@ -442,9 +500,11 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass 
     | 
|
| 
       442 
500 
     | 
    
         
             
            		Integer => [0, 'int8'],
         
     | 
| 
       443 
501 
     | 
    
         
             
            		Float => [0, 'float8'],
         
     | 
| 
       444 
502 
     | 
    
         
             
            		BigDecimal => [0, 'numeric'],
         
     | 
| 
      
 503 
     | 
    
         
            +
            		Time => [0, 'timestamptz'],
         
     | 
| 
       445 
504 
     | 
    
         
             
            		# We use text format and no type OID for IPAddr, because setting the OID can lead
         
     | 
| 
       446 
505 
     | 
    
         
             
            		# to unnecessary inet/cidr conversions on the server side.
         
     | 
| 
       447 
506 
     | 
    
         
             
            		IPAddr => [0, 'inet'],
         
     | 
| 
      
 507 
     | 
    
         
            +
            		Hash => [0, 'json'],
         
     | 
| 
       448 
508 
     | 
    
         
             
            		Array => :get_array_type,
         
     | 
| 
       449 
509 
     | 
    
         
             
            	}
         
     | 
| 
       450 
510 
     | 
    
         | 
| 
         @@ -454,6 +514,9 @@ class PG::BasicTypeMapForQueries < PG::TypeMapByClass 
     | 
|
| 
       454 
514 
     | 
    
         
             
            		Integer => [0, '_int8'],
         
     | 
| 
       455 
515 
     | 
    
         
             
            		String => [0, '_text'],
         
     | 
| 
       456 
516 
     | 
    
         
             
            		Float => [0, '_float8'],
         
     | 
| 
      
 517 
     | 
    
         
            +
            		BigDecimal => [0, '_numeric'],
         
     | 
| 
      
 518 
     | 
    
         
            +
            		Time => [0, '_timestamptz'],
         
     | 
| 
      
 519 
     | 
    
         
            +
            		IPAddr => [0, '_inet'],
         
     | 
| 
       457 
520 
     | 
    
         
             
            	}
         
     | 
| 
       458 
521 
     | 
    
         | 
| 
       459 
522 
     | 
    
         
             
            end
         
     | 
    
        data/lib/pg/binary_decoder.rb
    CHANGED
    
    
    
        data/lib/pg/coder.rb
    CHANGED
    
    | 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # -*- ruby -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module PG
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
         @@ -28,6 +29,7 @@ module PG 
     | 
|
| 
       28 
29 
     | 
    
         
             
            			{
         
     | 
| 
       29 
30 
     | 
    
         
             
            				oid: oid,
         
     | 
| 
       30 
31 
     | 
    
         
             
            				format: format,
         
     | 
| 
      
 32 
     | 
    
         
            +
            				flags: flags,
         
     | 
| 
       31 
33 
     | 
    
         
             
            				name: name,
         
     | 
| 
       32 
34 
     | 
    
         
             
            			}
         
     | 
| 
       33 
35 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -52,6 +54,18 @@ module PG 
     | 
|
| 
       52 
54 
     | 
    
         
             
            			str[-1,0] = "#{name_str} #{oid_str}#{format_str}"
         
     | 
| 
       53 
55 
     | 
    
         
             
            			str
         
     | 
| 
       54 
56 
     | 
    
         
             
            		end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            		def inspect_short
         
     | 
| 
      
 59 
     | 
    
         
            +
            			str = case format
         
     | 
| 
      
 60 
     | 
    
         
            +
            				when 0 then "T"
         
     | 
| 
      
 61 
     | 
    
         
            +
            				when 1 then "B"
         
     | 
| 
      
 62 
     | 
    
         
            +
            				else format.to_s
         
     | 
| 
      
 63 
     | 
    
         
            +
            			end
         
     | 
| 
      
 64 
     | 
    
         
            +
            			str += "E" if respond_to?(:encode)
         
     | 
| 
      
 65 
     | 
    
         
            +
            			str += "D" if respond_to?(:decode)
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
            			"#{name || self.class.name}:#{str}"
         
     | 
| 
      
 68 
     | 
    
         
            +
            		end
         
     | 
| 
       55 
69 
     | 
    
         
             
            	end
         
     | 
| 
       56 
70 
     | 
    
         | 
| 
       57 
71 
     | 
    
         
             
            	class CompositeCoder < Coder
         
     | 
| 
         @@ -79,5 +93,12 @@ module PG 
     | 
|
| 
       79 
93 
     | 
    
         
             
            			})
         
     | 
| 
       80 
94 
     | 
    
         
             
            		end
         
     | 
| 
       81 
95 
     | 
    
         
             
            	end
         
     | 
| 
       82 
     | 
    
         
            -
            end # module PG
         
     | 
| 
       83 
96 
     | 
    
         | 
| 
      
 97 
     | 
    
         
            +
            	class RecordCoder < Coder
         
     | 
| 
      
 98 
     | 
    
         
            +
            		def to_h
         
     | 
| 
      
 99 
     | 
    
         
            +
            			super.merge!({
         
     | 
| 
      
 100 
     | 
    
         
            +
            				type_map: type_map,
         
     | 
| 
      
 101 
     | 
    
         
            +
            			})
         
     | 
| 
      
 102 
     | 
    
         
            +
            		end
         
     | 
| 
      
 103 
     | 
    
         
            +
            	end
         
     | 
| 
      
 104 
     | 
    
         
            +
            end # module PG
         
     |