pg 1.1.3 → 1.2.0
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 +70 -0
- data/Manifest.txt +3 -2
- data/README-Windows.rdoc +4 -4
- data/README.ja.rdoc +1 -2
- data/README.rdoc +43 -8
- data/Rakefile +4 -4
- data/Rakefile.cross +7 -4
- data/ext/errorcodes.def +68 -0
- data/ext/errorcodes.txt +19 -2
- data/ext/extconf.rb +6 -6
- data/ext/pg.c +132 -95
- data/ext/pg.h +24 -17
- data/ext/pg_binary_decoder.c +20 -16
- data/ext/pg_binary_encoder.c +13 -12
- data/ext/pg_coder.c +5 -5
- data/ext/pg_connection.c +395 -301
- data/ext/pg_copy_coder.c +5 -3
- data/ext/pg_record_coder.c +490 -0
- data/ext/pg_result.c +272 -124
- 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 +4 -3
- 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 +2 -3
- data/lib/pg/basic_type_mapping.rb +79 -16
- 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 +17 -16
- data/spec/pg/basic_type_mapping_spec.rb +151 -14
- data/spec/pg/connection_spec.rb +117 -55
- data/spec/pg/result_spec.rb +193 -3
- data/spec/pg/tuple_spec.rb +55 -2
- data/spec/pg/type_map_by_column_spec.rb +5 -1
- data/spec/pg/type_spec.rb +180 -6
- metadata +40 -45
- metadata.gz.sig +0 -0
    
        data/ext/pg_result.c
    CHANGED
    
    | @@ -1,20 +1,27 @@ | |
| 1 1 | 
             
            /*
         | 
| 2 2 | 
             
             * pg_result.c - PG::Result class extension
         | 
| 3 | 
            -
             * $Id | 
| 3 | 
            +
             * $Id$
         | 
| 4 4 | 
             
             *
         | 
| 5 5 | 
             
             */
         | 
| 6 6 |  | 
| 7 7 | 
             
            #include "pg.h"
         | 
| 8 8 |  | 
| 9 | 
            -
             | 
| 10 9 | 
             
            VALUE rb_cPGresult;
         | 
| 10 | 
            +
            static VALUE sym_symbol, sym_string, sym_static_symbol;
         | 
| 11 11 |  | 
| 12 | 
            -
            static void pgresult_gc_free( t_pg_result * );
         | 
| 13 12 | 
             
            static VALUE pgresult_type_map_set( VALUE, VALUE );
         | 
| 14 | 
            -
            static VALUE pgresult_s_allocate( VALUE );
         | 
| 15 13 | 
             
            static t_pg_result *pgresult_get_this( VALUE );
         | 
| 16 14 | 
             
            static t_pg_result *pgresult_get_this_safe( VALUE );
         | 
| 17 15 |  | 
| 16 | 
            +
            #if defined(HAVE_PQRESULTMEMORYSIZE)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            static ssize_t
         | 
| 19 | 
            +
            pgresult_approx_size(const PGresult *result)
         | 
| 20 | 
            +
            {
         | 
| 21 | 
            +
            	return PQresultMemorySize(result);
         | 
| 22 | 
            +
            }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            #else
         | 
| 18 25 |  | 
| 19 26 | 
             
            #define PGRESULT_DATA_BLOCKSIZE 2048
         | 
| 20 27 | 
             
            typedef struct pgresAttValue
         | 
| @@ -44,7 +51,7 @@ count_leading_zero_bits(unsigned int x) | |
| 44 51 | 
             
            }
         | 
| 45 52 |  | 
| 46 53 | 
             
            static ssize_t
         | 
| 47 | 
            -
            pgresult_approx_size(PGresult *result)
         | 
| 54 | 
            +
            pgresult_approx_size(const PGresult *result)
         | 
| 48 55 | 
             
            {
         | 
| 49 56 | 
             
            	int num_fields = PQnfields(result);
         | 
| 50 57 | 
             
            	ssize_t size = 0;
         | 
| @@ -94,7 +101,29 @@ pgresult_approx_size(PGresult *result) | |
| 94 101 |  | 
| 95 102 | 
             
            	return size;
         | 
| 96 103 | 
             
            }
         | 
| 104 | 
            +
            #endif
         | 
| 97 105 |  | 
| 106 | 
            +
            /*
         | 
| 107 | 
            +
             * GC Mark function
         | 
| 108 | 
            +
             */
         | 
| 109 | 
            +
            static void
         | 
| 110 | 
            +
            pgresult_gc_mark( t_pg_result *this )
         | 
| 111 | 
            +
            {
         | 
| 112 | 
            +
            	int i;
         | 
| 113 | 
            +
             | 
| 114 | 
            +
            	rb_gc_mark( this->connection );
         | 
| 115 | 
            +
            	rb_gc_mark( this->typemap );
         | 
| 116 | 
            +
            	rb_gc_mark( this->tuple_hash );
         | 
| 117 | 
            +
            	rb_gc_mark( this->field_map );
         | 
| 118 | 
            +
             | 
| 119 | 
            +
            	for( i=0; i < this->nfields; i++ ){
         | 
| 120 | 
            +
            		rb_gc_mark( this->fnames[i] );
         | 
| 121 | 
            +
            	}
         | 
| 122 | 
            +
            }
         | 
| 123 | 
            +
             | 
| 124 | 
            +
            /*
         | 
| 125 | 
            +
             * GC Free function
         | 
| 126 | 
            +
             */
         | 
| 98 127 | 
             
            static void
         | 
| 99 128 | 
             
            pgresult_clear( t_pg_result *this )
         | 
| 100 129 | 
             
            {
         | 
| @@ -104,15 +133,41 @@ pgresult_clear( t_pg_result *this ) | |
| 104 133 | 
             
            		rb_gc_adjust_memory_usage(-this->result_size);
         | 
| 105 134 | 
             
            #endif
         | 
| 106 135 | 
             
            	}
         | 
