class PG::Tuple - pg-1.1.4 Documentation

# class PG::Tuple

The class to represent one query result tuple (row). An instance of this class can be created by PG::Result#tuple .

All field values of the tuple are retrieved on demand from the underlying PGresult object and converted to a Ruby object. Subsequent access to the same field returns the same object, since they are cached when materialized. Each PG::Tuple holds a reference to the related PG::Result object, but gets detached, when all fields are materialized.

Example:

    require 'pg'
    conn = PG.connect(:dbname => 'test')
    res  = conn.exec('VALUES(1,2), (3,4)')
    t0 = res.tuple(0)  # => #<PG::Tuple column1: "1", column2: "2">
    t1 = res.tuple(1)  # => #<PG::Tuple column1: "3", column2: "4">
    t1[0]  # => "3"
    t1["column2"]  # => "4"

### Public Instance Methods

res[ name ] → value click to toggle source

Returns field name.

    static VALUE
    pg_tuple_aref(VALUE self, VALUE key)
    {
            VALUE index;
            int field_num;
            t_pg_tuple *this = pg_tuple_get_this(self);

            switch(rb_type(key)){
                    case T_FIXNUM:
                    case T_BIGNUM:
                            field_num = NUM2INT(key);
                            if ( field_num < 0 )
                                    field_num = this->num_fields + field_num;
                            if ( field_num < 0 || field_num >= this->num_fields )
                                    return Qnil;
                            break;
                    default:
                            index = rb_hash_aref(this->field_map, key);
                            if( index == Qnil ) return Qnil;
                            field_num = NUM2INT(index);
            }

            return pg_tuple_materialize_field(this, field_num);
    }

each{ |key, value| ... } click to toggle source

Invokes block for each field name and value in the tuple.

    static VALUE
    pg_tuple_each(VALUE self)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);
            VALUE field_names;

            RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);

            field_names = pg_tuple_get_field_names(this);

            if( field_names == Qfalse ){
                    rb_hash_foreach(this->field_map, pg_tuple_yield_key_value, (VALUE)this);
            } else {
                    int i;
                    for( i = 0; i < this->num_fields; i++ ){
                            VALUE value = pg_tuple_materialize_field(this, i);
                            rb_yield_values(2, RARRAY_AREF(field_names, i), value);
                    }
            }

            pg_tuple_detach(this);
            return self;
    }

each_key(&block) click to toggle source

    # File lib/pg/tuple.rb, line 22
    def each_key(&block)
            if fn=field_names
                    fn.each(&block)
            else
                    field_map.each_key(&block)
            end
    end

each_value{ |value| ... } click to toggle source

Invokes block for each field value in the tuple.

    static VALUE
    pg_tuple_each_value(VALUE self)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);
            int field_num;

            RETURN_SIZED_ENUMERATOR(self, 0, NULL, pg_tuple_num_fields_for_enum);

            for(field_num = 0; field_num < this->num_fields; field_num++) {
                    VALUE value = pg_tuple_materialize_field(this, field_num);
                    rb_yield(value);
            }

            pg_tuple_detach(this);
            return self;
    }

fetch(key) → value click to toggle source
fetch(key, default) → value
fetch(key) { |key| block } → value

Returns a field value by either column index or column name.

An integer `key` is interpreted as column index. Negative values of index count from the end of the array.

A string `key` is interpreted as column name.

If the key can't be found, there are several options: With no other arguments, it will raise a IndexError exception; if default is given, then that will be returned; if the optional code block is specified, then that will be run and its result returned.

    static VALUE
    pg_tuple_fetch(int argc, VALUE *argv, VALUE self)
    {
            VALUE key;
            long block_given;
            VALUE index;
            int field_num;
            t_pg_tuple *this = pg_tuple_get_this(self);

            rb_check_arity(argc, 1, 2);
            key = argv[0];

            block_given = rb_block_given_p();
            if (block_given && argc == 2) {
                    rb_warn("block supersedes default value argument");
            }

            switch(rb_type(key)){
                    case T_FIXNUM:
                    case T_BIGNUM:
                            field_num = NUM2INT(key);
                            if ( field_num < 0 )
                                    field_num = this->num_fields + field_num;
                            if ( field_num < 0 || field_num >= this->num_fields ){
                                    if (block_given) return rb_yield(key);
                                    if (argc == 1) rb_raise( rb_eIndexError, "Index %d is out of range", field_num );
                                    return argv[1];
                            }
                            break;
                    default:
                            index = rb_hash_aref(this->field_map, key);

                            if (index == Qnil) {
                                    if (block_given) return rb_yield(key);
                                    if (argc == 1) rb_raise( rb_eKeyError, "column not found" );
                                    return argv[1];
                            }

                            field_num = NUM2INT(index);
            }

            return pg_tuple_materialize_field(this, field_num);
    }

