cassandra-driver 3.0.0.rc.1-java → 3.0.0.rc.2-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/lib/cassandra.rb +74 -55
- data/lib/cassandra/attr_boolean.rb +33 -0
- data/lib/cassandra/auth.rb +2 -1
- data/lib/cassandra/auth/providers/password.rb +4 -16
- data/lib/cassandra/cluster/connector.rb +14 -4
- data/lib/cassandra/cluster/control_connection.rb +59 -67
- data/lib/cassandra/cluster/metadata.rb +1 -3
- data/lib/cassandra/cluster/options.rb +9 -10
- data/lib/cassandra/cluster/registry.rb +16 -5
- data/lib/cassandra/cluster/schema.rb +45 -1
- data/lib/cassandra/cluster/schema/fetchers.rb +475 -272
- data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +2 -6
- data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +5 -7
- data/lib/cassandra/column.rb +1 -20
- data/lib/cassandra/column_container.rb +322 -0
- data/lib/cassandra/compression/compressors/lz4.rb +3 -5
- data/lib/cassandra/driver.rb +1 -1
- data/lib/cassandra/errors.rb +38 -22
- data/lib/cassandra/execution/options.rb +4 -2
- data/lib/cassandra/future.rb +3 -9
- data/lib/cassandra/host.rb +16 -2
- data/lib/cassandra/index.rb +104 -0
- data/lib/cassandra/keyspace.rb +88 -9
- data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +6 -10
- data/lib/cassandra/materialized_view.rb +90 -0
- data/lib/cassandra/protocol/coder.rb +3 -3
- data/lib/cassandra/protocol/cql_byte_buffer.rb +12 -11
- data/lib/cassandra/protocol/cql_protocol_handler.rb +12 -8
- data/lib/cassandra/protocol/request.rb +4 -5
- data/lib/cassandra/protocol/requests/execute_request.rb +3 -5
- data/lib/cassandra/protocol/requests/query_request.rb +1 -1
- data/lib/cassandra/protocol/requests/startup_request.rb +6 -8
- data/lib/cassandra/protocol/response.rb +1 -2
- data/lib/cassandra/protocol/responses/auth_challenge_response.rb +3 -4
- data/lib/cassandra/protocol/responses/auth_success_response.rb +3 -4
- data/lib/cassandra/protocol/responses/authenticate_response.rb +3 -4
- data/lib/cassandra/protocol/responses/error_response.rb +3 -4
- data/lib/cassandra/protocol/responses/event_response.rb +2 -3
- data/lib/cassandra/protocol/responses/prepared_result_response.rb +3 -4
- data/lib/cassandra/protocol/responses/ready_response.rb +3 -4
- data/lib/cassandra/protocol/responses/result_response.rb +7 -8
- data/lib/cassandra/protocol/responses/rows_result_response.rb +3 -4
- data/lib/cassandra/protocol/responses/schema_change_event_response.rb +3 -4
- data/lib/cassandra/protocol/responses/schema_change_result_response.rb +3 -4
- data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +3 -4
- data/lib/cassandra/protocol/responses/status_change_event_response.rb +3 -4
- data/lib/cassandra/protocol/responses/supported_response.rb +3 -4
- data/lib/cassandra/protocol/responses/topology_change_event_response.rb +3 -4
- data/lib/cassandra/protocol/responses/void_result_response.rb +3 -4
- data/lib/cassandra/protocol/v1.rb +1 -5
- data/lib/cassandra/protocol/v3.rb +1 -3
- data/lib/cassandra/result.rb +2 -1
- data/lib/cassandra/retry/policies/downgrading_consistency.rb +1 -3
- data/lib/cassandra/statements/prepared.rb +3 -3
- data/lib/cassandra/table.rb +39 -220
- data/lib/cassandra/time_uuid.rb +5 -7
- data/lib/cassandra/tuple.rb +4 -12
- data/lib/cassandra/types.rb +92 -65
- data/lib/cassandra/udt.rb +34 -14
- data/lib/cassandra/uuid.rb +10 -18
- data/lib/cassandra/version.rb +1 -1
- data/lib/cassandra_murmur3.jar +0 -0
- metadata +8 -2
@@ -39,9 +39,7 @@ module Cassandra
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def find_replicas(keyspace, statement)
|
42
|
-
unless statement.respond_to?(:partition_key) && statement.respond_to?(:keyspace)
|
43
|
-
return EMPTY_LIST
|
44
|
-
end
|
42
|
+
return EMPTY_LIST unless statement.respond_to?(:partition_key) && statement.respond_to?(:keyspace)
|
45
43
|
|
46
44
|
keyspace = String(statement.keyspace || keyspace)
|
47
45
|
partition_key = statement.partition_key
|
@@ -20,9 +20,12 @@ module Cassandra
|
|
20
20
|
class Cluster
|
21
21
|
# @private
|
22
22
|
class Options
|
23
|
+
extend AttrBoolean
|
24
|
+
|
23
25
|
attr_reader :auth_provider, :compressor, :connect_timeout, :credentials,
|
24
26
|
:heartbeat_interval, :idle_timeout, :port, :schema_refresh_delay,
|
25
27
|
:schema_refresh_timeout, :ssl
|
28
|
+
attr_boolean :protocol_negotiable, :synchronize_schema, :client_timestamps, :nodelay
|
26
29
|
|
27
30
|
attr_accessor :protocol_version
|
28
31
|
|
@@ -63,18 +66,14 @@ module Cassandra
|
|
63
66
|
@connections_per_local_node = connections_per_local_node
|
64
67
|
@connections_per_remote_node = connections_per_remote_node
|
65
68
|
@requests_per_connection = requests_per_connection
|
66
|
-
end
|
67
69
|
|
68
|
-
|
69
|
-
@
|
70
|
-
|
71
|
-
|
72
|
-
def client_timestamps?
|
73
|
-
@client_timestamps
|
74
|
-
end
|
70
|
+
# If @protocol_version is nil, it means we want the driver to negotiate the
|
71
|
+
# protocol starting with our known max (4). If @protocol_version is not nil,
|
72
|
+
# it means the user wants us to use a particular version, so we should not
|
73
|
+
# support negotiation.
|
75
74
|
|
76
|
-
|
77
|
-
@
|
75
|
+
@protocol_negotiable = @protocol_version.nil?
|
76
|
+
@protocol_version ||= 4
|
78
77
|
end
|
79
78
|
|
80
79
|
def compression
|
@@ -76,7 +76,9 @@ module Cassandra
|
|
76
76
|
if host.id == data['host_id'] &&
|
77
77
|
host.release_version == data['release_version'] &&
|
78
78
|
host.rack == data['rack'] &&
|
79
|
-
host.datacenter == data['data_center']
|
79
|
+
host.datacenter == data['data_center'] &&
|
80
|
+
host.broadcast_address == data['broadcast_address'] &&
|
81
|
+
host.listen_address == data['listen_address']
|
80
82
|
|
81
83
|
return self if host.up?
|
82
84
|
|
@@ -166,7 +168,10 @@ module Cassandra
|
|
166
168
|
data['data_center'],
|
167
169
|
data['release_version'],
|
168
170
|
Array(data['tokens']).freeze,
|
169
|
-
:up
|
171
|
+
:up,
|
172
|
+
data['broadcast_address'],
|
173
|
+
data['listen_address']
|
174
|
+
)
|
170
175
|
end
|
171
176
|
|
172
177
|
def toggle_up(host)
|
@@ -176,7 +181,9 @@ module Cassandra
|
|
176
181
|
host.datacenter,
|
177
182
|
host.release_version,
|
178
183
|
host.tokens,
|
179
|
-
:up
|
184
|
+
:up,
|
185
|
+
host.broadcast_address,
|
186
|
+
host.listen_address)
|
180
187
|
@logger.debug("Host #{host.ip} is up")
|
181
188
|
@listeners.each do |listener|
|
182
189
|
begin
|
@@ -195,7 +202,9 @@ module Cassandra
|
|
195
202
|
host.datacenter,
|
196
203
|
host.release_version,
|
197
204
|
host.tokens,
|
198
|
-
:down
|
205
|
+
:down,
|
206
|
+
host.broadcast_address,
|
207
|
+
host.listen_address)
|
199
208
|
@logger.debug("Host #{host.ip} is down")
|
200
209
|
@listeners.reverse_each do |listener|
|
201
210
|
begin
|
@@ -216,7 +225,9 @@ module Cassandra
|
|
216
225
|
host.datacenter,
|
217
226
|
host.release_version,
|
218
227
|
host.tokens,
|
219
|
-
:down
|
228
|
+
:down,
|
229
|
+
host.broadcast_address,
|
230
|
+
host.listen_address)
|
220
231
|
@listeners.reverse_each do |listener|
|
221
232
|
begin
|
222
233
|
listener.host_down(host)
|
@@ -126,7 +126,7 @@ module Cassandra
|
|
126
126
|
end
|
127
127
|
|
128
128
|
def replace_table(table)
|
129
|
-
keyspace =
|
129
|
+
keyspace = table.keyspace
|
130
130
|
|
131
131
|
return self unless keyspace
|
132
132
|
|
@@ -169,6 +169,50 @@ module Cassandra
|
|
169
169
|
self
|
170
170
|
end
|
171
171
|
|
172
|
+
def replace_materialized_view(view)
|
173
|
+
keyspace = view.keyspace
|
174
|
+
|
175
|
+
return self unless keyspace
|
176
|
+
|
177
|
+
old_view = keyspace.materialized_view(view.name)
|
178
|
+
|
179
|
+
return self if old_view == view
|
180
|
+
|
181
|
+
keyspace = keyspace.update_materialized_view(view)
|
182
|
+
|
183
|
+
synchronize do
|
184
|
+
keyspaces = @keyspaces.dup
|
185
|
+
keyspaces[keyspace.name] = keyspace
|
186
|
+
@keyspaces = keyspaces
|
187
|
+
end
|
188
|
+
|
189
|
+
keyspace_changed(keyspace)
|
190
|
+
|
191
|
+
self
|
192
|
+
end
|
193
|
+
|
194
|
+
def delete_materialized_view(keyspace_name, view_name)
|
195
|
+
keyspace = @keyspaces[keyspace_name]
|
196
|
+
|
197
|
+
return self unless keyspace
|
198
|
+
|
199
|
+
view = keyspace.materialized_view(view_name)
|
200
|
+
|
201
|
+
return self unless view
|
202
|
+
|
203
|
+
keyspace = keyspace.delete_materialized_view(view_name)
|
204
|
+
|
205
|
+
synchronize do
|
206
|
+
keyspaces = @keyspaces.dup
|
207
|
+
keyspaces[keyspace_name] = keyspace
|
208
|
+
@keyspaces = keyspaces
|
209
|
+
end
|
210
|
+
|
211
|
+
keyspace_changed(keyspace)
|
212
|
+
|
213
|
+
self
|
214
|
+
end
|
215
|
+
|
172
216
|
def replace_type(type)
|
173
217
|
keyspace = @keyspaces[type.keyspace]
|
174
218
|
|
@@ -26,20 +26,23 @@ module Cassandra
|
|
26
26
|
COMPRESSION_PACKAGE_PREFIX = 'org.apache.cassandra.io.compress.'.freeze
|
27
27
|
|
28
28
|
def fetch(connection)
|
29
|
+
# rubocop:disable Metrics/LineLength
|
29
30
|
Ione::Future.all(select_keyspaces(connection),
|
30
31
|
select_tables(connection),
|
31
32
|
select_columns(connection),
|
32
33
|
select_types(connection),
|
33
34
|
select_functions(connection),
|
34
|
-
select_aggregates(connection)
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
select_aggregates(connection),
|
36
|
+
select_materialized_views(connection),
|
37
|
+
select_indexes(connection))
|
38
|
+
.map do |rows_keyspaces, rows_tables, rows_columns, rows_types, rows_functions, rows_aggregates, rows_views, rows_indexes|
|
38
39
|
lookup_tables = map_rows_by(rows_tables, 'keyspace_name')
|
39
40
|
lookup_columns = map_rows_by(rows_columns, 'keyspace_name')
|
40
41
|
lookup_types = map_rows_by(rows_types, 'keyspace_name')
|
41
42
|
lookup_functions = map_rows_by(rows_functions, 'keyspace_name')
|
42
43
|
lookup_aggregates = map_rows_by(rows_aggregates, 'keyspace_name')
|
44
|
+
lookup_views = map_rows_by(rows_views, 'keyspace_name')
|
45
|
+
lookup_indexes = map_rows_by(rows_indexes, 'keyspace_name')
|
43
46
|
|
44
47
|
rows_keyspaces.map do |keyspace_data|
|
45
48
|
name = keyspace_data['keyspace_name']
|
@@ -49,7 +52,9 @@ module Cassandra
|
|
49
52
|
lookup_columns[name],
|
50
53
|
lookup_types[name],
|
51
54
|
lookup_functions[name],
|
52
|
-
lookup_aggregates[name]
|
55
|
+
lookup_aggregates[name],
|
56
|
+
lookup_views[name],
|
57
|
+
lookup_indexes[name])
|
53
58
|
end
|
54
59
|
end
|
55
60
|
end
|
@@ -60,9 +65,10 @@ module Cassandra
|
|
60
65
|
select_keyspace_columns(connection, keyspace_name),
|
61
66
|
select_keyspace_types(connection, keyspace_name),
|
62
67
|
select_keyspace_functions(connection, keyspace_name),
|
63
|
-
select_keyspace_aggregates(connection, keyspace_name)
|
64
|
-
|
65
|
-
|
68
|
+
select_keyspace_aggregates(connection, keyspace_name),
|
69
|
+
select_keyspace_materialized_views(connection, keyspace_name),
|
70
|
+
select_keyspace_indexes(connection, keyspace_name))
|
71
|
+
.map do |rows_keyspaces, rows_tables, rows_columns, rows_types, rows_functions, rows_aggregates, rows_views, rows_indexes|
|
66
72
|
if rows_keyspaces.empty?
|
67
73
|
nil
|
68
74
|
else
|
@@ -71,20 +77,40 @@ module Cassandra
|
|
71
77
|
rows_columns,
|
72
78
|
rows_types,
|
73
79
|
rows_functions,
|
74
|
-
rows_aggregates
|
80
|
+
rows_aggregates,
|
81
|
+
rows_views,
|
82
|
+
rows_indexes)
|
75
83
|
end
|
76
84
|
end
|
77
85
|
end
|
78
86
|
|
79
87
|
def fetch_table(connection, keyspace_name, table_name)
|
80
88
|
Ione::Future.all(select_table(connection, keyspace_name, table_name),
|
81
|
-
select_table_columns(connection, keyspace_name, table_name)
|
82
|
-
|
89
|
+
select_table_columns(connection, keyspace_name, table_name),
|
90
|
+
select_table_indexes(connection, keyspace_name, table_name))
|
91
|
+
.map do |(rows_tables, rows_columns, rows_indexes)|
|
83
92
|
if rows_tables.empty?
|
84
93
|
nil
|
85
94
|
else
|
86
95
|
create_table(rows_tables.first,
|
87
|
-
rows_columns
|
96
|
+
rows_columns,
|
97
|
+
rows_indexes)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def fetch_materialized_view(connection, keyspace_name, view_name)
|
103
|
+
Ione::Future.all(select_materialized_view(connection, keyspace_name, view_name),
|
104
|
+
select_table_columns(connection, keyspace_name, view_name))
|
105
|
+
.map do |rows_views, rows_columns|
|
106
|
+
if rows_views.empty?
|
107
|
+
nil
|
108
|
+
else
|
109
|
+
view_row = rows_views.first
|
110
|
+
base_table = @schema.keyspace(keyspace_name).table(view_row['base_table_name'])
|
111
|
+
create_materialized_view(view_row,
|
112
|
+
rows_columns,
|
113
|
+
base_table)
|
88
114
|
end
|
89
115
|
end
|
90
116
|
end
|
@@ -100,8 +126,8 @@ module Cassandra
|
|
100
126
|
end
|
101
127
|
|
102
128
|
def fetch_function(connection, keyspace_name, function_name, function_args)
|
103
|
-
select_function(connection, keyspace_name, function_name, function_args)
|
104
|
-
|
129
|
+
select_function(connection, keyspace_name, function_name, function_args)
|
130
|
+
.map do |rows_functions|
|
105
131
|
if rows_functions.empty?
|
106
132
|
nil
|
107
133
|
else
|
@@ -111,13 +137,13 @@ module Cassandra
|
|
111
137
|
end
|
112
138
|
|
113
139
|
def fetch_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
|
114
|
-
select_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
|
115
|
-
|
140
|
+
select_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
|
141
|
+
.map do |rows_aggregates|
|
116
142
|
if rows_aggregates.empty?
|
117
143
|
nil
|
118
144
|
else
|
119
|
-
create_aggregate(rows_aggregates.first, @schema.keyspace(keyspace_name)
|
120
|
-
send(:raw_functions))
|
145
|
+
create_aggregate(rows_aggregates.first, @schema.keyspace(keyspace_name)
|
146
|
+
.send(:raw_functions))
|
121
147
|
end
|
122
148
|
end
|
123
149
|
end
|
@@ -132,10 +158,18 @@ module Cassandra
|
|
132
158
|
FUTURE_EMPTY_LIST
|
133
159
|
end
|
134
160
|
|
161
|
+
def select_materialized_views(connection)
|
162
|
+
FUTURE_EMPTY_LIST
|
163
|
+
end
|
164
|
+
|
135
165
|
def select_columns(connection)
|
136
166
|
FUTURE_EMPTY_LIST
|
137
167
|
end
|
138
168
|
|
169
|
+
def select_indexes(connection)
|
170
|
+
FUTURE_EMPTY_LIST
|
171
|
+
end
|
172
|
+
|
139
173
|
def select_types(connection)
|
140
174
|
FUTURE_EMPTY_LIST
|
141
175
|
end
|
@@ -156,10 +190,18 @@ module Cassandra
|
|
156
190
|
FUTURE_EMPTY_LIST
|
157
191
|
end
|
158
192
|
|
193
|
+
def select_keyspace_materialized_views(connection, keyspace_name)
|
194
|
+
FUTURE_EMPTY_LIST
|
195
|
+
end
|
196
|
+
|
159
197
|
def select_keyspace_columns(connection, keyspace_name)
|
160
198
|
FUTURE_EMPTY_LIST
|
161
199
|
end
|
162
200
|
|
201
|
+
def select_keyspace_indexes(connection, keyspace_name)
|
202
|
+
FUTURE_EMPTY_LIST
|
203
|
+
end
|
204
|
+
|
163
205
|
def select_keyspace_types(connection, keyspace_name)
|
164
206
|
FUTURE_EMPTY_LIST
|
165
207
|
end
|
@@ -176,10 +218,18 @@ module Cassandra
|
|
176
218
|
FUTURE_EMPTY_LIST
|
177
219
|
end
|
178
220
|
|
221
|
+
def select_materialized_view(connection, keyspace_name, view_name)
|
222
|
+
FUTURE_EMPTY_LIST
|
223
|
+
end
|
224
|
+
|
179
225
|
def select_table_columns(connection, keyspace_name, table_name)
|
180
226
|
FUTURE_EMPTY_LIST
|
181
227
|
end
|
182
228
|
|
229
|
+
def select_table_indexes(connection, keyspace_name, table_name)
|
230
|
+
FUTURE_EMPTY_LIST
|
231
|
+
end
|
232
|
+
|
183
233
|
def select_type(connection, keyspace_name, type_name)
|
184
234
|
FUTURE_EMPTY_LIST
|
185
235
|
end
|
@@ -195,7 +245,7 @@ module Cassandra
|
|
195
245
|
def send_select_request(connection, cql, params = EMPTY_LIST, types = EMPTY_LIST)
|
196
246
|
backtrace = caller
|
197
247
|
connection.send_request(
|
198
|
-
|
248
|
+
Protocol::QueryRequest.new(cql, params, types, :one)).map do |r|
|
199
249
|
case r
|
200
250
|
when Protocol::RowsResultResponse
|
201
251
|
r.rows
|
@@ -212,43 +262,44 @@ module Cassandra
|
|
212
262
|
def map_rows_by(rows, key_name, &block)
|
213
263
|
rows.each_with_object(::Hash.new { EMPTY_LIST }) do |row, map|
|
214
264
|
key = row[key_name]
|
215
|
-
map[key] = [] unless map.
|
265
|
+
map[key] = [] unless map.key?(key)
|
216
266
|
|
217
|
-
if block
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
267
|
+
map[key] << if block
|
268
|
+
yield(row)
|
269
|
+
else
|
270
|
+
row
|
271
|
+
end
|
222
272
|
end
|
223
273
|
end
|
224
274
|
end
|
225
275
|
|
226
276
|
# @private
|
227
277
|
module Fetchers
|
278
|
+
# rubocop:disable Style/ClassAndModuleCamelCase
|
228
279
|
class V1_2_x
|
229
280
|
SELECT_KEYSPACES = 'SELECT * FROM system.schema_keyspaces'.freeze
|
230
281
|
SELECT_TABLES = 'SELECT * FROM system.schema_columnfamilies'.freeze
|
231
282
|
SELECT_COLUMNS = 'SELECT * FROM system.schema_columns'.freeze
|
232
283
|
SELECT_KEYSPACE =
|
233
|
-
|
234
|
-
|
235
|
-
|
284
|
+
'SELECT * ' \
|
285
|
+
'FROM system.schema_keyspaces ' \
|
286
|
+
'WHERE keyspace_name = \'%s\''.freeze
|
236
287
|
SELECT_KEYSPACE_TABLES =
|
237
|
-
|
238
|
-
|
239
|
-
|
288
|
+
'SELECT * ' \
|
289
|
+
'FROM system.schema_columnfamilies ' \
|
290
|
+
'WHERE keyspace_name = \'%s\''.freeze
|
240
291
|
SELECT_KEYSPACE_COLUMNS =
|
241
|
-
|
292
|
+
'SELECT * FROM system.schema_columns WHERE keyspace_name = \'%s\''.freeze
|
242
293
|
SELECT_TABLE =
|
243
|
-
|
244
|
-
|
245
|
-
|
294
|
+
'SELECT * ' \
|
295
|
+
'FROM system.schema_columnfamilies ' \
|
296
|
+
'WHERE keyspace_name = \'%s\' AND columnfamily_name = \'%s\''.freeze
|
246
297
|
SELECT_TABLE_COLUMNS =
|
247
|
-
|
248
|
-
|
249
|
-
|
298
|
+
'SELECT * ' \
|
299
|
+
'FROM system.schema_columns ' \
|
300
|
+
'WHERE keyspace_name = \'%s\' AND columnfamily_name = \'%s\''.freeze
|
250
301
|
|
251
|
-
include Fetcher
|
302
|
+
include Cassandra::Cluster::Schema::Fetcher
|
252
303
|
|
253
304
|
def initialize(type_parser, schema)
|
254
305
|
@type_parser = type_parser
|
@@ -274,20 +325,20 @@ module Cassandra
|
|
274
325
|
end
|
275
326
|
|
276
327
|
def select_keyspace_tables(connection, keyspace_name)
|
277
|
-
send_select_request(connection, SELECT_KEYSPACE_TABLES
|
328
|
+
send_select_request(connection, format(SELECT_KEYSPACE_TABLES, keyspace_name))
|
278
329
|
end
|
279
330
|
|
280
331
|
def select_keyspace_columns(connection, keyspace_name)
|
281
|
-
send_select_request(connection, SELECT_KEYSPACE_COLUMNS
|
332
|
+
send_select_request(connection, format(SELECT_KEYSPACE_COLUMNS, keyspace_name))
|
282
333
|
end
|
283
334
|
|
284
335
|
def select_table(connection, keyspace_name, table_name)
|
285
|
-
send_select_request(connection, SELECT_TABLE
|
336
|
+
send_select_request(connection, format(SELECT_TABLE, keyspace_name, table_name))
|
286
337
|
end
|
287
338
|
|
288
339
|
def select_table_columns(connection, keyspace_name, table_name)
|
289
340
|
send_select_request(connection,
|
290
|
-
SELECT_TABLE_COLUMNS
|
341
|
+
format(SELECT_TABLE_COLUMNS, keyspace_name, table_name))
|
291
342
|
end
|
292
343
|
|
293
344
|
def create_replication(keyspace_data)
|
@@ -298,12 +349,13 @@ module Cassandra
|
|
298
349
|
end
|
299
350
|
|
300
351
|
def create_keyspace(keyspace_data, rows_tables, rows_columns,
|
301
|
-
rows_types, rows_functions, rows_aggregates
|
352
|
+
rows_types, rows_functions, rows_aggregates,
|
353
|
+
rows_views, rows_indexes)
|
302
354
|
keyspace_name = keyspace_data['keyspace_name']
|
303
355
|
replication = create_replication(keyspace_data)
|
304
|
-
types = rows_types.each_with_object({}) do |row,
|
305
|
-
|
306
|
-
|
356
|
+
types = rows_types.each_with_object({}) do |row, h|
|
357
|
+
h[row['type_name']] = create_type(row)
|
358
|
+
end
|
307
359
|
|
308
360
|
# Create a FunctionCollection for the functions and aggregates.
|
309
361
|
functions = Cassandra::FunctionCollection.new
|
@@ -317,9 +369,10 @@ module Cassandra
|
|
317
369
|
end
|
318
370
|
|
319
371
|
lookup_columns = map_rows_by(rows_columns, 'columnfamily_name')
|
320
|
-
tables = rows_tables.each_with_object({}) do |row,
|
372
|
+
tables = rows_tables.each_with_object({}) do |row, h|
|
321
373
|
table_name = row['columnfamily_name']
|
322
|
-
|
374
|
+
# rows_indexes is nil for C* < 3.0.
|
375
|
+
h[table_name] = create_table(row, lookup_columns[table_name], nil)
|
323
376
|
end
|
324
377
|
|
325
378
|
Keyspace.new(keyspace_name,
|
@@ -328,24 +381,34 @@ module Cassandra
|
|
328
381
|
tables,
|
329
382
|
types,
|
330
383
|
functions,
|
331
|
-
aggregates
|
384
|
+
aggregates,
|
385
|
+
{})
|
332
386
|
end
|
333
387
|
|
334
|
-
def create_table(table_data, rows_columns)
|
388
|
+
def create_table(table_data, rows_columns, rows_indexes)
|
335
389
|
keyspace_name = table_data['keyspace_name']
|
336
390
|
table_name = table_data['columnfamily_name']
|
337
391
|
key_validator = @type_parser.parse(table_data['key_validator'])
|
338
392
|
comparator = @type_parser.parse(table_data['comparator'])
|
339
393
|
column_aliases = ::JSON.load(table_data['column_aliases'])
|
340
394
|
|
341
|
-
if
|
395
|
+
if comparator.collections.nil?
|
396
|
+
is_compact = true
|
397
|
+
if !column_aliases.empty? || rows_columns.empty?
|
398
|
+
has_value = true
|
399
|
+
clustering_size = comparator.results.size
|
400
|
+
else
|
401
|
+
has_value = false
|
402
|
+
clustering_size = 0
|
403
|
+
end
|
404
|
+
else
|
342
405
|
size = comparator.results.size
|
343
406
|
if !comparator.collections.empty?
|
344
407
|
is_compact = false
|
345
408
|
has_value = false
|
346
409
|
clustering_size = size - 2
|
347
410
|
elsif column_aliases.size == size - 1 &&
|
348
|
-
|
411
|
+
comparator.results.last.first == Cassandra::Types.varchar
|
349
412
|
is_compact = false
|
350
413
|
has_value = false
|
351
414
|
clustering_size = size - 1
|
@@ -354,33 +417,24 @@ module Cassandra
|
|
354
417
|
has_value = (!column_aliases.empty? || rows_columns.empty?)
|
355
418
|
clustering_size = size
|
356
419
|
end
|
357
|
-
else
|
358
|
-
is_compact = true
|
359
|
-
if (!column_aliases.empty? || rows_columns.empty?)
|
360
|
-
has_value = true
|
361
|
-
clustering_size = comparator.results.size
|
362
|
-
else
|
363
|
-
has_value = false
|
364
|
-
clustering_size = 0
|
365
|
-
end
|
366
420
|
end
|
367
421
|
|
422
|
+
# Separate out the partition-key, clustering-columns, and other-columns
|
368
423
|
partition_key = []
|
369
424
|
clustering_columns = []
|
370
425
|
clustering_order = []
|
426
|
+
other_columns = []
|
371
427
|
|
372
428
|
compaction_strategy = create_compaction_strategy(table_data)
|
373
429
|
table_options =
|
374
|
-
|
375
|
-
table_columns = {}
|
376
|
-
other_columns = []
|
430
|
+
create_table_options(table_data, compaction_strategy, is_compact)
|
377
431
|
|
378
432
|
key_aliases = ::JSON.load(table_data['key_aliases'])
|
379
433
|
|
380
434
|
key_validator.results.each_with_index do |(type, order, is_frozen), i|
|
381
|
-
key_alias = key_aliases.fetch(i) { i.zero? ?
|
435
|
+
key_alias = key_aliases.fetch(i) { i.zero? ? 'key' : "key#{i + 1}" }
|
382
436
|
|
383
|
-
partition_key[i] = Column.new(key_alias, type, order,
|
437
|
+
partition_key[i] = Column.new(key_alias, type, order, false, is_frozen)
|
384
438
|
end
|
385
439
|
|
386
440
|
clustering_size.times do |i|
|
@@ -388,7 +442,7 @@ module Cassandra
|
|
388
442
|
type, order, is_frozen = comparator.results.fetch(i)
|
389
443
|
|
390
444
|
clustering_columns[i] =
|
391
|
-
|
445
|
+
Column.new(column_alias, type, order, false, is_frozen)
|
392
446
|
clustering_order[i] = order
|
393
447
|
end
|
394
448
|
|
@@ -398,71 +452,86 @@ module Cassandra
|
|
398
452
|
|
399
453
|
unless value_alias.empty?
|
400
454
|
type, order, is_frozen =
|
401
|
-
|
455
|
+
@type_parser.parse(table_data['default_validator']).results.first
|
402
456
|
other_columns <<
|
403
|
-
|
457
|
+
Column.new(value_alias, type, order, false, is_frozen)
|
404
458
|
end
|
405
459
|
end
|
406
460
|
|
461
|
+
index_rows = []
|
407
462
|
rows_columns.each do |row|
|
408
|
-
|
409
|
-
|
463
|
+
column = create_column(row)
|
464
|
+
other_columns << column
|
410
465
|
|
411
|
-
|
412
|
-
|
466
|
+
# In C* 1.2.x, index info is in the column metadata; rows_indexes is nil.
|
467
|
+
index_rows << [column, row] unless row['index_type'].nil?
|
413
468
|
end
|
414
469
|
|
415
|
-
|
416
|
-
|
470
|
+
table = Cassandra::Table.new(@schema.keyspace(keyspace_name),
|
471
|
+
table_name,
|
472
|
+
partition_key,
|
473
|
+
clustering_columns,
|
474
|
+
other_columns,
|
475
|
+
table_options,
|
476
|
+
clustering_order,
|
477
|
+
table_data['id'])
|
478
|
+
|
479
|
+
# Create Index objects and add them to the table.
|
480
|
+
index_rows.each do |column, row|
|
481
|
+
create_index(table, column, row)
|
417
482
|
end
|
483
|
+
table
|
484
|
+
end
|
418
485
|
|
419
|
-
|
420
|
-
|
486
|
+
def create_index(table, column, row_column)
|
487
|
+
# Most of this logic was taken from the Java driver.
|
488
|
+
options = {}
|
489
|
+
# For some versions of C*, this field could have a literal string 'null' value.
|
490
|
+
if !row_column['index_options'].nil? && row_column['index_options'] != 'null' && !row_column['index_options'].empty?
|
491
|
+
options = ::JSON.load(row_column['index_options'])
|
421
492
|
end
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
493
|
+
column_name = Util.escape_name(column.name)
|
494
|
+
target = if options.key?('index_keys')
|
495
|
+
"keys(#{column_name})"
|
496
|
+
elsif options.key?('index_keys_and_values')
|
497
|
+
"entries(#{column_name})"
|
498
|
+
elsif column.frozen? && (column.type == Cassandra::Types::Set ||
|
499
|
+
column.type == Cassandra::Types::List ||
|
500
|
+
column.type == Cassandra::Types::Map)
|
501
|
+
"full(#{column_name})"
|
502
|
+
else
|
503
|
+
column_name
|
504
|
+
end
|
505
|
+
|
506
|
+
table.add_index(Cassandra::Index.new(table,
|
507
|
+
row_column['index_name'],
|
508
|
+
row_column['index_type'].downcase.to_sym,
|
509
|
+
target,
|
510
|
+
options))
|
430
511
|
end
|
431
512
|
|
432
513
|
def create_column(column_data)
|
433
514
|
name = column_data['column_name']
|
434
515
|
is_static = (column_data['type'] == 'STATIC')
|
435
516
|
type, order, is_frozen =
|
436
|
-
|
437
|
-
|
438
|
-
if column_data['index_type'].nil?
|
439
|
-
index = nil
|
440
|
-
elsif column_data['index_type'].to_s.upcase == 'CUSTOM' ||
|
441
|
-
!column_data['index_options']
|
442
|
-
index = Column::Index.new(column_data['index_name'])
|
443
|
-
else
|
444
|
-
options = ::JSON.load(column_data['index_options'])
|
445
|
-
index = Column::Index.new(column_data['index_name'],
|
446
|
-
options && options['class_name'])
|
447
|
-
end
|
448
|
-
|
449
|
-
Column.new(name, type, order, index, is_static, is_frozen)
|
517
|
+
@type_parser.parse(column_data['validator']).results.first
|
518
|
+
Column.new(name, type, order, is_static, is_frozen)
|
450
519
|
end
|
451
520
|
|
452
521
|
def create_compaction_strategy(table_data)
|
453
522
|
klass = table_data['compaction_strategy_class']
|
454
523
|
klass.slice!('org.apache.cassandra.db.compaction.')
|
455
524
|
options = ::JSON.load(table_data['compaction_strategy_options'])
|
456
|
-
|
525
|
+
ColumnContainer::Compaction.new(klass, options)
|
457
526
|
end
|
458
527
|
|
459
528
|
def create_table_options(table_data, compaction_strategy, is_compact)
|
460
529
|
compression_parameters = ::JSON.load(table_data['compression_parameters'])
|
461
530
|
if compression_parameters['sstable_compression']
|
462
|
-
compression_parameters['sstable_compression']
|
463
|
-
|
531
|
+
compression_parameters['sstable_compression']
|
532
|
+
.slice!(COMPRESSION_PACKAGE_PREFIX)
|
464
533
|
end
|
465
|
-
|
534
|
+
Cassandra::ColumnContainer::Options.new(
|
466
535
|
table_data['comment'],
|
467
536
|
table_data['read_repair_chance'],
|
468
537
|
table_data['local_read_repair_chance'],
|
@@ -479,88 +548,87 @@ module Cassandra
|
|
479
548
|
nil,
|
480
549
|
compaction_strategy,
|
481
550
|
compression_parameters,
|
482
|
-
is_compact
|
551
|
+
is_compact,
|
552
|
+
table_data['crc_check_chance'],
|
553
|
+
table_data['extensions']
|
483
554
|
)
|
484
555
|
end
|
485
556
|
end
|
486
557
|
|
487
558
|
class V2_0_x < V1_2_x
|
488
559
|
SELECT_KEYSPACE =
|
489
|
-
|
560
|
+
'SELECT * FROM system.schema_keyspaces WHERE keyspace_name = ?'.freeze
|
490
561
|
SELECT_KEYSPACE_TABLES =
|
491
|
-
|
562
|
+
'SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = ?'.freeze
|
492
563
|
SELECT_KEYSPACE_COLUMNS =
|
493
|
-
|
564
|
+
'SELECT * FROM system.schema_columns WHERE keyspace_name = ?'.freeze
|
494
565
|
SELECT_TABLE =
|
495
|
-
|
496
|
-
|
497
|
-
|
566
|
+
'SELECT * ' \
|
567
|
+
'FROM system.schema_columnfamilies ' \
|
568
|
+
'WHERE keyspace_name = ? AND columnfamily_name = ?'.freeze
|
498
569
|
SELECT_TABLE_COLUMNS =
|
499
|
-
|
500
|
-
|
501
|
-
|
570
|
+
'SELECT * ' \
|
571
|
+
'FROM system.schema_columns ' \
|
572
|
+
'WHERE keyspace_name = ? AND columnfamily_name = ?'.freeze
|
502
573
|
|
503
574
|
private
|
504
575
|
|
505
|
-
def create_table(table_data, rows_columns)
|
576
|
+
def create_table(table_data, rows_columns, rows_indexes)
|
506
577
|
keyspace_name = table_data['keyspace_name']
|
507
578
|
table_name = table_data['columnfamily_name']
|
508
579
|
comparator = @type_parser.parse(table_data['comparator'])
|
509
|
-
table_columns = {}
|
510
|
-
other_columns = []
|
511
580
|
clustering_size = 0
|
512
581
|
|
582
|
+
# Separate out partition-key, clustering columns, other columns.
|
513
583
|
partition_key = []
|
514
584
|
clustering_columns = []
|
515
585
|
clustering_order = []
|
586
|
+
other_columns = []
|
516
587
|
|
588
|
+
index_rows = []
|
517
589
|
rows_columns.each do |row|
|
518
590
|
next if row['column_name'].empty?
|
519
591
|
|
520
592
|
column = create_column(row)
|
521
593
|
type = row['type'].to_s
|
522
|
-
|
594
|
+
ind = row['component_index'] || 0
|
523
595
|
|
524
596
|
case type.upcase
|
525
597
|
when 'PARTITION_KEY'
|
526
|
-
partition_key[
|
598
|
+
partition_key[ind] = column
|
527
599
|
when 'CLUSTERING_KEY'
|
528
|
-
clustering_columns[
|
529
|
-
clustering_order[
|
600
|
+
clustering_columns[ind] = column
|
601
|
+
clustering_order[ind] = column.order
|
530
602
|
|
531
|
-
if clustering_size.zero? ||
|
532
|
-
clustering_size = index + 1
|
533
|
-
end
|
603
|
+
clustering_size = ind + 1 if clustering_size.zero? || ind == clustering_size
|
534
604
|
else
|
535
605
|
other_columns << column
|
536
606
|
end
|
537
|
-
end
|
538
607
|
|
539
|
-
|
540
|
-
|
541
|
-
end
|
542
|
-
|
543
|
-
clustering_columns.each do |column|
|
544
|
-
table_columns[column.name] = column
|
545
|
-
end
|
546
|
-
|
547
|
-
other_columns.each do |column|
|
548
|
-
table_columns[column.name] = column
|
608
|
+
# In C* 2.0.x, index info is in the column metadata; rows_indexes is nil.
|
609
|
+
index_rows << [column, row] unless row['index_type'].nil?
|
549
610
|
end
|
550
611
|
|
551
612
|
compaction_strategy = create_compaction_strategy(table_data)
|
552
613
|
is_compact = (clustering_size != comparator.results.size - 1) ||
|
553
|
-
|
614
|
+
!comparator.collections
|
554
615
|
table_options =
|
555
|
-
|
556
|
-
|
557
|
-
Table.new(keyspace_name,
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
616
|
+
create_table_options(table_data, compaction_strategy, is_compact)
|
617
|
+
|
618
|
+
table = Cassandra::Table.new(@schema.keyspace(keyspace_name),
|
619
|
+
table_name,
|
620
|
+
partition_key,
|
621
|
+
clustering_columns,
|
622
|
+
other_columns,
|
623
|
+
table_options,
|
624
|
+
clustering_order,
|
625
|
+
table_data['id'])
|
626
|
+
|
627
|
+
# Create Index objects and add them to the table.
|
628
|
+
index_rows.each do |column, row|
|
629
|
+
create_index(table, column, row)
|
630
|
+
end
|
631
|
+
table
|
564
632
|
end
|
565
633
|
|
566
634
|
def select_keyspace(connection, keyspace_name)
|
@@ -596,10 +664,10 @@ module Cassandra
|
|
596
664
|
def create_table_options(table_data, compaction_strategy, is_compact)
|
597
665
|
compression_parameters = ::JSON.load(table_data['compression_parameters'])
|
598
666
|
if compression_parameters['sstable_compression']
|
599
|
-
compression_parameters['sstable_compression']
|
600
|
-
|
667
|
+
compression_parameters['sstable_compression']
|
668
|
+
.slice!(COMPRESSION_PACKAGE_PREFIX)
|
601
669
|
end
|
602
|
-
|
670
|
+
Cassandra::ColumnContainer::Options.new(
|
603
671
|
table_data['comment'],
|
604
672
|
table_data['read_repair_chance'],
|
605
673
|
table_data['local_read_repair_chance'],
|
@@ -616,7 +684,9 @@ module Cassandra
|
|
616
684
|
nil,
|
617
685
|
compaction_strategy,
|
618
686
|
compression_parameters,
|
619
|
-
is_compact
|
687
|
+
is_compact,
|
688
|
+
table_data['crc_check_chance'],
|
689
|
+
table_data['extensions']
|
620
690
|
)
|
621
691
|
end
|
622
692
|
end
|
@@ -624,11 +694,11 @@ module Cassandra
|
|
624
694
|
class V2_1_x < V2_0_x
|
625
695
|
SELECT_TYPES = 'SELECT * FROM system.schema_usertypes'.freeze
|
626
696
|
SELECT_KEYSPACE_TYPES =
|
627
|
-
|
697
|
+
'SELECT * FROM system.schema_usertypes WHERE keyspace_name = ?'.freeze
|
628
698
|
SELECT_TYPE =
|
629
|
-
|
630
|
-
|
631
|
-
|
699
|
+
'SELECT * ' \
|
700
|
+
'FROM system.schema_usertypes ' \
|
701
|
+
'WHERE keyspace_name = ? AND type_name = ?'.freeze
|
632
702
|
|
633
703
|
private
|
634
704
|
|
@@ -668,10 +738,10 @@ module Cassandra
|
|
668
738
|
def create_table_options(table_data, compaction_strategy, is_compact)
|
669
739
|
compression_parameters = ::JSON.load(table_data['compression_parameters'])
|
670
740
|
if compression_parameters['sstable_compression']
|
671
|
-
compression_parameters['sstable_compression']
|
672
|
-
|
741
|
+
compression_parameters['sstable_compression']
|
742
|
+
.slice!(COMPRESSION_PACKAGE_PREFIX)
|
673
743
|
end
|
674
|
-
|
744
|
+
Cassandra::ColumnContainer::Options.new(
|
675
745
|
table_data['comment'],
|
676
746
|
table_data['read_repair_chance'],
|
677
747
|
table_data['local_read_repair_chance'],
|
@@ -688,7 +758,9 @@ module Cassandra
|
|
688
758
|
table_data['max_index_interval'],
|
689
759
|
compaction_strategy,
|
690
760
|
compression_parameters,
|
691
|
-
is_compact
|
761
|
+
is_compact,
|
762
|
+
table_data['crc_check_chance'],
|
763
|
+
table_data['extensions']
|
692
764
|
)
|
693
765
|
end
|
694
766
|
end
|
@@ -697,19 +769,19 @@ module Cassandra
|
|
697
769
|
SELECT_FUNCTIONS = 'SELECT * FROM system.schema_functions'.freeze
|
698
770
|
SELECT_AGGREGATES = 'SELECT * FROM system.schema_aggregates'.freeze
|
699
771
|
SELECT_KEYSPACE_FUNCTIONS =
|
700
|
-
|
772
|
+
'SELECT * FROM system.schema_functions WHERE keyspace_name = ?'.freeze
|
701
773
|
SELECT_KEYSPACE_AGGREGATES =
|
702
|
-
|
774
|
+
'SELECT * FROM system.schema_aggregates WHERE keyspace_name = ?'.freeze
|
703
775
|
SELECT_FUNCTION =
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
776
|
+
'SELECT * ' \
|
777
|
+
'FROM system.schema_functions ' \
|
778
|
+
'WHERE keyspace_name = ? AND function_name = ? ' \
|
779
|
+
'AND argument_types = ?'.freeze
|
708
780
|
SELECT_AGGREGATE =
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
781
|
+
'SELECT * ' \
|
782
|
+
'FROM system.schema_aggregates ' \
|
783
|
+
'WHERE keyspace_name = ? AND aggregate_name = ? ' \
|
784
|
+
'AND argument_types = ?'.freeze
|
713
785
|
|
714
786
|
# parse an array of string argument types and return an array of
|
715
787
|
# [Cassandra::Type]s.
|
@@ -730,41 +802,41 @@ module Cassandra
|
|
730
802
|
function_name = function_data['function_name']
|
731
803
|
function_lang = function_data['language']
|
732
804
|
function_type =
|
733
|
-
|
805
|
+
@type_parser.parse(function_data['return_type']).results.first.first
|
734
806
|
function_body = function_data['body']
|
735
807
|
called_on_null = function_data['called_on_null_input']
|
736
808
|
|
737
809
|
arguments = []
|
738
810
|
|
739
|
-
Array(function_data['argument_names'])
|
740
|
-
|
811
|
+
Array(function_data['argument_names'])
|
812
|
+
.zip(Array(function_data['argument_types'])) do |argument_name, fqcn|
|
741
813
|
argument_type = @type_parser.parse(fqcn).results.first.first
|
742
814
|
arguments << Argument.new(argument_name, argument_type)
|
743
815
|
end
|
744
816
|
|
745
|
-
Function.new(keyspace_name,
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
817
|
+
Cassandra::Function.new(keyspace_name,
|
818
|
+
function_name,
|
819
|
+
function_lang,
|
820
|
+
function_type,
|
821
|
+
arguments,
|
822
|
+
function_body,
|
823
|
+
called_on_null)
|
752
824
|
end
|
753
825
|
|
754
826
|
def create_aggregate(aggregate_data, functions)
|
755
827
|
keyspace_name = aggregate_data['keyspace_name']
|
756
828
|
aggregate_name = aggregate_data['aggregate_name']
|
757
829
|
aggregate_type =
|
758
|
-
|
830
|
+
@type_parser.parse(aggregate_data['return_type']).results.first.first
|
759
831
|
argument_types = aggregate_data['argument_types'].map do |fqcn|
|
760
832
|
@type_parser.parse(fqcn).results.first.first
|
761
833
|
end.freeze
|
762
834
|
state_type =
|
763
|
-
|
835
|
+
@type_parser.parse(aggregate_data['state_type']).results.first.first
|
764
836
|
initial_state = Util.encode_object(
|
765
|
-
|
766
|
-
|
767
|
-
|
837
|
+
Protocol::Coder.read_value_v4(
|
838
|
+
Protocol::CqlByteBuffer.new.append_bytes(aggregate_data['initcond']),
|
839
|
+
state_type))
|
768
840
|
|
769
841
|
# The state-function takes arguments: first the stype, then the args of the aggregate.
|
770
842
|
state_function = functions.get(aggregate_data['state_func'],
|
@@ -818,53 +890,66 @@ module Cassandra
|
|
818
890
|
end
|
819
891
|
|
820
892
|
class V3_0_x < V2_2_x
|
821
|
-
SELECT_KEYSPACES =
|
822
|
-
SELECT_TABLES =
|
823
|
-
SELECT_COLUMNS =
|
824
|
-
SELECT_TYPES =
|
825
|
-
SELECT_FUNCTIONS =
|
826
|
-
SELECT_AGGREGATES =
|
827
|
-
SELECT_INDEXES =
|
828
|
-
SELECT_VIEWS =
|
893
|
+
SELECT_KEYSPACES = 'SELECT * FROM system_schema.keyspaces'.freeze
|
894
|
+
SELECT_TABLES = 'SELECT * FROM system_schema.tables'.freeze
|
895
|
+
SELECT_COLUMNS = 'SELECT * FROM system_schema.columns'.freeze
|
896
|
+
SELECT_TYPES = 'SELECT * FROM system_schema.types'.freeze
|
897
|
+
SELECT_FUNCTIONS = 'SELECT * FROM system_schema.functions'.freeze
|
898
|
+
SELECT_AGGREGATES = 'SELECT * FROM system_schema.aggregates'.freeze
|
899
|
+
SELECT_INDEXES = 'SELECT * FROM system_schema.indexes'.freeze
|
900
|
+
SELECT_VIEWS = 'SELECT * FROM system_schema.views'.freeze
|
829
901
|
|
830
902
|
SELECT_KEYSPACE =
|
831
|
-
|
903
|
+
'SELECT * FROM system_schema.keyspaces WHERE keyspace_name = ?'.freeze
|
832
904
|
SELECT_KEYSPACE_TABLES =
|
833
|
-
|
905
|
+
'SELECT * FROM system_schema.tables WHERE keyspace_name = ?'.freeze
|
906
|
+
SELECT_KEYSPACE_INDEXES =
|
907
|
+
'SELECT * FROM system_schema.indexes WHERE keyspace_name = ?'.freeze
|
834
908
|
SELECT_KEYSPACE_COLUMNS =
|
835
|
-
|
909
|
+
'SELECT * FROM system_schema.columns WHERE keyspace_name = ?'.freeze
|
910
|
+
SELECT_KEYSPACE_VIEWS =
|
911
|
+
'SELECT * FROM system_schema.views WHERE keyspace_name = ?'.freeze
|
836
912
|
SELECT_KEYSPACE_TYPES =
|
837
|
-
|
913
|
+
'SELECT * FROM system_schema.types WHERE keyspace_name = ?'.freeze
|
838
914
|
SELECT_KEYSPACE_FUNCTIONS =
|
839
|
-
|
915
|
+
'SELECT * FROM system_schema.functions WHERE keyspace_name = ?'.freeze
|
840
916
|
SELECT_KEYSPACE_AGGREGATES =
|
841
|
-
|
917
|
+
'SELECT * FROM system_schema.aggregates WHERE keyspace_name = ?'.freeze
|
842
918
|
|
843
919
|
SELECT_TABLE =
|
844
|
-
|
845
|
-
|
846
|
-
|
920
|
+
'SELECT * ' \
|
921
|
+
'FROM system_schema.tables ' \
|
922
|
+
'WHERE keyspace_name = ? AND table_name = ?'.freeze
|
847
923
|
SELECT_TABLE_COLUMNS =
|
848
|
-
|
849
|
-
|
850
|
-
|
924
|
+
'SELECT * ' \
|
925
|
+
'FROM system_schema.columns ' \
|
926
|
+
'WHERE keyspace_name = ? AND table_name = ?'.freeze
|
927
|
+
SELECT_TABLE_INDEXES =
|
928
|
+
'SELECT * ' \
|
929
|
+
'FROM system_schema.indexes ' \
|
930
|
+
'WHERE keyspace_name = ? AND table_name = ?'.freeze
|
931
|
+
|
932
|
+
SELECT_VIEW =
|
933
|
+
'SELECT * ' \
|
934
|
+
'FROM system_schema.views ' \
|
935
|
+
'WHERE keyspace_name = ? AND view_name = ?'.freeze
|
851
936
|
|
852
937
|
SELECT_TYPE =
|
853
|
-
|
854
|
-
|
855
|
-
|
938
|
+
'SELECT * ' \
|
939
|
+
'FROM system_schema.types ' \
|
940
|
+
'WHERE keyspace_name = ? AND type_name = ?'.freeze
|
856
941
|
|
857
942
|
SELECT_FUNCTION =
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
943
|
+
'SELECT * ' \
|
944
|
+
'FROM system_schema.functions ' \
|
945
|
+
'WHERE keyspace_name = ? AND function_name = ? ' \
|
946
|
+
'AND argument_types = ?'.freeze
|
862
947
|
|
863
948
|
SELECT_AGGREGATE =
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
949
|
+
'SELECT * ' \
|
950
|
+
'FROM system_schema.aggregates ' \
|
951
|
+
'WHERE keyspace_name = ? AND aggregate_name = ? ' \
|
952
|
+
'AND argument_types = ?'.freeze
|
868
953
|
|
869
954
|
# parse an array of string argument types and return an array of
|
870
955
|
# [Cassandra::Type]s.
|
@@ -889,6 +974,14 @@ module Cassandra
|
|
889
974
|
send_select_request(connection, SELECT_TABLES)
|
890
975
|
end
|
891
976
|
|
977
|
+
def select_indexes(connection)
|
978
|
+
send_select_request(connection, SELECT_INDEXES)
|
979
|
+
end
|
980
|
+
|
981
|
+
def select_materialized_views(connection)
|
982
|
+
send_select_request(connection, SELECT_VIEWS)
|
983
|
+
end
|
984
|
+
|
892
985
|
def select_columns(connection)
|
893
986
|
send_select_request(connection, SELECT_COLUMNS)
|
894
987
|
end
|
@@ -923,6 +1016,18 @@ module Cassandra
|
|
923
1016
|
send_select_request(connection, SELECT_KEYSPACE_COLUMNS, params, hints)
|
924
1017
|
end
|
925
1018
|
|
1019
|
+
def select_keyspace_indexes(connection, keyspace_name)
|
1020
|
+
params = [keyspace_name]
|
1021
|
+
hints = [Types.varchar]
|
1022
|
+
send_select_request(connection, SELECT_KEYSPACE_INDEXES, params, hints)
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
def select_keyspace_materialized_views(connection, keyspace_name)
|
1026
|
+
params = [keyspace_name]
|
1027
|
+
hints = [Types.varchar]
|
1028
|
+
send_select_request(connection, SELECT_KEYSPACE_VIEWS, params, hints)
|
1029
|
+
end
|
1030
|
+
|
926
1031
|
def select_keyspace_types(connection, keyspace_name)
|
927
1032
|
params = [keyspace_name]
|
928
1033
|
hints = [Types.varchar]
|
@@ -948,11 +1053,26 @@ module Cassandra
|
|
948
1053
|
end
|
949
1054
|
|
950
1055
|
def select_table_columns(connection, keyspace_name, table_name)
|
1056
|
+
# This is identical to the 2.0 impl, but the SELECT_TABLE_COLUMNS query
|
1057
|
+
# is different between the two, so we need two impls. :(
|
1058
|
+
# Also, this method works fine for finding view columns as well.
|
951
1059
|
params = [keyspace_name, table_name]
|
952
1060
|
hints = [Types.varchar, Types.varchar]
|
953
1061
|
send_select_request(connection, SELECT_TABLE_COLUMNS, params, hints)
|
954
1062
|
end
|
955
1063
|
|
1064
|
+
def select_table_indexes(connection, keyspace_name, table_name)
|
1065
|
+
params = [keyspace_name, table_name]
|
1066
|
+
hints = [Types.varchar, Types.varchar]
|
1067
|
+
send_select_request(connection, SELECT_TABLE_INDEXES, params, hints)
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
def select_materialized_view(connection, keyspace_name, view_name)
|
1071
|
+
params = [keyspace_name, view_name]
|
1072
|
+
hints = [Types.varchar, Types.varchar]
|
1073
|
+
send_select_request(connection, SELECT_VIEW, params, hints)
|
1074
|
+
end
|
1075
|
+
|
956
1076
|
def select_type(connection, keyspace_name, type_name)
|
957
1077
|
params = [keyspace_name, type_name]
|
958
1078
|
hints = [Types.varchar, Types.varchar]
|
@@ -982,19 +1102,19 @@ module Cassandra
|
|
982
1102
|
|
983
1103
|
arguments = []
|
984
1104
|
|
985
|
-
function_data['argument_names']
|
986
|
-
|
1105
|
+
function_data['argument_names']
|
1106
|
+
.zip(function_data['argument_types']) do |argument_name, argument_type|
|
987
1107
|
arguments << Argument.new(argument_name,
|
988
1108
|
@type_parser.parse(argument_type, types).first)
|
989
1109
|
end
|
990
1110
|
|
991
|
-
Function.new(keyspace_name,
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
1111
|
+
Cassandra::Function.new(keyspace_name,
|
1112
|
+
function_name,
|
1113
|
+
function_lang,
|
1114
|
+
function_type,
|
1115
|
+
arguments,
|
1116
|
+
function_body,
|
1117
|
+
called_on_null)
|
998
1118
|
end
|
999
1119
|
|
1000
1120
|
def create_aggregate(aggregate_data, functions, types = nil)
|
@@ -1002,7 +1122,7 @@ module Cassandra
|
|
1002
1122
|
aggregate_name = aggregate_data['aggregate_name']
|
1003
1123
|
types ||= @schema.keyspace(keyspace_name).send(:raw_types)
|
1004
1124
|
aggregate_type =
|
1005
|
-
|
1125
|
+
@type_parser.parse(aggregate_data['return_type'], types).first
|
1006
1126
|
argument_types = aggregate_data['argument_types'].map do |argument_type|
|
1007
1127
|
@type_parser.parse(argument_type, types).first
|
1008
1128
|
end.freeze
|
@@ -1057,16 +1177,14 @@ module Cassandra
|
|
1057
1177
|
|
1058
1178
|
break if skipped_rows.empty?
|
1059
1179
|
|
1060
|
-
if rows_size == skipped_rows.size
|
1061
|
-
|
1062
|
-
|
1063
|
-
rows_types, skipped_rows = skipped_rows, rows_types
|
1064
|
-
end
|
1180
|
+
raise 'Unable to resolve circular references among UDTs when parsing' if rows_size == skipped_rows.size
|
1181
|
+
|
1182
|
+
rows_types, skipped_rows = skipped_rows, rows_types
|
1065
1183
|
end
|
1066
1184
|
end
|
1067
1185
|
|
1068
|
-
def create_keyspace(keyspace_data, rows_tables, rows_columns,
|
1069
|
-
|
1186
|
+
def create_keyspace(keyspace_data, rows_tables, rows_columns, rows_types,
|
1187
|
+
rows_functions, rows_aggregates, rows_views, rows_indexes)
|
1070
1188
|
keyspace_name = keyspace_data['keyspace_name']
|
1071
1189
|
replication = create_replication(keyspace_data)
|
1072
1190
|
|
@@ -1084,10 +1202,25 @@ module Cassandra
|
|
1084
1202
|
aggregates.add_or_update(create_aggregate(row, functions, types))
|
1085
1203
|
end
|
1086
1204
|
|
1205
|
+
# lookup_columns is a hash of <table-name, rows_columns for that table>.
|
1206
|
+
# However, views are analogous to tables in this context, so we get
|
1207
|
+
# view columns organized by view-name also.
|
1208
|
+
|
1087
1209
|
lookup_columns = map_rows_by(rows_columns, 'table_name')
|
1088
|
-
|
1210
|
+
lookup_indexes = map_rows_by(rows_indexes, 'table_name')
|
1211
|
+
tables = rows_tables.each_with_object({}) do |row, h|
|
1089
1212
|
table_name = row['table_name']
|
1090
|
-
|
1213
|
+
h[table_name] = create_table(row, lookup_columns[table_name],
|
1214
|
+
lookup_indexes[table_name], types)
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
views = rows_views.each_with_object({}) do |row, h|
|
1218
|
+
view_name = row['view_name']
|
1219
|
+
base_table = tables[row['base_table_name']]
|
1220
|
+
h[view_name] = create_materialized_view(row,
|
1221
|
+
lookup_columns[view_name],
|
1222
|
+
base_table,
|
1223
|
+
types)
|
1091
1224
|
end
|
1092
1225
|
|
1093
1226
|
Keyspace.new(keyspace_name,
|
@@ -1096,7 +1229,8 @@ module Cassandra
|
|
1096
1229
|
tables,
|
1097
1230
|
types,
|
1098
1231
|
functions,
|
1099
|
-
aggregates
|
1232
|
+
aggregates,
|
1233
|
+
views)
|
1100
1234
|
end
|
1101
1235
|
|
1102
1236
|
def create_replication(keyspace_data)
|
@@ -1110,16 +1244,14 @@ module Cassandra
|
|
1110
1244
|
options = table_data['compaction']
|
1111
1245
|
klass = options.delete('class')
|
1112
1246
|
klass.slice!('org.apache.cassandra.db.compaction.')
|
1113
|
-
|
1247
|
+
ColumnContainer::Compaction.new(klass, options)
|
1114
1248
|
end
|
1115
1249
|
|
1116
1250
|
def create_table_options(table_data, compaction_strategy, is_compact)
|
1117
1251
|
compression = table_data['compression']
|
1118
|
-
if compression['class']
|
1119
|
-
compression['class'].slice!(COMPRESSION_PACKAGE_PREFIX)
|
1120
|
-
end
|
1252
|
+
compression['class'].slice!(COMPRESSION_PACKAGE_PREFIX) if compression['class']
|
1121
1253
|
|
1122
|
-
|
1254
|
+
Cassandra::ColumnContainer::Options.new(
|
1123
1255
|
table_data['comment'],
|
1124
1256
|
table_data['read_repair_chance'],
|
1125
1257
|
table_data['dclocal_read_repair_chance'],
|
@@ -1136,82 +1268,146 @@ module Cassandra
|
|
1136
1268
|
table_data['max_index_interval'],
|
1137
1269
|
compaction_strategy,
|
1138
1270
|
compression,
|
1139
|
-
is_compact
|
1271
|
+
is_compact,
|
1272
|
+
table_data['crc_check_chance'],
|
1273
|
+
table_data['extensions']
|
1140
1274
|
)
|
1141
1275
|
end
|
1142
1276
|
|
1143
1277
|
def create_column(column_data, types)
|
1144
1278
|
name = column_data['column_name']
|
1145
|
-
is_static =
|
1279
|
+
is_static = column_data['kind'].to_s.casecmp('STATIC').zero?
|
1146
1280
|
order = column_data['clustering_order'] == 'desc' ? :desc : :asc
|
1147
|
-
|
1281
|
+
if column_data['type'][0] == "'"
|
1282
|
+
# This is a custom column type.
|
1283
|
+
type = Types.custom(column_data['type'].slice(1, column_data['type'].length - 2))
|
1284
|
+
is_frozen = false
|
1285
|
+
else
|
1286
|
+
type, is_frozen = @type_parser.parse(column_data['type'], types)
|
1287
|
+
end
|
1148
1288
|
|
1149
|
-
Column.new(name, type, order,
|
1289
|
+
Column.new(name, type, order, is_static, is_frozen)
|
1150
1290
|
end
|
1151
1291
|
|
1152
|
-
def create_table(table_data, rows_columns, types = nil)
|
1292
|
+
def create_table(table_data, rows_columns, rows_indexes, types = nil)
|
1153
1293
|
keyspace_name = table_data['keyspace_name']
|
1154
1294
|
table_name = table_data['table_name']
|
1155
1295
|
table_flags = table_data['flags']
|
1156
|
-
table_columns = {}
|
1157
|
-
other_columns = []
|
1158
|
-
clustering_size = 0
|
1159
1296
|
|
1160
1297
|
is_dense = table_flags.include?('dense')
|
1161
1298
|
is_super = table_flags.include?('super')
|
1162
1299
|
is_compound = table_flags.include?('compound')
|
1163
1300
|
is_compact = is_super || is_dense || !is_compound
|
1301
|
+
is_static_compact = !is_super && !is_dense && !is_compound
|
1164
1302
|
|
1303
|
+
# Separate out partition-key, clustering columns, other columns.
|
1165
1304
|
partition_key = []
|
1166
1305
|
clustering_columns = []
|
1167
1306
|
clustering_order = []
|
1168
|
-
|
1307
|
+
other_columns = []
|
1308
|
+
types ||= @schema.keyspace(keyspace_name).send(:raw_types)
|
1169
1309
|
|
1170
1310
|
rows_columns.each do |row|
|
1171
1311
|
next if row['column_name'].empty?
|
1172
1312
|
|
1173
|
-
column = create_column(row, types)
|
1174
1313
|
kind = row['kind'].to_s
|
1175
1314
|
index = row['position'] || 0
|
1176
1315
|
|
1316
|
+
if is_static_compact
|
1317
|
+
if kind.casecmp('CLUSTERING').zero? || kind.casecmp('REGULAR').zero?
|
1318
|
+
# Skip clustering columns in static-compact tables; they are internal to C*.
|
1319
|
+
# Oddly so are regular columns.
|
1320
|
+
next
|
1321
|
+
end
|
1322
|
+
if kind.casecmp('STATIC').zero?
|
1323
|
+
# Coerce static type to regular.
|
1324
|
+
kind = 'REGULAR'
|
1325
|
+
row['kind'] = 'regular'
|
1326
|
+
end
|
1327
|
+
end
|
1328
|
+
|
1329
|
+
column = create_column(row, types)
|
1177
1330
|
case kind.upcase
|
1178
1331
|
when 'PARTITION_KEY'
|
1179
1332
|
partition_key[index] = column
|
1180
1333
|
when 'CLUSTERING'
|
1181
1334
|
clustering_columns[index] = column
|
1182
1335
|
clustering_order[index] = column.order
|
1183
|
-
|
1184
|
-
if clustering_size.zero? || index == clustering_size
|
1185
|
-
clustering_size = index + 1
|
1186
|
-
end
|
1187
1336
|
else
|
1188
1337
|
other_columns << column
|
1189
1338
|
end
|
1190
1339
|
end
|
1191
1340
|
|
1192
|
-
|
1193
|
-
|
1341
|
+
# Default the crc_check_chance to 1.0 (Java driver does this, so we
|
1342
|
+
# should, too).
|
1343
|
+
table_data['crc_check_chance'] ||= 1.0
|
1344
|
+
compaction_strategy = create_compaction_strategy(table_data)
|
1345
|
+
table_options =
|
1346
|
+
create_table_options(table_data, compaction_strategy, is_compact)
|
1347
|
+
|
1348
|
+
table = Cassandra::Table.new(@schema.keyspace(keyspace_name),
|
1349
|
+
table_name,
|
1350
|
+
partition_key,
|
1351
|
+
clustering_columns,
|
1352
|
+
other_columns,
|
1353
|
+
table_options,
|
1354
|
+
clustering_order,
|
1355
|
+
table_data['id'])
|
1356
|
+
rows_indexes.each do |row|
|
1357
|
+
create_index(table, row)
|
1194
1358
|
end
|
1359
|
+
table
|
1360
|
+
end
|
1195
1361
|
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1362
|
+
def create_index(table, row_index)
|
1363
|
+
options = row_index['options']
|
1364
|
+
table.add_index(Cassandra::Index.new(table, row_index['index_name'],
|
1365
|
+
row_index['kind'].downcase.to_sym,
|
1366
|
+
options['target'], options))
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
def create_materialized_view(view_data, rows_columns, base_table, types = nil)
|
1370
|
+
keyspace_name = view_data['keyspace_name']
|
1371
|
+
view_name = view_data['view_name']
|
1372
|
+
include_all_columns = view_data['include_all_columns']
|
1373
|
+
where_clause = view_data['where_clause']
|
1199
1374
|
|
1200
|
-
|
1201
|
-
|
1375
|
+
# Separate out partition key, clustering columns, other columns
|
1376
|
+
partition_key = []
|
1377
|
+
clustering_columns = []
|
1378
|
+
other_columns = []
|
1379
|
+
types ||= @schema.keyspace(keyspace_name).send(:raw_types)
|
1380
|
+
|
1381
|
+
rows_columns.each do |row|
|
1382
|
+
next if row['column_name'].empty?
|
1383
|
+
|
1384
|
+
column = create_column(row, types)
|
1385
|
+
kind = row['kind'].to_s
|
1386
|
+
index = row['position'] || 0
|
1387
|
+
|
1388
|
+
case kind.upcase
|
1389
|
+
when 'PARTITION_KEY'
|
1390
|
+
partition_key[index] = column
|
1391
|
+
when 'CLUSTERING'
|
1392
|
+
clustering_columns[index] = column
|
1393
|
+
else
|
1394
|
+
other_columns << column
|
1395
|
+
end
|
1202
1396
|
end
|
1203
1397
|
|
1204
|
-
compaction_strategy = create_compaction_strategy(
|
1205
|
-
|
1206
|
-
create_table_options(table_data, compaction_strategy, is_compact)
|
1398
|
+
compaction_strategy = create_compaction_strategy(view_data)
|
1399
|
+
view_options = create_table_options(view_data, compaction_strategy, false)
|
1207
1400
|
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1401
|
+
MaterializedView.new(@schema.keyspace(keyspace_name),
|
1402
|
+
view_name,
|
1403
|
+
partition_key,
|
1404
|
+
clustering_columns,
|
1405
|
+
other_columns,
|
1406
|
+
view_options,
|
1407
|
+
include_all_columns,
|
1408
|
+
where_clause,
|
1409
|
+
base_table,
|
1410
|
+
view_data['id'])
|
1215
1411
|
end
|
1216
1412
|
end
|
1217
1413
|
|
@@ -1263,6 +1459,13 @@ module Cassandra
|
|
1263
1459
|
return Ione::Future.failed(e)
|
1264
1460
|
end
|
1265
1461
|
|
1462
|
+
def fetch_materialized_view(connection, keyspace_name, view_name)
|
1463
|
+
find_fetcher(connection)
|
1464
|
+
.fetch_materialized_view(connection, keyspace_name, view_name)
|
1465
|
+
rescue => e
|
1466
|
+
return Ione::Future.failed(e)
|
1467
|
+
end
|
1468
|
+
|
1266
1469
|
def fetch_type(connection, keyspace_name, type_name)
|
1267
1470
|
find_fetcher(connection)
|
1268
1471
|
.fetch_type(connection, keyspace_name, type_name)
|
@@ -1304,21 +1507,21 @@ module Cassandra
|
|
1304
1507
|
unless host
|
1305
1508
|
ips = @registry.hosts.map(&:ip)
|
1306
1509
|
raise Errors::ClientError,
|
1307
|
-
|
1510
|
+
'unable to find release version for current host, ' \
|
1308
1511
|
"connected to #{connection.host}, but cluster contains " \
|
1309
1512
|
"#{ips}."
|
1310
1513
|
end
|
1311
1514
|
|
1312
1515
|
version = host.release_version
|
1313
1516
|
unless version
|
1314
|
-
raise Errors::ClientError,
|
1517
|
+
raise Errors::ClientError, 'unable to determine release ' \
|
1315
1518
|
"version for host: #{host.inspect}"
|
1316
1519
|
end
|
1317
1520
|
|
1318
1521
|
@fetchers[version] ||= begin
|
1319
1522
|
current = @versions.find {|v| v.matches?(version)}
|
1320
1523
|
unless current
|
1321
|
-
raise Errors::ClientError,
|
1524
|
+
raise Errors::ClientError, 'unsupported release version ' \
|
1322
1525
|
"#{version.inspect}."
|
1323
1526
|
end
|
1324
1527
|
current.fetcher
|