| 136 | 
            +
            	this->result_size = 0;
         | 
| 137 | 
            +
            	this->nfields = -1;
         | 
| 107 138 | 
             
            	this->pgresult = NULL;
         | 
| 108 139 | 
             
            }
         | 
| 109 140 |  | 
| 141 | 
            +
            static void
         | 
| 142 | 
            +
            pgresult_gc_free( t_pg_result *this )
         | 
| 143 | 
            +
            {
         | 
| 144 | 
            +
            	pgresult_clear( this );
         | 
| 145 | 
            +
            	xfree(this);
         | 
| 146 | 
            +
            }
         | 
| 147 | 
            +
             | 
| 110 148 | 
             
            static size_t
         | 
| 111 149 | 
             
            pgresult_memsize( t_pg_result *this )
         | 
| 112 150 | 
             
            {
         | 
| 151 | 
            +
            	/* Ideally the memory 'this' is pointing to should be taken into account as well.
         | 
| 152 | 
            +
            	 * However we don't want to store two memory sizes in t_pg_result just for reporting by ObjectSpace.memsize_of.
         | 
| 153 | 
            +
            	 */
         | 
| 113 154 | 
             
            	return this->result_size;
         | 
| 114 155 | 
             
            }
         | 
| 115 156 |  | 
| 157 | 
            +
            static const rb_data_type_t pgresult_type = {
         | 
| 158 | 
            +
            	"pg",
         | 
| 159 | 
            +
            	{
         | 
| 160 | 
            +
            		(void (*)(void*))pgresult_gc_mark,
         | 
| 161 | 
            +
            		(void (*)(void*))pgresult_gc_free,
         | 
| 162 | 
            +
            		(size_t (*)(const void *))pgresult_memsize,
         | 
| 163 | 
            +
            	},
         | 
| 164 | 
            +
            	0, 0,
         | 
| 165 | 
            +
            #ifdef RUBY_TYPED_FREE_IMMEDIATELY
         | 
| 166 | 
            +
            	RUBY_TYPED_FREE_IMMEDIATELY,
         | 
| 167 | 
            +
            #endif
         | 
| 168 | 
            +
            };
         | 
| 169 | 
            +
             | 
| 170 | 
            +
             | 
| 116 171 | 
             
            /*
         | 
| 117 172 | 
             
             * Global functions
         | 
| 118 173 | 
             
             */
         | 
| @@ -124,12 +179,10 @@ static VALUE | |
| 124 179 | 
             
            pg_new_result2(PGresult *result, VALUE rb_pgconn)
         | 
| 125 180 | 
             
            {
         | 
| 126 181 | 
             
            	int nfields = result ? PQnfields(result) : 0;
         | 
| 127 | 
            -
            	VALUE self | 
| 182 | 
            +
            	VALUE self;
         | 
| 128 183 | 
             
            	t_pg_result *this;
         | 
| 129 184 |  | 
| 130 185 | 
             
            	this = (t_pg_result *)xmalloc(sizeof(*this) +  sizeof(*this->fnames) * nfields);
         | 
| 131 | 
            -
            	RTYPEDDATA_DATA(self) = this;
         | 
| 132 | 
            -
             | 
| 133 186 | 
             
            	this->pgresult = result;
         | 
| 134 187 | 
             
            	this->connection = rb_pgconn;
         | 
| 135 188 | 
             
            	this->typemap = pg_typemap_all_strings;
         | 
| @@ -137,18 +190,21 @@ pg_new_result2(PGresult *result, VALUE rb_pgconn) | |
| 137 190 | 
             
            	this->nfields = -1;
         | 
| 138 191 | 
             
            	this->tuple_hash = Qnil;
         | 
| 139 192 | 
             
            	this->field_map = Qnil;
         | 
| 140 | 
            -
             | 
| 141 | 
            -
            	 | 
| 193 | 
            +
            	this->flags = 0;
         | 
| 194 | 
            +
            	self = TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, this);
         | 
| 142 195 |  | 
| 143 196 | 
             
            	if( result ){
         | 
| 144 197 | 
             
            		t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
         | 
| 145 198 | 
             
            		VALUE typemap = p_conn->type_map_for_results;
         | 
| 146 | 
            -
             | 
| 147 199 | 
             
            		/* Type check is done when assigned to PG::Connection. */
         | 
| 148 200 | 
             
            		t_typemap *p_typemap = DATA_PTR(typemap);
         | 
| 149 201 |  | 
| 202 | 
            +
            		this->enc_idx = p_conn->enc_idx;
         | 
| 150 203 | 
             
            		this->typemap = p_typemap->funcs.fit_to_result( typemap, self );
         | 
| 151 204 | 
             
            		this->p_typemap = DATA_PTR( this->typemap );
         | 
| 205 | 
            +
            		this->flags = p_conn->flags;
         | 
| 206 | 
            +
            	} else {
         | 
| 207 | 
            +
            		this->enc_idx = rb_locale_encindex();
         | 
| 152 208 | 
             
            	}
         | 
| 153 209 |  | 
| 154 210 | 
             
            	return self;
         | 
