vertica 1.0.0.rc1 → 1.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +4 -0
- data/README.md +97 -62
- data/lib/vertica.rb +3 -2
- data/lib/vertica/column.rb +50 -84
- data/lib/vertica/connection.rb +173 -18
- data/lib/vertica/data_type.rb +146 -0
- data/lib/vertica/error.rb +1 -0
- data/lib/vertica/protocol/backend/command_complete.rb +2 -11
- data/lib/vertica/protocol/backend/row_description.rb +1 -1
- data/lib/vertica/query.rb +36 -18
- data/lib/vertica/result.rb +69 -5
- data/lib/vertica/row.rb +57 -6
- data/lib/vertica/row_description.rb +56 -3
- data/lib/vertica/version.rb +3 -1
- data/test/functional/functional_connection_test.rb +2 -2
- data/test/functional/functional_query_test.rb +14 -11
- data/test/functional/functional_type_deserialization_test.rb +179 -0
- data/test/unit/backend_message_test.rb +3 -5
- data/test/unit/column_test.rb +21 -31
- data/test/unit/data_type_test.rb +72 -0
- data/test/unit/result_test.rb +2 -2
- data/test/unit/row_description_test.rb +31 -2
- data/test/unit/row_test.rb +26 -2
- metadata +8 -4
- data/test/functional/functional_value_conversion_test.rb +0 -117
@@ -0,0 +1,146 @@
|
|
1
|
+
# Class that represents a data type of a column.
|
2
|
+
#
|
3
|
+
# This gem is only able to handle registered types. Types are registered using {.register}.
|
4
|
+
# If an unregistered type is encountered, the library will raise {Vertica::Error::UnknownTypeError}.
|
5
|
+
#
|
6
|
+
# @example Handling an unknown OID:
|
7
|
+
# Vertica::DataType.register 12345, 'fancy_type', lambda { |bytes| ... }
|
8
|
+
#
|
9
|
+
# @attr_reader oid [Integer] The object ID of the type.
|
10
|
+
# @attr_reader name [String] The name of the type as it can be used in SQL.
|
11
|
+
# @attr_reader size [Integer] The size of the type.
|
12
|
+
# @attr_reader modifier [Integer] A modifier of the type.
|
13
|
+
# @attr_reader format [Integer] The serialization format of this type.
|
14
|
+
# @attr_reader deserializer [Proc] Proc that can deserialize values of this type coming from the database.
|
15
|
+
#
|
16
|
+
# @see Vertica::Column
|
17
|
+
class Vertica::DataType
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# @return [Hash<Integer, Hash>] The Vertica types that are registered with this library, indexed by OID.
|
21
|
+
# @see .register
|
22
|
+
attr_accessor :registered_types
|
23
|
+
|
24
|
+
# Registers a new type by OID.
|
25
|
+
#
|
26
|
+
# @param oid [Integer] The object ID of the type.
|
27
|
+
# @param name [String] The name of the type as it can be used in SQL.
|
28
|
+
# @param deserializer [Proc] Proc that can deserialize values of this type coming
|
29
|
+
# from the database.
|
30
|
+
# @return [void]
|
31
|
+
def register(oid, name, deserializer = self.default_deserializer)
|
32
|
+
self.registered_types ||= {}
|
33
|
+
self.registered_types[oid] = { oid: oid, name: name, deserializer: TYPE_DESERIALIZERS.fetch(deserializer) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# Builds a new type instance based on an OID.
|
37
|
+
# @param (see Vertica::DataType#initialize)
|
38
|
+
# @return [Vertica::DataType]
|
39
|
+
# @raise [Vertica::Error::UnknownTypeError] if the OID is not registered.
|
40
|
+
def build(oid: nil, **kwargs)
|
41
|
+
args = registered_types.fetch(oid) do |unknown_oid|
|
42
|
+
raise Vertica::Error::UnknownTypeError, "Unknown type OID: #{unknown_oid}"
|
43
|
+
end
|
44
|
+
|
45
|
+
new(args.merge(kwargs))
|
46
|
+
end
|
47
|
+
|
48
|
+
# The name of the default deserializer proc.
|
49
|
+
# @return [Symbol]
|
50
|
+
def default_deserializer
|
51
|
+
:generic
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_reader :oid, :name, :size, :modifier, :format, :deserializer
|
56
|
+
|
57
|
+
# Instantiates a new DataType.
|
58
|
+
#
|
59
|
+
# @param oid [Integer] The object ID of the type.
|
60
|
+
# @param name [String] The name of the type as it can be used in SQL.
|
61
|
+
# @param size [Integer] The size of the type.
|
62
|
+
# @param modifier [Integer] A modifier of the type.
|
63
|
+
# @param format [Integer] The serialization format of this type.
|
64
|
+
# @param deserializer [Proc] Proc that can deserialize values of this type coming
|
65
|
+
# from the database.
|
66
|
+
# @see .build
|
67
|
+
def initialize(oid: nil, name: nil, size: nil, modifier: nil, format: 0, deserializer: nil)
|
68
|
+
@oid, @name, @size, @modifier, @format, @deserializer = oid, name, size, modifier, format, deserializer
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [Integer] Returns a hash digtest of this object.
|
72
|
+
def hash
|
73
|
+
[oid, size, modifier, format].hash
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Boolean] Returns true iff this record is equal to the other provided object
|
77
|
+
def eql?(other)
|
78
|
+
other.kind_of?(Vertica::DataType) && oid == other.oid && size == other.size &&
|
79
|
+
modifier == other.modifier && other.format == format
|
80
|
+
end
|
81
|
+
|
82
|
+
alias_method :==, :eql?
|
83
|
+
|
84
|
+
# Deserializes a value of this type as returned by the server.
|
85
|
+
# @param bytes [String, nil] The representation of the value returned by the server.
|
86
|
+
# @return [Object] The Ruby-value taht repesents the value returned from the DB.
|
87
|
+
# @see Vertica::Protocol::DataRow
|
88
|
+
def deserialize(bytes)
|
89
|
+
return nil if bytes.nil?
|
90
|
+
deserializer.call(bytes)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [String] Returns a user-consumable string representation of this type.
|
94
|
+
def inspect
|
95
|
+
"#<#{self.class.name}:#{oid} #{sql.inspect}>"
|
96
|
+
end
|
97
|
+
|
98
|
+
# Returns a SQL representation of this type.
|
99
|
+
# @return [String]
|
100
|
+
# @todo Take size and modifier into account.
|
101
|
+
def sql
|
102
|
+
name
|
103
|
+
end
|
104
|
+
|
105
|
+
TYPE_DESERIALIZERS = {
|
106
|
+
generic: lambda { |bytes| bytes },
|
107
|
+
bool: lambda { |bytes|
|
108
|
+
case bytes
|
109
|
+
when 't'; true
|
110
|
+
when 'f'; false
|
111
|
+
else raise ArgumentError, "Cannot convert #{bytes.inspect} to a boolean value"
|
112
|
+
end
|
113
|
+
},
|
114
|
+
integer: lambda { |bytes| Integer(bytes) },
|
115
|
+
float: lambda { |bytes|
|
116
|
+
case bytes
|
117
|
+
when 'Infinity'; Float::INFINITY
|
118
|
+
when '-Infinity'; -Float::INFINITY
|
119
|
+
when 'NaN'; Float::NAN
|
120
|
+
else Float(bytes)
|
121
|
+
end
|
122
|
+
},
|
123
|
+
bigdecimal: lambda { |bytes| BigDecimal(bytes) },
|
124
|
+
unicode_string: lambda { |bytes| bytes.force_encoding(Encoding::UTF_8) },
|
125
|
+
binary_string: lambda { |bytes| bytes.gsub(/\\([0-3][0-7][0-7])/) { $1.to_i(8).chr }.force_encoding(Encoding::BINARY) },
|
126
|
+
date: lambda { |bytes| Date.parse(bytes) },
|
127
|
+
timestamp: lambda { |bytes| Time.parse(bytes) },
|
128
|
+
}.freeze
|
129
|
+
|
130
|
+
private_constant :TYPE_DESERIALIZERS
|
131
|
+
end
|
132
|
+
|
133
|
+
Vertica::DataType.register 5, 'bool', :bool
|
134
|
+
Vertica::DataType.register 6, 'integer', :integer
|
135
|
+
Vertica::DataType.register 7, 'float', :float
|
136
|
+
Vertica::DataType.register 8, 'char', :unicode_string
|
137
|
+
Vertica::DataType.register 9, 'varchar', :unicode_string
|
138
|
+
Vertica::DataType.register 10, 'date', :date
|
139
|
+
Vertica::DataType.register 11, 'time'
|
140
|
+
Vertica::DataType.register 12, 'timestamp', :timestamp
|
141
|
+
Vertica::DataType.register 13, 'timestamp_tz', :timestamp
|
142
|
+
Vertica::DataType.register 14, 'time_tz'
|
143
|
+
Vertica::DataType.register 15, 'interval'
|
144
|
+
Vertica::DataType.register 16, 'numeric', :bigdecimal
|
145
|
+
Vertica::DataType.register 17, 'bytes', :binary_string
|
146
|
+
Vertica::DataType.register 115, 'long varchar', :unicode_string
|
data/lib/vertica/error.rb
CHANGED
@@ -8,6 +8,7 @@ class Vertica::Error < StandardError
|
|
8
8
|
class EmptyQueryError < Vertica::Error; end
|
9
9
|
class TimedOutError < ConnectionError; end
|
10
10
|
class UnknownTypeError < Vertica::Error; end
|
11
|
+
class DuplicateColumnName < Vertica::Error; end
|
11
12
|
|
12
13
|
class SynchronizeError < Vertica::Error
|
13
14
|
attr_reader :running_job, :requested_job
|
@@ -3,19 +3,10 @@ module Vertica
|
|
3
3
|
class CommandComplete < BackendMessage
|
4
4
|
message_id 'C'
|
5
5
|
|
6
|
-
attr_reader :tag
|
6
|
+
attr_reader :tag
|
7
7
|
|
8
8
|
def initialize(data)
|
9
|
-
|
10
|
-
when /^INSERT /
|
11
|
-
@tag, oid, rows = data.split(' ', 3)
|
12
|
-
@oid, @rows = oid.to_i, rows.to_i
|
13
|
-
when /^DELETE /, /^UPDATE /, /^MOVE /, /^FETCH /, /^COPY /
|
14
|
-
@tag, @rows = data.split(' ', 2)
|
15
|
-
@rows = rows.to_i
|
16
|
-
else
|
17
|
-
@tag = data
|
18
|
-
end
|
9
|
+
@tag = data.unpack('Z*').first
|
19
10
|
end
|
20
11
|
end
|
21
12
|
end
|
data/lib/vertica/query.rb
CHANGED
@@ -1,38 +1,56 @@
|
|
1
|
+
# The Query class handles the state of the connection while a SQL query is being executed.
|
2
|
+
# The connection should call {#run} and it will block until the query has been handled by
|
3
|
+
# the connection, after which control will be given back to the {Connection} instance.
|
4
|
+
#
|
5
|
+
# @note This class is for internal use only, you should never interact with this class directly.
|
6
|
+
#
|
7
|
+
# @see Vertica::Connection#query
|
8
|
+
# @see Vertica::Connection#copy
|
1
9
|
class Vertica::Query
|
2
10
|
|
3
|
-
|
4
|
-
|
11
|
+
# Instantiates a new query
|
12
|
+
# @param connection [Vertica::Connection] The connection to use for the query
|
13
|
+
# @param sql [String] The SQL statement to execute.
|
14
|
+
# @param row_handler [Proc, nil] Callback that will be called for every row that is returned.
|
15
|
+
# If no handler is provided, all rows will be buffered so a {Vertica::Result} can be returned.
|
16
|
+
#
|
17
|
+
# @param copy_handler [Proc, nil] Callback that will be called when the connection is ready
|
18
|
+
# to receive data for a `COPY ... FROM STDIN` statement.
|
5
19
|
def initialize(connection, sql, row_handler: nil, copy_handler: nil)
|
6
20
|
@connection, @sql = connection, sql
|
7
|
-
|
8
|
-
|
9
|
-
@row_handler = lambda { |row| buffer_row(row) }
|
10
|
-
else
|
11
|
-
@row_handler = row_handler
|
12
|
-
end
|
21
|
+
@buffer = row_handler.nil? && copy_handler.nil? ? [] : nil
|
22
|
+
@row_handler = row_handler || lambda { |row| buffer_row(row) }
|
13
23
|
@copy_handler = copy_handler
|
14
|
-
@error = nil
|
24
|
+
@row_description, @error = nil, nil
|
15
25
|
end
|
16
26
|
|
27
|
+
# Sends the query to the server, and processes the results.
|
28
|
+
# @return [String] For an unbuffered query, the type of SQL command will be return as a string
|
29
|
+
# (e.g. `"SELECT"` or `"COPY"`).
|
30
|
+
# @return [Vertica::Result] For a buffered query, this method will return a {Vertica::Result} instance
|
31
|
+
# @raise [Vertica::Error::ConnectionError] if the connection between client and
|
32
|
+
# server fails.
|
33
|
+
# @raise [Vertica::Error::QueryError] if the server cannot evaluate the query.
|
17
34
|
def run
|
18
|
-
@connection.write_message(Vertica::Protocol::Query.new(sql))
|
35
|
+
@connection.write_message(Vertica::Protocol::Query.new(@sql))
|
19
36
|
|
20
37
|
begin
|
21
38
|
process_message(message = @connection.read_message)
|
22
39
|
end until message.kind_of?(Vertica::Protocol::ReadyForQuery)
|
23
40
|
|
24
|
-
raise error unless error.nil?
|
25
|
-
return result
|
41
|
+
raise @error unless @error.nil?
|
42
|
+
return @result
|
26
43
|
end
|
27
44
|
|
28
|
-
|
29
|
-
|
45
|
+
# @return [String] Returns a user-consumable string representation of this query instance.
|
46
|
+
def inspect
|
47
|
+
"#<Vertica::Query:#{object_id} sql=#{@sql.inspect}>"
|
30
48
|
end
|
31
49
|
|
32
|
-
|
50
|
+
private
|
33
51
|
|
34
52
|
def buffer_rows?
|
35
|
-
|
53
|
+
@buffer.is_a?(Array)
|
36
54
|
end
|
37
55
|
|
38
56
|
def process_message(message)
|
@@ -64,7 +82,7 @@ class Vertica::Query
|
|
64
82
|
|
65
83
|
def handle_command_complete(message)
|
66
84
|
if buffer_rows?
|
67
|
-
@result = Vertica::Result.
|
85
|
+
@result = Vertica::Result.new(row_description: @row_description, rows: @buffer, tag: message.tag)
|
68
86
|
@row_description, @buffer = nil, nil
|
69
87
|
else
|
70
88
|
@result = message.tag
|
@@ -76,7 +94,7 @@ class Vertica::Query
|
|
76
94
|
@connection.write_message(Vertica::Protocol::CopyFail.new('no handler provided'))
|
77
95
|
else
|
78
96
|
begin
|
79
|
-
@copy_handler.call(CopyFromStdinWriter.new(connection))
|
97
|
+
@copy_handler.call(CopyFromStdinWriter.new(@connection))
|
80
98
|
@connection.write_message(Vertica::Protocol::CopyDone.new)
|
81
99
|
rescue => e
|
82
100
|
@connection.write_message(Vertica::Protocol::CopyFail.new(e.message))
|
data/lib/vertica/result.rb
CHANGED
@@ -1,22 +1,62 @@
|
|
1
|
+
# Class that represents a buffered resultset.
|
2
|
+
#
|
3
|
+
# This class implements the Enumerable interface for easy iteration through
|
4
|
+
# the rows. You can also address specific values in the result using {#fetch}.
|
5
|
+
# To leanr more about the shape of the result {#row_description} will give you
|
6
|
+
# an ordered list of all the {Vertica::Column}s in this result.
|
7
|
+
#
|
8
|
+
# @example Iterating over the rows
|
9
|
+
# result = connection.query("SELECT name, id")
|
10
|
+
# result.each do |row|
|
11
|
+
# puts "#{row[:id]}: #{row[:name]}"
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# @example Fetching specific values in the result
|
15
|
+
# result = connection.query('SELECT id, name FROM people WHERE id = 1')
|
16
|
+
# name = result.fetch(0, 'name')
|
17
|
+
# id = result[0,0]
|
18
|
+
#
|
19
|
+
# @example Retrieving the only value in a result
|
20
|
+
# average_salery = connection.query("SELECT AVG(salery) FROM employees").the_value
|
21
|
+
#
|
22
|
+
# @attr_reader [Vertica::RowDescription] row_description The columns in the result.
|
23
|
+
# @attr_reader [String] tag The kind of SQL command that produced this reuslt.
|
24
|
+
#
|
25
|
+
# @see Vertica::Connection#query
|
1
26
|
class Vertica::Result
|
2
27
|
include Enumerable
|
3
28
|
|
4
|
-
attr_reader :row_description
|
5
|
-
attr_reader :rows
|
6
|
-
attr_reader :tag
|
29
|
+
attr_reader :row_description, :tag
|
7
30
|
|
31
|
+
# Initializes a new Vertica::Result instance.
|
32
|
+
#
|
33
|
+
# The constructor assumes that the row description, and the list of rows match up.
|
34
|
+
# If you're unsure, use {Vertica::Result.build} which will assert this is the case.
|
35
|
+
#
|
36
|
+
# @param row_description [Vertica::RowDescription] The description of the rows
|
37
|
+
# @param rows [Array<Vertica::Row>] The array of rows
|
38
|
+
# @param tag [String] The kind of command that returned this result.
|
39
|
+
# @see Vertica::Result.build
|
8
40
|
def initialize(row_description: nil, rows: nil, tag: nil)
|
9
41
|
@row_description, @rows, @tag = row_description, rows, tag
|
10
42
|
end
|
11
43
|
|
44
|
+
# Iterates through the resultset. This class also includes the `Enumerable`
|
45
|
+
# interface, which means you can use all the `Enumerable` methods like `map`
|
46
|
+
# and `inject` as well.
|
47
|
+
# @yield The provided block will be called for every row in the resutset.
|
48
|
+
# @yieldparam row [Vertica::Row]
|
49
|
+
# @return [void]
|
12
50
|
def each(&block)
|
13
51
|
@rows.each(&block)
|
14
52
|
end
|
15
53
|
|
54
|
+
# @return [Boolean] Returns `true` if the result has no rows.
|
16
55
|
def empty?
|
17
56
|
@rows.empty?
|
18
57
|
end
|
19
58
|
|
59
|
+
# @return [Integer] The number of rows in this result
|
20
60
|
def size
|
21
61
|
@rows.length
|
22
62
|
end
|
@@ -24,14 +64,31 @@ class Vertica::Result
|
|
24
64
|
alias_method :count, :size
|
25
65
|
alias_method :length, :size
|
26
66
|
|
27
|
-
|
28
|
-
|
67
|
+
# Retrieves a row or value from the result.
|
68
|
+
# @return [Vertica::Row, Object]
|
69
|
+
#
|
70
|
+
# @overload fetch(row)
|
71
|
+
# Returns a row from the result.
|
72
|
+
# @param row [Integer] The 0-indexed row number.
|
73
|
+
# @raise [IndexError] if the row index is out of bounds.
|
74
|
+
# @return [Vertica::Row]
|
75
|
+
# @overload fetch(row, column)
|
76
|
+
# Returns a singular value from the result.
|
77
|
+
# @param row [Integer] The 0-indexed row number.
|
78
|
+
# @param col [Symbol, String, Integer] The name or index of the column.
|
79
|
+
# @raise [IndexError] if the row index is out of bounds.
|
80
|
+
# @raise [KeyError] if the requested column is not part of the result
|
81
|
+
# @return The value at the given row and column in the result.
|
82
|
+
def fetch(row, col = nil)
|
83
|
+
row = @rows.fetch(row)
|
29
84
|
return row if col.nil?
|
30
85
|
row.fetch(col)
|
31
86
|
end
|
32
87
|
|
33
88
|
alias_method :[], :fetch
|
34
89
|
|
90
|
+
# Shorthand to return the value of a query that only returns a single value.
|
91
|
+
# @return The first value of the first row, i.e. `fetch(0, 0)`.
|
35
92
|
def value
|
36
93
|
fetch(0, 0)
|
37
94
|
end
|
@@ -40,6 +97,13 @@ class Vertica::Result
|
|
40
97
|
|
41
98
|
alias_method :columns, :row_description
|
42
99
|
|
100
|
+
# Builds a {Vertica::Result} from a row description and a list of compatible rows.
|
101
|
+
# @param row_description An object that can be built into a {Vertica::RowDescription}.
|
102
|
+
# See {Vertica::RowDescription.build} for more info
|
103
|
+
# @param rows [Array] An array of objects that can be turned into a {Vertica::Row}.
|
104
|
+
# See {Vertica::RowDescription#build_row} for more info
|
105
|
+
# @param tag [String] The type of SQL command that yielded the result.
|
106
|
+
# @return [Vertica::Result]
|
43
107
|
def self.build(row_description: nil, rows: [], tag: nil)
|
44
108
|
row_description = Vertica::RowDescription.build(row_description)
|
45
109
|
rows = rows.map { |values| row_description.build_row(values) }
|
data/lib/vertica/row.rb
CHANGED
@@ -1,35 +1,86 @@
|
|
1
|
+
# Class to represent a row returns by a query.
|
2
|
+
#
|
3
|
+
# Row instances can either be yielded to the block passed to {Vertica::Connection#query},
|
4
|
+
# or be part of a buffered {Vertica::Result} returned by {Vertica::Connection#query}.
|
5
|
+
#
|
6
|
+
# @attr_reader row_description [Vertica::RowDescription] The ordered list of columns this
|
7
|
+
# row conforms to.
|
8
|
+
#
|
9
|
+
# @see Vertica::RowDescription#build_row
|
1
10
|
class Vertica::Row
|
2
11
|
include Enumerable
|
3
12
|
|
13
|
+
attr_reader :row_description
|
14
|
+
|
15
|
+
# Initializes a new row instance for a given row description and values. The
|
16
|
+
# number of values MUST match the number of columns in the row description.
|
17
|
+
# @param row_description [Vertica::RowDescription] The row description the
|
18
|
+
# values will conform to.
|
19
|
+
# @param values [Array] The values for the columns in the row description
|
20
|
+
# @see Vertica::RowDescription#build_row
|
4
21
|
def initialize(row_description, values)
|
5
22
|
@row_description, @values = row_description, values
|
6
23
|
end
|
7
24
|
|
25
|
+
# Iterates over the values in this row.
|
26
|
+
# @yield [value] The provided block will get called with the values in the order of
|
27
|
+
# the columns in the row_description.
|
8
28
|
def each(&block)
|
9
29
|
@values.each(&block)
|
10
30
|
end
|
11
31
|
|
32
|
+
# Fetches a value from this row.
|
33
|
+
# @param name_or_index [Symbol, String, Integer] The name of the column as string or symbol,
|
34
|
+
# or the index of the column in the row description.
|
35
|
+
# @raise KeyError A KeyError is raised if the field connot be found.
|
12
36
|
def fetch(name_or_index)
|
13
37
|
@values.fetch(column_index(name_or_index))
|
14
38
|
end
|
15
39
|
|
16
|
-
def inspect
|
17
|
-
"<Vertica::Row#{@values.inspect}>"
|
18
|
-
end
|
19
|
-
|
20
40
|
alias_method :[], :fetch
|
21
41
|
|
42
|
+
# Returns an array representation of the row. The values will
|
43
|
+
# be ordered like the order of the fields in the {#row_description}.
|
44
|
+
# @return [Array]
|
22
45
|
def to_a
|
23
|
-
@values
|
46
|
+
@values
|
24
47
|
end
|
25
48
|
|
49
|
+
# Returns a hash representation of this rows, using the name of the
|
50
|
+
# fields as keys.
|
51
|
+
# @param symbolize_keys [true, false] Set to true to use symbols instead
|
52
|
+
# of strings for the field names.
|
53
|
+
# @return [Hash]
|
54
|
+
# @raise [Vertica::Error::DuplicateColumnName] If the row contains multiple
|
55
|
+
# columns with the same name
|
26
56
|
def to_h(symbolize_keys: false)
|
27
57
|
@row_description.inject({}) do |carry, column|
|
28
58
|
key = symbolize_keys ? column.name.to_sym : column.name
|
29
|
-
carry.
|
59
|
+
raise Vertica::Error::DuplicateColumnName, "Column with name #{key} occurs more than once in this row." if carry.key?(key)
|
60
|
+
carry[key] = fetch(column.name)
|
61
|
+
carry
|
30
62
|
end
|
31
63
|
end
|
32
64
|
|
65
|
+
# @return [Boolean] Returns true iff this record is equal to the other provided object
|
66
|
+
def eql?(other)
|
67
|
+
other.kind_of?(Vertica::Row) && other.row_description == row_description && other.to_a == to_a
|
68
|
+
end
|
69
|
+
|
70
|
+
alias_method :==, :eql?
|
71
|
+
|
72
|
+
# @return [Integer] Returns a hash digtest of this object.
|
73
|
+
def hash
|
74
|
+
[row_description, values].hash
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [String] Returns a user-consumable string representation of this row.
|
78
|
+
def inspect
|
79
|
+
"#<#{self.class.name}#{@values.inspect}>"
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
33
84
|
def column(name_or_index)
|
34
85
|
column_with_index(name_or_index).fetch(0)
|
35
86
|
end
|