cassandra-driver 3.0.0.rc.1-java → 3.0.0.rc.2-java
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
- 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
|