| @@ -159,22 +215,38 @@ pg_new_result(PGresult *result, VALUE rb_pgconn) | |
| 159 215 | 
             
            {
         | 
| 160 216 | 
             
            	VALUE self = pg_new_result2(result, rb_pgconn);
         | 
| 161 217 | 
             
            	t_pg_result *this = pgresult_get_this(self);
         | 
| 162 | 
            -
            	t_pg_connection *p_conn = pg_get_connection(rb_pgconn);
         | 
| 163 218 |  | 
| 164 219 | 
             
            	this->autoclear = 0;
         | 
| 165 220 |  | 
| 166 | 
            -
            	 | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 221 | 
            +
            	/* Estimate size of underlying pgresult memory storage and account to ruby GC.
         | 
| 222 | 
            +
            	 * There's no need to adjust the GC for xmalloc'ed memory, but libpq is using libc malloc() ruby doesn't know about.
         | 
| 223 | 
            +
            	 */
         | 
| 224 | 
            +
            	/* TODO: If someday most systems provide PQresultMemorySize(), it's questionable to store result_size in t_pg_result in addition to the value already stored in PGresult.
         | 
| 225 | 
            +
            	 * For now the memory savings don't justify the ifdefs necessary to support both cases.
         | 
| 226 | 
            +
            	 */
         | 
| 227 | 
            +
            	this->result_size = pgresult_approx_size(result);
         | 
| 169 228 |  | 
| 170 229 | 
             
            #ifdef HAVE_RB_GC_ADJUST_MEMORY_USAGE
         | 
| 171 | 
            -
             | 
| 230 | 
            +
            	rb_gc_adjust_memory_usage(this->result_size);
         | 
| 172 231 | 
             
            #endif
         | 
| 173 | 
            -
            	}
         | 
| 174 232 |  | 
| 175 233 | 
             
            	return self;
         | 
| 176 234 | 
             
            }
         | 
| 177 235 |  | 
| 236 | 
            +
            static VALUE
         | 
| 237 | 
            +
            pg_copy_result(t_pg_result *this)
         | 
| 238 | 
            +
            {
         | 
| 239 | 
            +
            	int nfields = this->nfields == -1 ? (this->pgresult ? PQnfields(this->pgresult) : 0) : this->nfields;
         | 
| 240 | 
            +
            	size_t len = sizeof(*this) +  sizeof(*this->fnames) * nfields;
         | 
| 241 | 
            +
            	t_pg_result *copy;
         | 
| 242 | 
            +
             | 
| 243 | 
            +
            	copy = (t_pg_result *)xmalloc(len);
         | 
| 244 | 
            +
            	memcpy(copy, this, len);
         | 
| 245 | 
            +
            	this->result_size = 0;
         | 
| 246 | 
            +
             | 
| 247 | 
            +
            	return TypedData_Wrap_Struct(rb_cPGresult, &pgresult_type, copy);
         | 
| 248 | 
            +
            }
         | 
| 249 | 
            +
             | 
| 178 250 | 
             
            VALUE
         | 
| 179 251 | 
             
            pg_new_result_autoclear(PGresult *result, VALUE rb_pgconn)
         | 
| 180 252 | 
             
            {
         | 
| @@ -229,7 +301,7 @@ pg_result_check( VALUE self ) | |
| 229 301 | 
             
            		}
         | 
| 230 302 | 
             
            	}
         | 