has_key?(key) click to toggle source

    # File lib/pg/tuple.rb, line 13
    def has_key?(key)
            field_map.has_key?(key)
    end

Also aliased as: key?
index(key) → integer click to toggle source

Returns the field number which matches the given column name.

    static VALUE
    pg_tuple_index(VALUE self, VALUE key)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);
            return rb_hash_aref(this->field_map, key);
    }

inspect() click to toggle source

Return a String representation of the object suitable for debugging.

    # File lib/pg/tuple.rb, line 9
    def inspect
            "#<#{self.class} #{self.map{|k,v| "#{k}: #{v.inspect}" }.join(", ") }>"
    end

key?(key)
Alias for: has_key?
keys() click to toggle source

    # File lib/pg/tuple.rb, line 18
    def keys
            field_names || field_map.keys.freeze
    end

length → integer click to toggle source

Returns number of fields of this tuple.

    static VALUE
    pg_tuple_length(VALUE self)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);
            return INT2NUM(this->num_fields);
    }

Also aliased as: size
size()
Alias for: length
values → Array click to toggle source

Returns the values of this tuple as Array. +res.tuple(i).values+ is equal to +res.tuple_values(i)+ .

    static VALUE
    pg_tuple_values(VALUE self)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);

            pg_tuple_materialize(this);
            return rb_ary_new4(this->num_fields, &this->values[0]);
    }

### Private Instance Methods

field_map() click to toggle source

    static VALUE
    pg_tuple_field_map(VALUE self)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);
            return this->field_map;
    }

field_names() click to toggle source

    static VALUE
    pg_tuple_field_names(VALUE self)
    {
            t_pg_tuple *this = pg_tuple_get_this(self);
            return pg_tuple_get_field_names(this);
    }

marshal_dump() click to toggle source

    static VALUE
    pg_tuple_dump(VALUE self)
    {
            VALUE field_names;
            VALUE values;
            VALUE a;
            t_pg_tuple *this = pg_tuple_get_this(self);

            pg_tuple_materialize(this);

            field_names = pg_tuple_get_field_names(this);
            if( field_names == Qfalse )
                    field_names = rb_funcall(this->field_map, rb_intern("keys"), 0);

            values = rb_ary_new4(this->num_fields, &this->values[0]);
            a = rb_ary_new3(2, field_names, values);

            if (FL_TEST(self, FL_EXIVAR)) {
                    rb_copy_generic_ivar(a, self);
                    FL_SET(a, FL_EXIVAR);
            }

            return a;
    }

marshal_load(p1) click to toggle source

    static VALUE
    pg_tuple_load(VALUE self, VALUE a)
    {
            int num_fields;
            int i;
            t_pg_tuple *this;
            VALUE values;
            VALUE field_names;
            VALUE field_map;
            int dup_names;

            rb_check_frozen(self);
            rb_check_trusted(self);

            TypedData_Get_Struct(self, t_pg_tuple, &pg_tuple_type, this);
            if (this)
                    rb_raise(rb_eTypeError, "tuple is not empty");

            Check_Type(a, T_ARRAY);
            if (RARRAY_LEN(a) != 2)
                    rb_raise(rb_eTypeError, "expected an array of 2 elements");

            field_names = RARRAY_AREF(a, 0);
            Check_Type(field_names, T_ARRAY);
            rb_obj_freeze(field_names);
            values = RARRAY_AREF(a, 1);
            Check_Type(values, T_ARRAY);
            num_fields = RARRAY_LEN(values);

            if (RARRAY_LEN(field_names) != num_fields)
                    rb_raise(rb_eTypeError, "different number of fields and values");

            field_map = rb_hash_new();
            for( i = 0; i < num_fields; i++ ){
                    rb_hash_aset(field_map, RARRAY_AREF(field_names, i), INT2FIX(i));
            }
            rb_obj_freeze(field_map);

            dup_names = num_fields != (int)RHASH_SIZE(field_map);

            this = (t_pg_tuple *)xmalloc(
                    sizeof(*this) +
                    sizeof(*this->values) * num_fields +
                    sizeof(*this->values) * (dup_names ? 1 : 0));
            RTYPEDDATA_DATA(self) = this;

            this->result = Qnil;
            this->typemap = Qnil;
            this->row_num = -1;
            this->num_fields = num_fields;
            this->field_map = field_map;

            for( i = 0; i < num_fields; i++ ){
                    VALUE v = RARRAY_AREF(values, i);
                    if( v == Qundef )
                            rb_raise(rb_eTypeError, "field %d is not materialized", i);
                    this->values[i] = v;
            }

            if( dup_names ){
                    this->values[num_fields] = field_names;
            }

            if (FL_TEST(a, FL_EXIVAR)) {
                    rb_copy_generic_ivar(self, a);
                    FL_SET(self, FL_EXIVAR);
            }

            return self;
    }