| 231 303 |  | 
| 232 | 
            -
            	PG_ENCODING_SET_NOCHECK( error,  | 
| 304 | 
            +
            	PG_ENCODING_SET_NOCHECK( error, this->enc_idx );
         | 
| 233 305 |  | 
| 234 306 | 
             
            	sqlstate = PQresultErrorField( this->pgresult, PG_DIAG_SQLSTATE );
         | 
| 235 307 | 
             
            	klass = lookup_error_class( sqlstate );
         | 
| @@ -305,37 +377,6 @@ pgresult_autoclear_p( VALUE self ) | |
| 305 377 | 
             
             * DATA pointer functions
         | 
| 306 378 | 
             
             */
         | 
| 307 379 |  | 
| 308 | 
            -
            /*
         | 
| 309 | 
            -
             * GC Mark function
         | 
| 310 | 
            -
             */
         | 
| 311 | 
            -
            static void
         | 
| 312 | 
            -
            pgresult_gc_mark( t_pg_result *this )
         | 
| 313 | 
            -
            {
         | 
| 314 | 
            -
            	int i;
         | 
| 315 | 
            -
             | 
| 316 | 
            -
            	if( !this ) return;
         | 
| 317 | 
            -
            	rb_gc_mark( this->connection );
         | 
| 318 | 
            -
            	rb_gc_mark( this->typemap );
         | 
| 319 | 
            -
            	rb_gc_mark( this->tuple_hash );
         | 
| 320 | 
            -
            	rb_gc_mark( this->field_map );
         | 
| 321 | 
            -
             | 
| 322 | 
            -
            	for( i=0; i < this->nfields; i++ ){
         | 
| 323 | 
            -
            		rb_gc_mark( this->fnames[i] );
         | 
| 324 | 
            -
            	}
         | 
| 325 | 
            -
            }
         | 
| 326 | 
            -
             | 
| 327 | 
            -
            /*
         | 
| 328 | 
            -
             * GC Free function
         | 
| 329 | 
            -
             */
         | 
| 330 | 
            -
            static void
         | 
| 331 | 
            -
            pgresult_gc_free( t_pg_result *this )
         | 
| 332 | 
            -
            {
         | 
| 333 | 
            -
            	if( !this ) return;
         | 
| 334 | 
            -
            	pgresult_clear( this );
         | 
| 335 | 
            -
             | 
| 336 | 
            -
            	xfree(this);
         | 
| 337 | 
            -
            }
         | 
| 338 | 
            -
             | 
| 339 380 | 
             
            /*
         | 
| 340 381 | 
             
             * Fetch the PG::Result object data pointer and check it's
         | 
| 341 382 | 
             
             * PGresult data pointer for sanity.
         | 
| @@ -365,32 +406,30 @@ pgresult_get(VALUE self) | |
| 365 406 | 
             
            	return this->pgresult;
         | 
| 366 407 | 
             
            }
         | 
| 367 408 |  | 
| 368 | 
            -
             | 
| 369 | 
            -
            static const rb_data_type_t pgresult_type = {
         | 
| 370 | 
            -
            	"pg",
         | 
| 371 | 
            -
            	{
         | 
| 372 | 
            -
            		(void (*)(void*))pgresult_gc_mark,
         | 
| 373 | 
            -
            		(void (*)(void*))pgresult_gc_free,
         | 
| 374 | 
            -
            		(size_t (*)(const void *))pgresult_memsize,
         | 
| 375 | 
            -
            	},
         | 
| 376 | 
            -
            	0, 0,
         | 
| 377 | 
            -
            #ifdef RUBY_TYPED_FREE_IMMEDIATELY
         | 
| 378 | 
            -
            	RUBY_TYPED_FREE_IMMEDIATELY,
         | 
| 379 | 
            -
            #endif
         | 
| 380 | 
            -
            };
         | 
| 381 | 
            -
             | 
| 382 | 
            -
            /*
         | 
| 383 | 
            -
             * Document-method: allocate
         | 
| 384 | 
            -
             *
         | 
| 385 | 
            -
             * call-seq:
         | 
| 386 | 
            -
             *   PG::Result.allocate -> result
         | 
| 387 | 
            -
             */
         | 
| 388 | 
            -
            static VALUE
         | 
| 389 | 
            -
            pgresult_s_allocate( VALUE klass )
         | 
| 409 | 
            +
            static VALUE pg_cstr_to_sym(char *cstr, unsigned int flags, int enc_idx)
         | 
| 390 410 | 
             
            {
         | 
| 391 | 
            -
            	VALUE  | 
| 392 | 
            -
             | 
| 393 | 
            -
            	 | 
| 411 | 
            +
            	VALUE fname;
         | 
| 412 | 
            +
            #ifdef TRUFFLERUBY
         | 
| 413 | 
            +
            	if( flags & (PG_RESULT_FIELD_NAMES_SYMBOL | PG_RESULT_FIELD_NAMES_STATIC_SYMBOL) ){
         | 
| 414 | 
            +
            #else
         | 
| 415 | 
            +
            	if( flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
         | 
| 416 | 
            +
            		rb_encoding *enc = rb_enc_from_index(enc_idx);
         | 
| 417 | 
            +
            		fname = rb_check_symbol_cstr(cstr, strlen(cstr), enc);
         | 
| 418 | 
            +
            		if( fname == Qnil ){
         | 
| 419 | 
            +
            			fname = rb_str_new2(cstr);
         | 
| 420 | 
            +
            			PG_ENCODING_SET_NOCHECK(fname, enc_idx);
         | 
| 421 | 
            +
            			fname = rb_str_intern(fname);
         | 
| 422 | 
            +
            		}
         | 
| 423 | 
            +
            	} else if( flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
         | 
| 424 | 
            +
            #endif
         | 
| 425 | 
            +
            		rb_encoding *enc = rb_enc_from_index(enc_idx);
         | 
| 426 | 
            +
            		fname = ID2SYM(rb_intern3(cstr, strlen(cstr), enc));
         | 
| 427 | 
            +
            	} else {
         | 
| 428 | 
            +
            		fname = rb_str_new2(cstr);
         | 
| 429 | 
            +
            		PG_ENCODING_SET_NOCHECK(fname, enc_idx);
         | 
| 430 | 
            +
            		fname = rb_obj_freeze(fname);
         | 
| 431 | 
            +
            	}
         | 
| 432 | 
            +
            	return fname;
         | 
| 394 433 | 
             
            }
         | 
| 395 434 |  | 
| 396 435 | 
             
            static void pgresult_init_fnames(VALUE self)
         | 
| @@ -402,12 +441,9 @@ static void pgresult_init_fnames(VALUE self) | |
| 402 441 | 
             
            		int nfields = PQnfields(this->pgresult);
         | 
| 403 442 |  | 
| 404 443 | 
             
            		for( i=0; i<nfields; i++ ){
         | 
| 405 | 
            -
            			 | 
| 406 | 
            -
            			 | 
| 407 | 
            -
            			this->fnames[i] = rb_obj_freeze(fname);
         | 
| 444 | 
            +
            			char *cfname = PQfname(this->pgresult, i);
         | 
| 445 | 
            +
            			this->fnames[i] = pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
         | 
| 408 446 | 
             
            			this->nfields = i + 1;
         | 
| 409 | 
            -
             | 
| 410 | 
            -
            			RB_GC_GUARD(fname);
         | 
| 411 447 | 
             
            		}
         | 
| 412 448 | 
             
            		this->nfields = nfields;
         | 
| 413 449 | 
             
            	}
         | 
| @@ -419,6 +455,8 @@ static void pgresult_init_fnames(VALUE self) | |
| 419 455 | 
             
             *
         | 
| 420 456 | 
             
             * The class to represent the query result tuples (rows).
         | 
| 421 457 | 
             
             * An instance of this class is created as the result of every query.
         | 
| 458 | 
            +
             * All result rows and columns are stored in a memory block attached to the PG::Result object.
         | 
| 459 | 
            +
             * Whenever a value is accessed it is casted to a Ruby object by the assigned #type_map .
         | 
| 422 460 | 
             
             *
         | 
| 423 461 | 
             
             * Since pg-1.1 the amount of memory in use by a PG::Result object is estimated and passed to ruby's garbage collector.
         | 
| 424 462 | 
             
             * You can invoke the #clear method to force deallocation of memory of the instance when finished with the result for better memory performance.
         | 
| @@ -468,8 +506,9 @@ pgresult_result_status(VALUE self) | |
| 468 506 | 
             
            static VALUE
         | 
| 469 507 | 
             
            pgresult_res_status(VALUE self, VALUE status)
         | 
| 470 508 | 
             
            {
         | 
| 471 | 
            -
            	 | 
| 472 | 
            -
            	 | 
| 509 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 510 | 
            +
            	VALUE ret = rb_str_new2(PQresStatus(NUM2INT(status)));
         | 
| 511 | 
            +
            	PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
         | 
| 473 512 | 
             
            	return ret;
         | 
| 474 513 | 
             
            }
         | 
| 475 514 |  | 
| @@ -482,10 +521,39 @@ pgresult_res_status(VALUE self, VALUE status) | |
| 482 521 | 
             
            static VALUE
         | 
| 483 522 | 
             
            pgresult_error_message(VALUE self)
         | 
| 484 523 | 
             
            {
         | 
| 485 | 
            -
            	 | 
| 486 | 
            -
            	 | 
| 524 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 525 | 
            +
            	VALUE ret = rb_str_new2(PQresultErrorMessage(this->pgresult));
         | 
| 526 | 
            +
            	PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
         | 
| 527 | 
            +
            	return ret;
         | 
| 528 | 
            +
            }
         | 
| 529 | 
            +
             | 
| 530 | 
            +
            #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
         | 
| 531 | 
            +
            /*
         | 
| 532 | 
            +
             * call-seq:
         | 
| 533 | 
            +
             *    res.verbose_error_message( verbosity, show_context ) -> String
         | 
| 534 | 
            +
             *
         | 
| 535 | 
            +
             * Returns a reformatted version of the error message associated with a PGresult object.
         | 
| 536 | 
            +
             *
         | 
| 537 | 
            +
             * Available since PostgreSQL-9.6
         | 
| 538 | 
            +
             */
         | 
| 539 | 
            +
            static VALUE
         | 
| 540 | 
            +
            pgresult_verbose_error_message(VALUE self, VALUE verbosity, VALUE show_context)
         | 
| 541 | 
            +
            {
         | 
| 542 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 543 | 
            +
            	VALUE ret;
         | 
| 544 | 
            +
            	char *c_str;
         | 
| 545 | 
            +
             | 
| 546 | 
            +
            	c_str = PQresultVerboseErrorMessage(this->pgresult, NUM2INT(verbosity), NUM2INT(show_context));
         | 
| 547 | 
            +
            	if(!c_str)
         | 
| 548 | 
            +
            		rb_raise(rb_eNoMemError, "insufficient memory to format error message");
         | 
| 549 | 
            +
             | 
| 550 | 
            +
            	ret = rb_str_new2(c_str);
         | 
| 551 | 
            +
            	PQfreemem(c_str);
         | 
| 552 | 
            +
            	PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
         | 
| 553 | 
            +
             | 
| 487 554 | 
             
            	return ret;
         | 
| 488 555 | 
             
            }
         | 
| 556 | 
            +
            #endif
         | 
| 489 557 |  | 
| 490 558 | 
             
            /*
         | 
| 491 559 | 
             
             * call-seq:
         | 
| @@ -536,14 +604,14 @@ pgresult_error_message(VALUE self) | |
| 536 604 | 
             
            static VALUE
         | 
| 537 605 | 
             
            pgresult_error_field(VALUE self, VALUE field)
         | 
| 538 606 | 
             
            {
         | 
| 539 | 
            -
            	 | 
| 607 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 540 608 | 
             
            	int fieldcode = NUM2INT( field );
         | 
| 541 | 
            -
            	char * fieldstr = PQresultErrorField(  | 
| 609 | 
            +
            	char * fieldstr = PQresultErrorField( this->pgresult, fieldcode );
         | 
| 542 610 | 
             
            	VALUE ret = Qnil;
         | 
| 543 611 |  | 
| 544 612 | 
             
            	if ( fieldstr ) {
         | 
| 545 | 
            -
            		ret =  | 
| 546 | 
            -
            		PG_ENCODING_SET_NOCHECK( ret,  | 
| 613 | 
            +
            		ret = rb_str_new2( fieldstr );
         | 
| 614 | 
            +
            		PG_ENCODING_SET_NOCHECK( ret, this->enc_idx );
         | 
| 547 615 | 
             
            	}
         | 
| 548 616 |  | 
| 549 617 | 
             
            	return ret;
         | 
| @@ -581,24 +649,25 @@ pgresult_nfields(VALUE self) | |
| 581 649 |  | 
| 582 650 | 
             
            /*
         | 
| 583 651 | 
             
             * call-seq:
         | 
| 584 | 
            -
             *    res.fname( index ) -> String
         | 
| 652 | 
            +
             *    res.fname( index ) -> String or Symbol
         | 
| 585 653 | 
             
             *
         | 
| 586 654 | 
             
             * Returns the name of the column corresponding to _index_.
         | 
| 655 | 
            +
             * Depending on #field_name_type= it's a String or Symbol.
         | 
| 656 | 
            +
             *
         | 
| 587 657 | 
             
             */
         | 
| 588 658 | 
             
            static VALUE
         | 
| 589 659 | 
             
            pgresult_fname(VALUE self, VALUE index)
         | 
| 590 660 | 
             
            {
         | 
| 591 | 
            -
            	 | 
| 592 | 
            -
            	PGresult *result = pgresult_get(self);
         | 
| 661 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 593 662 | 
             
            	int i = NUM2INT(index);
         | 
| 663 | 
            +
            	char *cfname;
         | 
| 594 664 |  | 
| 595 | 
            -
            	if (i < 0 || i >= PQnfields( | 
| 665 | 
            +
            	if (i < 0 || i >= PQnfields(this->pgresult)) {
         | 
| 596 666 | 
             
            		rb_raise(rb_eArgError,"invalid field number %d", i);
         | 
| 597 667 | 
             
            	}
         | 
| 598 668 |  | 
| 599 | 
            -
            	 | 
| 600 | 
            -
            	 | 
| 601 | 
            -
            	return rb_obj_freeze(fname);
         | 
| 669 | 
            +
            	cfname = PQfname(this->pgresult, i);
         | 
| 670 | 
            +
            	return pg_cstr_to_sym(cfname, this->flags, this->enc_idx);
         | 
| 602 671 | 
             
            }
         | 
| 603 672 |  | 
| 604 673 | 
             
            /*
         | 
| @@ -897,8 +966,9 @@ pgresult_paramtype(VALUE self, VALUE param_number) | |
| 897 966 | 
             
            static VALUE
         | 
| 898 967 | 
             
            pgresult_cmd_status(VALUE self)
         | 
| 899 968 | 
             
            {
         | 
| 900 | 
            -
            	 | 
| 901 | 
            -
            	 | 
| 969 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 970 | 
            +
            	VALUE ret = rb_str_new2(PQcmdStatus(this->pgresult));
         | 
| 971 | 
            +
            	PG_ENCODING_SET_NOCHECK(ret, this->enc_idx);
         | 
| 902 972 | 
             
            	return ret;
         | 
| 903 973 | 
             
            }
         | 
| 904 974 |  | 
| @@ -1098,8 +1168,12 @@ static VALUE | |
| 1098 1168 | 
             
            pgresult_field_values( VALUE self, VALUE field )
         | 
| 1099 1169 | 
             
            {
         | 
| 1100 1170 | 
             
            	PGresult *result = pgresult_get( self );
         | 
| 1101 | 
            -
            	const char *fieldname | 
| 1102 | 
            -
            	int fnum | 
| 1171 | 
            +
            	const char *fieldname;
         | 
| 1172 | 
            +
            	int fnum;
         | 
| 1173 | 
            +
             | 
| 1174 | 
            +
            	if( RB_TYPE_P(field, T_SYMBOL) ) field = rb_sym_to_s( field );
         | 
| 1175 | 
            +
            	fieldname = StringValueCStr( field );
         | 
| 1176 | 
            +
            	fnum = PQfnumber( result, fieldname );
         | 
| 1103 1177 |  | 
| 1104 1178 | 
             
            	if ( fnum < 0 )
         | 
| 1105 1179 | 
             
            		rb_raise( rb_eIndexError, "no such field '%s' in result", fieldname );
         | 
| @@ -1142,6 +1216,25 @@ pgresult_tuple_values(VALUE self, VALUE index) | |
| 1142 1216 | 
             
            	}
         | 
| 1143 1217 | 
             
            }
         | 
| 1144 1218 |  | 
| 1219 | 
            +
            static void ensure_init_for_tuple(VALUE self)
         | 
| 1220 | 
            +
            {
         | 
| 1221 | 
            +
            	t_pg_result *this = pgresult_get_this_safe(self);
         | 
| 1222 | 
            +
             | 
| 1223 | 
            +
            	if( this->field_map == Qnil ){
         | 
| 1224 | 
            +
            		int i;
         | 
| 1225 | 
            +
            		VALUE field_map = rb_hash_new();
         | 
| 1226 | 
            +
             | 
| 1227 | 
            +
            		if( this->nfields == -1 )
         | 
| 1228 | 
            +
            			pgresult_init_fnames( self );
         | 
| 1229 | 
            +
             | 
| 1230 | 
            +
            		for( i = 0; i < this->nfields; i++ ){
         | 
| 1231 | 
            +
            			rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
         | 
| 1232 | 
            +
            		}
         | 
| 1233 | 
            +
            		rb_obj_freeze(field_map);
         | 
| 1234 | 
            +
            		this->field_map = field_map;
         | 
| 1235 | 
            +
            	}
         | 
| 1236 | 
            +
            }
         | 
| 1237 | 
            +
             | 
| 1145 1238 | 
             
            /*
         | 
| 1146 1239 | 
             
             *  call-seq:
         | 
| 1147 1240 | 
             
             *     res.tuple( n )   -> PG::Tuple
         | 
| @@ -1162,19 +1255,7 @@ pgresult_tuple(VALUE self, VALUE index) | |
| 1162 1255 | 
             
            	if ( tuple_num < 0 || tuple_num >= num_tuples )
         | 
| 1163 1256 | 
             
            		rb_raise( rb_eIndexError, "Index %d is out of range", tuple_num );
         | 
| 1164 1257 |  | 
| 1165 | 
            -
            	 | 
| 1166 | 
            -
            		int i;
         | 
| 1167 | 
            -
            		VALUE field_map = rb_hash_new();
         | 
| 1168 | 
            -
             | 
| 1169 | 
            -
            		if( this->nfields == -1 )
         | 
| 1170 | 
            -
            			pgresult_init_fnames( self );
         | 
| 1171 | 
            -
             | 
| 1172 | 
            -
            		for( i = 0; i < this->nfields; i++ ){
         | 
| 1173 | 
            -
            			rb_hash_aset(field_map, this->fnames[i], INT2FIX(i));
         | 
| 1174 | 
            -
            		}
         | 
| 1175 | 
            -
            		rb_obj_freeze(field_map);
         | 
| 1176 | 
            -
            		this->field_map = field_map;
         | 
| 1177 | 
            -
            	}
         | 
| 1258 | 
            +
            	ensure_init_for_tuple(self);
         | 
| 1178 1259 |  | 
| 1179 1260 | 
             
              return pg_tuple_new(self, tuple_num);
         | 
| 1180 1261 | 
             
            }
         | 
| @@ -1206,7 +1287,7 @@ pgresult_each(VALUE self) | |
| 1206 1287 | 
             
             * call-seq:
         | 
| 1207 1288 | 
             
             *    res.fields() -> Array
         | 
| 1208 1289 | 
             
             *
         | 
| 1209 | 
            -
             *  | 
| 1290 | 
            +
             * Depending on #field_name_type= returns an array of strings or symbols representing the names of the fields in the result.
         | 
| 1210 1291 | 
             
             */
         | 
| 1211 1292 | 
             
            static VALUE
         | 
| 1212 1293 | 
             
            pgresult_fields(VALUE self)
         | 
| @@ -1305,11 +1386,17 @@ yield_tuple(VALUE self, int ntuples, int nfields) | |
| 1305 1386 | 
             
            {
         | 
| 1306 1387 | 
             
            	int tuple_num;
         | 
| 1307 1388 | 
             
            	t_pg_result *this = pgresult_get_this(self);
         | 
| 1308 | 
            -
            	VALUE  | 
| 1389 | 
            +
            	VALUE copy;
         | 
| 1309 1390 | 
             
            	UNUSED(nfields);
         | 
| 1310 1391 |  | 
| 1392 | 
            +
            	/* make a copy of the base result, that is bound to the PG::Tuple */
         | 
| 1393 | 
            +
            	copy = pg_copy_result(this);
         | 
| 1394 | 
            +
            	/* The copy is now owner of the PGresult and is responsible to PQclear it.
         | 
| 1395 | 
            +
            	 * We clear the pgresult here, so that it's not double freed on error within yield. */
         | 
| 1396 | 
            +
            	this->pgresult = NULL;
         | 
| 1397 | 
            +
             | 
| 1311 1398 | 
             
            	for(tuple_num = 0; tuple_num < ntuples; tuple_num++) {
         | 
| 1312 | 
            -
            		VALUE tuple = pgresult_tuple( | 
| 1399 | 
            +
            		VALUE tuple = pgresult_tuple(copy, INT2FIX(tuple_num));
         | 
| 1313 1400 | 
             
            		rb_yield( tuple );
         | 
| 1314 1401 | 
             
            	}
         | 
| 1315 1402 | 
             
            }
         | 
| @@ -1390,8 +1477,6 @@ pgresult_stream_any(VALUE self, void (*yielder)(VALUE, int, int)) | |
| 1390 1477 | 
             
             *     # do something with each received row of the second query
         | 
| 1391 1478 | 
             
             *   end
         | 
| 1392 1479 | 
             
             *   conn.get_result  # => nil   (no more results)
         | 
| 1393 | 
            -
             *
         | 
| 1394 | 
            -
             * Available since PostgreSQL-9.2
         | 
| 1395 1480 | 
             
             */
         | 
| 1396 1481 | 
             
            static VALUE
         | 
| 1397 1482 | 
             
            pgresult_stream_each(VALUE self)
         | 
| @@ -1408,8 +1493,6 @@ pgresult_stream_each(VALUE self) | |
| 1408 1493 | 
             
             *
         | 
| 1409 1494 | 
             
             * This method works equally to #stream_each , but yields an Array of
         | 
| 1410 1495 | 
             
             * values.
         | 
| 1411 | 
            -
             *
         | 
| 1412 | 
            -
             * Available since PostgreSQL-9.2
         | 
| 1413 1496 | 
             
             */
         | 
| 1414 1497 | 
             
            static VALUE
         | 
| 1415 1498 | 
             
            pgresult_stream_each_row(VALUE self)
         | 
| @@ -1424,21 +1507,81 @@ pgresult_stream_each_row(VALUE self) | |
| 1424 1507 | 
             
             * Yields each row of the result set in single row mode.
         | 
| 1425 1508 | 
             
             *
         | 
| 1426 1509 | 
             
             * This method works equally to #stream_each , but yields a PG::Tuple object.
         | 
| 1427 | 
            -
             *
         | 
| 1428 | 
            -
             * Available since PostgreSQL-9.2
         | 
| 1429 1510 | 
             
             */
         | 
| 1430 1511 | 
             
            static VALUE
         | 
| 1431 1512 | 
             
            pgresult_stream_each_tuple(VALUE self)
         | 
| 1432 1513 | 
             
            {
         | 
| 1514 | 
            +
            	/* allocate VALUEs that are shared between all streamed tuples */
         | 
| 1515 | 
            +
            	ensure_init_for_tuple(self);
         | 
| 1516 | 
            +
             | 
| 1433 1517 | 
             
            	return pgresult_stream_any(self, yield_tuple);
         | 
| 1434 1518 | 
             
            }
         | 
| 1435 1519 |  | 
| 1520 | 
            +
            /*
         | 
| 1521 | 
            +
             * call-seq:
         | 
| 1522 | 
            +
             *    res.field_name_type = Symbol
         | 
| 1523 | 
            +
             *
         | 
| 1524 | 
            +
             * Set type of field names specific to this result.
         | 
| 1525 | 
            +
             * It can be set to one of:
         | 
| 1526 | 
            +
             * * +:string+ to use String based field names
         | 
| 1527 | 
            +
             * * +:symbol+ to use Symbol based field names
         | 
| 1528 | 
            +
             * * +:static_symbol+ to use pinned Symbol (can not be garbage collected) - Don't use this, it will probably removed in future.
         | 
| 1529 | 
            +
             *
         | 
| 1530 | 
            +
             * The default is retrieved from PG::Connection#field_name_type , which defaults to +:string+ .
         | 
| 1531 | 
            +
             *
         | 
| 1532 | 
            +
             * This setting affects several result methods:
         | 
| 1533 | 
            +
             * * keys of Hash returned by #[] , #each and #stream_each
         | 
| 1534 | 
            +
             * * #fields
         | 
| 1535 | 
            +
             * * #fname
         | 
| 1536 | 
            +
             * * field names used by #tuple and #stream_each_tuple
         | 
| 1537 | 
            +
             *
         | 
| 1538 | 
            +
             * The type of field names can only be changed before any of the affected methods have been called.
         | 
| 1539 | 
            +
             *
         | 
| 1540 | 
            +
             */
         | 
| 1541 | 
            +
            static VALUE
         | 
| 1542 | 
            +
            pgresult_field_name_type_set(VALUE self, VALUE sym)
         | 
| 1543 | 
            +
            {
         | 
| 1544 | 
            +
            	t_pg_result *this = pgresult_get_this(self);
         | 
| 1545 | 
            +
            	if( this->nfields != -1 ) rb_raise(rb_eArgError, "field names are already materialized");
         | 
| 1546 | 
            +
             | 
| 1547 | 
            +
            	this->flags &= ~PG_RESULT_FIELD_NAMES_MASK;
         | 
| 1548 | 
            +
            	if( sym == sym_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_SYMBOL;
         | 
| 1549 | 
            +
            	else if ( sym == sym_static_symbol ) this->flags |= PG_RESULT_FIELD_NAMES_STATIC_SYMBOL;
         | 
| 1550 | 
            +
            	else if ( sym == sym_string );
         | 
| 1551 | 
            +
            	else rb_raise(rb_eArgError, "invalid argument %+"PRIsVALUE, sym);
         | 
| 1552 | 
            +
             | 
| 1553 | 
            +
            	return sym;
         | 
| 1554 | 
            +
            }
         | 
| 1555 | 
            +
             | 
| 1556 | 
            +
            /*
         | 
| 1557 | 
            +
             * call-seq:
         | 
| 1558 | 
            +
             *    res.field_name_type -> Symbol
         | 
| 1559 | 
            +
             *
         | 
| 1560 | 
            +
             * Get type of field names.
         | 
| 1561 | 
            +
             *
         | 
| 1562 | 
            +
             * See description at #field_name_type=
         | 
| 1563 | 
            +
             */
         | 
| 1564 | 
            +
            static VALUE
         | 
| 1565 | 
            +
            pgresult_field_name_type_get(VALUE self)
         | 
| 1566 | 
            +
            {
         | 
| 1567 | 
            +
            	t_pg_result *this = pgresult_get_this(self);
         | 
| 1568 | 
            +
            	if( this->flags & PG_RESULT_FIELD_NAMES_SYMBOL ){
         | 
| 1569 | 
            +
            		return sym_symbol;
         | 
| 1570 | 
            +
            	} else if( this->flags & PG_RESULT_FIELD_NAMES_STATIC_SYMBOL ){
         | 
| 1571 | 
            +
            		return sym_static_symbol;
         | 
| 1572 | 
            +
            	} else {
         | 
| 1573 | 
            +
            		return sym_string;
         | 
| 1574 | 
            +
            	}
         | 
| 1575 | 
            +
            }
         | 
| 1436 1576 |  | 
| 1437 1577 | 
             
            void
         | 
| 1438 1578 | 
             
            init_pg_result()
         | 
| 1439 1579 | 
             
            {
         | 
| 1440 | 
            -
            	 | 
| 1441 | 
            -
            	 | 
| 1580 | 
            +
            	sym_string = ID2SYM(rb_intern("string"));
         | 
| 1581 | 
            +
            	sym_symbol = ID2SYM(rb_intern("symbol"));
         | 
| 1582 | 
            +
            	sym_static_symbol = ID2SYM(rb_intern("static_symbol"));
         | 
| 1583 | 
            +
             | 
| 1584 | 
            +
            	rb_cPGresult = rb_define_class_under( rb_mPG, "Result", rb_cData );
         | 
| 1442 1585 | 
             
            	rb_include_module(rb_cPGresult, rb_mEnumerable);
         | 
| 1443 1586 | 
             
            	rb_include_module(rb_cPGresult, rb_mPGconstants);
         | 
| 1444 1587 |  | 
| @@ -1447,6 +1590,10 @@ init_pg_result() | |
| 1447 1590 | 
             
            	rb_define_method(rb_cPGresult, "res_status", pgresult_res_status, 1);
         | 
| 1448 1591 | 
             
            	rb_define_method(rb_cPGresult, "error_message", pgresult_error_message, 0);
         | 
| 1449 1592 | 
             
            	rb_define_alias( rb_cPGresult, "result_error_message", "error_message");
         | 
| 1593 | 
            +
            #ifdef HAVE_PQRESULTVERBOSEERRORMESSAGE
         | 
| 1594 | 
            +
            	rb_define_method(rb_cPGresult, "verbose_error_message", pgresult_verbose_error_message, 2);
         | 
| 1595 | 
            +
            	rb_define_alias( rb_cPGresult, "result_verbose_error_message", "verbose_error_message");
         | 
| 1596 | 
            +
            #endif
         | 
| 1450 1597 | 
             
            	rb_define_method(rb_cPGresult, "error_field", pgresult_error_field, 1);
         | 
| 1451 1598 | 
             
            	rb_define_alias( rb_cPGresult, "result_error_field", "error_field" );
         | 
| 1452 1599 | 
             
            	rb_define_method(rb_cPGresult, "clear", pg_result_clear, 0);
         | 
| @@ -1494,6 +1641,7 @@ init_pg_result() | |
| 1494 1641 | 
             
            	rb_define_method(rb_cPGresult, "stream_each", pgresult_stream_each, 0);
         | 
| 1495 1642 | 
             
            	rb_define_method(rb_cPGresult, "stream_each_row", pgresult_stream_each_row, 0);
         | 
| 1496 1643 | 
             
            	rb_define_method(rb_cPGresult, "stream_each_tuple", pgresult_stream_each_tuple, 0);
         | 
| 1497 | 
            -
            }
         | 
| 1498 | 
            -
             | 
| 1499 1644 |  | 
| 1645 | 
            +
            	rb_define_method(rb_cPGresult, "field_name_type=", pgresult_field_name_type_set, 1 );
         | 
| 1646 | 
            +
            	rb_define_method(rb_cPGresult, "field_name_type", pgresult_field_name_type_get, 0 );
         | 
| 1647 | 
            +
            }
         |