yugabyte-ycql-driver 3.2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +13 -0
  3. data/README.md +242 -0
  4. data/ext/cassandra_murmur3/cassandra_murmur3.c +178 -0
  5. data/ext/cassandra_murmur3/extconf.rb +2 -0
  6. data/lib/cassandra/address_resolution.rb +36 -0
  7. data/lib/cassandra/address_resolution/policies.rb +2 -0
  8. data/lib/cassandra/address_resolution/policies/ec2_multi_region.rb +56 -0
  9. data/lib/cassandra/address_resolution/policies/none.rb +35 -0
  10. data/lib/cassandra/aggregate.rb +123 -0
  11. data/lib/cassandra/argument.rb +51 -0
  12. data/lib/cassandra/attr_boolean.rb +33 -0
  13. data/lib/cassandra/auth.rb +100 -0
  14. data/lib/cassandra/auth/providers.rb +17 -0
  15. data/lib/cassandra/auth/providers/password.rb +65 -0
  16. data/lib/cassandra/cassandra_logger.rb +80 -0
  17. data/lib/cassandra/cluster.rb +331 -0
  18. data/lib/cassandra/cluster/client.rb +1612 -0
  19. data/lib/cassandra/cluster/connection_pool.rb +78 -0
  20. data/lib/cassandra/cluster/connector.rb +372 -0
  21. data/lib/cassandra/cluster/control_connection.rb +962 -0
  22. data/lib/cassandra/cluster/failed_connection.rb +35 -0
  23. data/lib/cassandra/cluster/metadata.rb +142 -0
  24. data/lib/cassandra/cluster/options.rb +145 -0
  25. data/lib/cassandra/cluster/registry.rb +284 -0
  26. data/lib/cassandra/cluster/schema.rb +405 -0
  27. data/lib/cassandra/cluster/schema/cql_type_parser.rb +112 -0
  28. data/lib/cassandra/cluster/schema/fetchers.rb +1627 -0
  29. data/lib/cassandra/cluster/schema/fqcn_type_parser.rb +175 -0
  30. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  31. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +45 -0
  32. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  33. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  34. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  35. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +102 -0
  36. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  37. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  38. data/lib/cassandra/column.rb +66 -0
  39. data/lib/cassandra/column_container.rb +326 -0
  40. data/lib/cassandra/compression.rb +69 -0
  41. data/lib/cassandra/compression/compressors/lz4.rb +73 -0
  42. data/lib/cassandra/compression/compressors/snappy.rb +69 -0
  43. data/lib/cassandra/custom_data.rb +53 -0
  44. data/lib/cassandra/driver.rb +260 -0
  45. data/lib/cassandra/errors.rb +784 -0
  46. data/lib/cassandra/execution/info.rb +69 -0
  47. data/lib/cassandra/execution/options.rb +267 -0
  48. data/lib/cassandra/execution/profile.rb +153 -0
  49. data/lib/cassandra/execution/profile_manager.rb +71 -0
  50. data/lib/cassandra/execution/trace.rb +192 -0
  51. data/lib/cassandra/executors.rb +113 -0
  52. data/lib/cassandra/function.rb +156 -0
  53. data/lib/cassandra/function_collection.rb +85 -0
  54. data/lib/cassandra/future.rb +794 -0
  55. data/lib/cassandra/host.rb +102 -0
  56. data/lib/cassandra/index.rb +118 -0
  57. data/lib/cassandra/keyspace.rb +473 -0
  58. data/lib/cassandra/listener.rb +87 -0
  59. data/lib/cassandra/load_balancing.rb +121 -0
  60. data/lib/cassandra/load_balancing/policies.rb +20 -0
  61. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +172 -0
  62. data/lib/cassandra/load_balancing/policies/round_robin.rb +141 -0
  63. data/lib/cassandra/load_balancing/policies/token_aware.rb +149 -0
  64. data/lib/cassandra/load_balancing/policies/white_list.rb +100 -0
  65. data/lib/cassandra/materialized_view.rb +92 -0
  66. data/lib/cassandra/null_logger.rb +56 -0
  67. data/lib/cassandra/protocol.rb +102 -0
  68. data/lib/cassandra/protocol/coder.rb +1085 -0
  69. data/lib/cassandra/protocol/cql_byte_buffer.rb +418 -0
  70. data/lib/cassandra/protocol/cql_protocol_handler.rb +448 -0
  71. data/lib/cassandra/protocol/request.rb +41 -0
  72. data/lib/cassandra/protocol/requests/auth_response_request.rb +51 -0
  73. data/lib/cassandra/protocol/requests/batch_request.rb +117 -0
  74. data/lib/cassandra/protocol/requests/credentials_request.rb +51 -0
  75. data/lib/cassandra/protocol/requests/execute_request.rb +122 -0
  76. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  77. data/lib/cassandra/protocol/requests/prepare_request.rb +59 -0
  78. data/lib/cassandra/protocol/requests/query_request.rb +112 -0
  79. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  80. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  81. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  82. data/lib/cassandra/protocol/response.rb +28 -0
  83. data/lib/cassandra/protocol/responses/already_exists_error_response.rb +50 -0
  84. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +36 -0
  85. data/lib/cassandra/protocol/responses/auth_success_response.rb +36 -0
  86. data/lib/cassandra/protocol/responses/authenticate_response.rb +36 -0
  87. data/lib/cassandra/protocol/responses/error_response.rb +142 -0
  88. data/lib/cassandra/protocol/responses/event_response.rb +30 -0
  89. data/lib/cassandra/protocol/responses/function_failure_error_response.rb +52 -0
  90. data/lib/cassandra/protocol/responses/prepared_result_response.rb +62 -0
  91. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +59 -0
  92. data/lib/cassandra/protocol/responses/read_failure_error_response.rb +71 -0
  93. data/lib/cassandra/protocol/responses/read_timeout_error_response.rb +61 -0
  94. data/lib/cassandra/protocol/responses/ready_response.rb +43 -0
  95. data/lib/cassandra/protocol/responses/result_response.rb +42 -0
  96. data/lib/cassandra/protocol/responses/rows_result_response.rb +39 -0
  97. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +73 -0
  98. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +70 -0
  99. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +37 -0
  100. data/lib/cassandra/protocol/responses/status_change_event_response.rb +39 -0
  101. data/lib/cassandra/protocol/responses/supported_response.rb +36 -0
  102. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +33 -0
  103. data/lib/cassandra/protocol/responses/unavailable_error_response.rb +58 -0
  104. data/lib/cassandra/protocol/responses/unprepared_error_response.rb +48 -0
  105. data/lib/cassandra/protocol/responses/void_result_response.rb +34 -0
  106. data/lib/cassandra/protocol/responses/write_failure_error_response.rb +73 -0
  107. data/lib/cassandra/protocol/responses/write_timeout_error_response.rb +63 -0
  108. data/lib/cassandra/protocol/v1.rb +326 -0
  109. data/lib/cassandra/protocol/v3.rb +358 -0
  110. data/lib/cassandra/protocol/v4.rb +478 -0
  111. data/lib/cassandra/reconnection.rb +49 -0
  112. data/lib/cassandra/reconnection/policies.rb +20 -0
  113. data/lib/cassandra/reconnection/policies/constant.rb +46 -0
  114. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  115. data/lib/cassandra/result.rb +276 -0
  116. data/lib/cassandra/retry.rb +154 -0
  117. data/lib/cassandra/retry/policies.rb +21 -0
  118. data/lib/cassandra/retry/policies/default.rb +53 -0
  119. data/lib/cassandra/retry/policies/downgrading_consistency.rb +73 -0
  120. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  121. data/lib/cassandra/session.rb +270 -0
  122. data/lib/cassandra/statement.rb +32 -0
  123. data/lib/cassandra/statements.rb +23 -0
  124. data/lib/cassandra/statements/batch.rb +146 -0
  125. data/lib/cassandra/statements/bound.rb +65 -0
  126. data/lib/cassandra/statements/prepared.rb +235 -0
  127. data/lib/cassandra/statements/simple.rb +118 -0
  128. data/lib/cassandra/statements/void.rb +38 -0
  129. data/lib/cassandra/table.rb +240 -0
  130. data/lib/cassandra/time.rb +103 -0
  131. data/lib/cassandra/time_uuid.rb +78 -0
  132. data/lib/cassandra/timestamp_generator.rb +37 -0
  133. data/lib/cassandra/timestamp_generator/simple.rb +38 -0
  134. data/lib/cassandra/timestamp_generator/ticking_on_duplicate.rb +58 -0
  135. data/lib/cassandra/trigger.rb +67 -0
  136. data/lib/cassandra/tuple.rb +131 -0
  137. data/lib/cassandra/types.rb +1704 -0
  138. data/lib/cassandra/udt.rb +443 -0
  139. data/lib/cassandra/util.rb +464 -0
  140. data/lib/cassandra/uuid.rb +110 -0
  141. data/lib/cassandra/uuid/generator.rb +212 -0
  142. data/lib/cassandra/version.rb +21 -0
  143. data/lib/datastax/cassandra.rb +47 -0
  144. data/lib/ycql.rb +842 -0
  145. metadata +243 -0
@@ -0,0 +1,1627 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ class Cluster
21
+ class Schema
22
+ # @private
23
+ module Fetcher
24
+ FUTURE_EMPTY_LIST = Ione::Future.resolved(EMPTY_LIST)
25
+ REPLICATION_PACKAGE_PREFIX = 'org.apache.cassandra.locator.'.freeze
26
+ COMPRESSION_PACKAGE_PREFIX = 'org.apache.cassandra.io.compress.'.freeze
27
+
28
+ def fetch(connection)
29
+ # rubocop:disable Metrics/LineLength
30
+ Ione::Future.all(select_keyspaces(connection),
31
+ select_tables(connection),
32
+ select_columns(connection),
33
+ select_types(connection),
34
+ select_functions(connection),
35
+ select_aggregates(connection),
36
+ select_materialized_views(connection),
37
+ select_indexes(connection),
38
+ select_triggers(connection))
39
+ .map do |rows_keyspaces, rows_tables, rows_columns, rows_types, rows_functions, rows_aggregates, rows_views, rows_indexes, rows_triggers|
40
+ lookup_tables = map_rows_by(rows_tables, 'keyspace_name')
41
+ lookup_columns = map_rows_by(rows_columns, 'keyspace_name')
42
+ lookup_types = map_rows_by(rows_types, 'keyspace_name')
43
+ lookup_functions = map_rows_by(rows_functions, 'keyspace_name')
44
+ lookup_aggregates = map_rows_by(rows_aggregates, 'keyspace_name')
45
+ lookup_views = map_rows_by(rows_views, 'keyspace_name')
46
+ lookup_indexes = map_rows_by(rows_indexes, 'keyspace_name')
47
+ lookup_triggers = map_rows_by(rows_triggers, 'keyspace_name')
48
+
49
+ rows_keyspaces.map do |keyspace_data|
50
+ name = keyspace_data['keyspace_name']
51
+
52
+ create_keyspace(keyspace_data,
53
+ lookup_tables[name],
54
+ lookup_columns[name],
55
+ lookup_types[name],
56
+ lookup_functions[name],
57
+ lookup_aggregates[name],
58
+ lookup_views[name],
59
+ lookup_indexes[name],
60
+ lookup_triggers[name])
61
+ end
62
+ end
63
+ end
64
+
65
+ def fetch_keyspace(connection, keyspace_name)
66
+ Ione::Future.all(select_keyspace(connection, keyspace_name),
67
+ select_keyspace_tables(connection, keyspace_name),
68
+ select_keyspace_columns(connection, keyspace_name),
69
+ select_keyspace_types(connection, keyspace_name),
70
+ select_keyspace_functions(connection, keyspace_name),
71
+ select_keyspace_aggregates(connection, keyspace_name),
72
+ select_keyspace_materialized_views(connection, keyspace_name),
73
+ select_keyspace_indexes(connection, keyspace_name),
74
+ select_keyspace_triggers(connection, keyspace_name))
75
+ .map do |rows_keyspaces, rows_tables, rows_columns, rows_types, rows_functions, rows_aggregates, rows_views, rows_indexes, rows_triggers|
76
+ if rows_keyspaces.empty?
77
+ nil
78
+ else
79
+ create_keyspace(rows_keyspaces.first,
80
+ rows_tables,
81
+ rows_columns,
82
+ rows_types,
83
+ rows_functions,
84
+ rows_aggregates,
85
+ rows_views,
86
+ rows_indexes,
87
+ rows_triggers)
88
+ end
89
+ end
90
+ end
91
+
92
+ def fetch_table(connection, keyspace_name, table_name)
93
+ Ione::Future.all(select_table(connection, keyspace_name, table_name),
94
+ select_table_columns(connection, keyspace_name, table_name),
95
+ select_table_indexes(connection, keyspace_name, table_name),
96
+ select_table_triggers(connection, keyspace_name, table_name))
97
+ .map do |(rows_tables, rows_columns, rows_indexes, rows_triggers)|
98
+ if rows_tables.empty?
99
+ nil
100
+ else
101
+ create_table(rows_tables.first,
102
+ rows_columns,
103
+ rows_indexes,
104
+ rows_triggers)
105
+ end
106
+ end
107
+ end
108
+
109
+ def fetch_materialized_view(connection, keyspace_name, view_name)
110
+ Ione::Future.all(select_materialized_view(connection, keyspace_name, view_name),
111
+ select_table_columns(connection, keyspace_name, view_name))
112
+ .map do |rows_views, rows_columns|
113
+ if rows_views.empty?
114
+ nil
115
+ else
116
+ view_row = rows_views.first
117
+ create_materialized_view(view_row,
118
+ rows_columns)
119
+ end
120
+ end
121
+ end
122
+
123
+ def fetch_type(connection, keyspace_name, type_name)
124
+ select_type(connection, keyspace_name, type_name).map do |rows_types|
125
+ if rows_types.empty?
126
+ nil
127
+ else
128
+ create_type(rows_types.first)
129
+ end
130
+ end
131
+ end
132
+
133
+ def fetch_function(connection, keyspace_name, function_name, function_args)
134
+ select_function(connection, keyspace_name, function_name, function_args)
135
+ .map do |rows_functions|
136
+ if rows_functions.empty?
137
+ nil
138
+ else
139
+ create_function(rows_functions.first)
140
+ end
141
+ end
142
+ end
143
+
144
+ def fetch_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
145
+ select_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
146
+ .map do |rows_aggregates|
147
+ if rows_aggregates.empty?
148
+ nil
149
+ else
150
+ create_aggregate(rows_aggregates.first, @schema.keyspace(keyspace_name)
151
+ .send(:raw_functions))
152
+ end
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def select_keyspaces(connection)
159
+ FUTURE_EMPTY_LIST
160
+ end
161
+
162
+ def select_tables(connection)
163
+ FUTURE_EMPTY_LIST
164
+ end
165
+
166
+ def select_materialized_views(connection)
167
+ FUTURE_EMPTY_LIST
168
+ end
169
+
170
+ def select_columns(connection)
171
+ FUTURE_EMPTY_LIST
172
+ end
173
+
174
+ def select_indexes(connection)
175
+ FUTURE_EMPTY_LIST
176
+ end
177
+
178
+ def select_triggers(connection)
179
+ FUTURE_EMPTY_LIST
180
+ end
181
+
182
+ def select_types(connection)
183
+ FUTURE_EMPTY_LIST
184
+ end
185
+
186
+ def select_functions(connection)
187
+ FUTURE_EMPTY_LIST
188
+ end
189
+
190
+ def select_aggregates(connection)
191
+ FUTURE_EMPTY_LIST
192
+ end
193
+
194
+ def select_keyspace(connection, keyspace_name)
195
+ FUTURE_EMPTY_LIST
196
+ end
197
+
198
+ def select_keyspace_tables(connection, keyspace_name)
199
+ FUTURE_EMPTY_LIST
200
+ end
201
+
202
+ def select_keyspace_materialized_views(connection, keyspace_name)
203
+ FUTURE_EMPTY_LIST
204
+ end
205
+
206
+ def select_keyspace_columns(connection, keyspace_name)
207
+ FUTURE_EMPTY_LIST
208
+ end
209
+
210
+ def select_keyspace_indexes(connection, keyspace_name)
211
+ FUTURE_EMPTY_LIST
212
+ end
213
+
214
+ def select_keyspace_triggers(connection, keyspace_name)
215
+ FUTURE_EMPTY_LIST
216
+ end
217
+
218
+ def select_keyspace_types(connection, keyspace_name)
219
+ FUTURE_EMPTY_LIST
220
+ end
221
+
222
+ def select_keyspace_functions(connection, keyspace_name)
223
+ FUTURE_EMPTY_LIST
224
+ end
225
+
226
+ def select_keyspace_aggregates(connection, keyspace_name)
227
+ FUTURE_EMPTY_LIST
228
+ end
229
+
230
+ def select_table(connection, keyspace_name, table_name)
231
+ FUTURE_EMPTY_LIST
232
+ end
233
+
234
+ def select_materialized_view(connection, keyspace_name, view_name)
235
+ FUTURE_EMPTY_LIST
236
+ end
237
+
238
+ def select_table_columns(connection, keyspace_name, table_name)
239
+ FUTURE_EMPTY_LIST
240
+ end
241
+
242
+ def select_table_indexes(connection, keyspace_name, table_name)
243
+ FUTURE_EMPTY_LIST
244
+ end
245
+
246
+ def select_table_triggers(connection, keyspace_name, table_name)
247
+ FUTURE_EMPTY_LIST
248
+ end
249
+
250
+ def select_type(connection, keyspace_name, type_name)
251
+ FUTURE_EMPTY_LIST
252
+ end
253
+
254
+ def select_function(connection, keyspace_name, function_name, function_args)
255
+ FUTURE_EMPTY_LIST
256
+ end
257
+
258
+ def select_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
259
+ FUTURE_EMPTY_LIST
260
+ end
261
+
262
+ def send_select_request(connection, cql, params = EMPTY_LIST, types = EMPTY_LIST)
263
+ backtrace = caller
264
+ connection.send_request(
265
+ Protocol::QueryRequest.new(cql, params, types, :quorum)
266
+ ).map do |r|
267
+ case r
268
+ when Protocol::RowsResultResponse
269
+ r.rows
270
+ when Protocol::ErrorResponse
271
+ e = r.to_error(nil, VOID_STATEMENT, VOID_OPTIONS, EMPTY_LIST, :quorum, 0)
272
+ e.set_backtrace(backtrace)
273
+ raise e
274
+ else
275
+ raise Errors::InternalError, "Unexpected response #{r.inspect}", caller
276
+ end
277
+ end
278
+ end
279
+
280
+ def map_rows_by(rows, key_name, &block)
281
+ rows.each_with_object(::Hash.new { EMPTY_LIST }) do |row, map|
282
+ key = row[key_name]
283
+ map[key] = [] unless map.key?(key)
284
+
285
+ map[key] << if block
286
+ yield(row)
287
+ else
288
+ row
289
+ end
290
+ end
291
+ end
292
+ end
293
+
294
+ # @private
295
+ module Fetchers
296
+ # rubocop:disable Naming/ClassAndModuleCamelCase
297
+ class V1_2_x
298
+ SELECT_KEYSPACES = 'SELECT * FROM system.schema_keyspaces'.freeze
299
+ SELECT_TABLES = 'SELECT * FROM system.schema_columnfamilies'.freeze
300
+ SELECT_COLUMNS = 'SELECT * FROM system.schema_columns'.freeze
301
+ SELECT_KEYSPACE =
302
+ 'SELECT * ' \
303
+ 'FROM system.schema_keyspaces ' \
304
+ 'WHERE keyspace_name = \'%s\''.freeze
305
+ SELECT_KEYSPACE_TABLES =
306
+ 'SELECT * ' \
307
+ 'FROM system.schema_columnfamilies ' \
308
+ 'WHERE keyspace_name = \'%s\''.freeze
309
+ SELECT_KEYSPACE_COLUMNS =
310
+ 'SELECT * FROM system.schema_columns WHERE keyspace_name = \'%s\''.freeze
311
+ SELECT_TABLE =
312
+ 'SELECT * ' \
313
+ 'FROM system.schema_columnfamilies ' \
314
+ 'WHERE keyspace_name = \'%s\' AND columnfamily_name = \'%s\''.freeze
315
+ SELECT_TABLE_COLUMNS =
316
+ 'SELECT * ' \
317
+ 'FROM system.schema_columns ' \
318
+ 'WHERE keyspace_name = \'%s\' AND columnfamily_name = \'%s\''.freeze
319
+
320
+ include Cassandra::Cluster::Schema::Fetcher
321
+
322
+ def initialize(type_parser, schema)
323
+ @type_parser = type_parser
324
+ @schema = schema
325
+ end
326
+
327
+ private
328
+
329
+ def select_keyspaces(connection)
330
+ send_select_request(connection, SELECT_KEYSPACES)
331
+ end
332
+
333
+ def select_tables(connection)
334
+ send_select_request(connection, SELECT_TABLES)
335
+ end
336
+
337
+ def select_columns(connection)
338
+ send_select_request(connection, SELECT_COLUMNS)
339
+ end
340
+
341
+ def select_keyspace(connection, keyspace_name)
342
+ send_select_request(connection, SELECT_KEYSPACE % keyspace_name)
343
+ end
344
+
345
+ def select_keyspace_tables(connection, keyspace_name)
346
+ send_select_request(connection, format(SELECT_KEYSPACE_TABLES, keyspace_name))
347
+ end
348
+
349
+ def select_keyspace_columns(connection, keyspace_name)
350
+ send_select_request(connection, format(SELECT_KEYSPACE_COLUMNS, keyspace_name))
351
+ end
352
+
353
+ def select_table(connection, keyspace_name, table_name)
354
+ send_select_request(connection, format(SELECT_TABLE, keyspace_name, table_name))
355
+ end
356
+
357
+ def select_table_columns(connection, keyspace_name, table_name)
358
+ send_select_request(connection,
359
+ format(SELECT_TABLE_COLUMNS, keyspace_name, table_name))
360
+ end
361
+
362
+ def create_replication(keyspace_data)
363
+ klass = keyspace_data['strategy_class']
364
+ klass.slice!(REPLICATION_PACKAGE_PREFIX)
365
+ options = ::JSON.load(keyspace_data['strategy_options'])
366
+ Keyspace::Replication.new(klass, options)
367
+ end
368
+
369
+ def create_keyspace(keyspace_data, rows_tables, rows_columns,
370
+ rows_types, rows_functions, rows_aggregates,
371
+ rows_views, rows_indexes, rows_triggers)
372
+ keyspace_name = keyspace_data['keyspace_name']
373
+ replication = create_replication(keyspace_data)
374
+ types = rows_types.each_with_object({}) do |row, h|
375
+ h[row['type_name']] = create_type(row)
376
+ end
377
+
378
+ # Create a FunctionCollection for the functions and aggregates.
379
+ functions = Cassandra::FunctionCollection.new
380
+ rows_functions.each do |row|
381
+ functions.add_or_update(create_function(row))
382
+ end
383
+
384
+ aggregates = Cassandra::FunctionCollection.new
385
+ rows_aggregates.each do |row|
386
+ aggregates.add_or_update(create_aggregate(row, functions))
387
+ end
388
+
389
+ lookup_columns = map_rows_by(rows_columns, 'columnfamily_name')
390
+ lookup_indexes = map_rows_by(rows_indexes, 'columnfamily_name')
391
+ lookup_triggers = map_rows_by(rows_triggers, 'columnfamily_name')
392
+ tables = rows_tables.each_with_object({}) do |row, h|
393
+ table_name = row['columnfamily_name']
394
+ h[table_name] = create_table(row,
395
+ lookup_columns[table_name],
396
+ lookup_indexes[table_name],
397
+ lookup_triggers[table_name])
398
+ end
399
+
400
+ Keyspace.new(keyspace_name,
401
+ keyspace_data['durable_writes'],
402
+ replication,
403
+ tables,
404
+ types,
405
+ functions,
406
+ aggregates,
407
+ {})
408
+ end
409
+
410
+ def create_table(table_data, rows_columns, rows_indexes, rows_triggers)
411
+ keyspace_name = table_data['keyspace_name']
412
+ table_name = table_data['columnfamily_name']
413
+ key_validator = @type_parser.parse(table_data['key_validator'])
414
+ comparator = @type_parser.parse(table_data['comparator'])
415
+ column_aliases = ::JSON.load(table_data['column_aliases'])
416
+
417
+ if comparator.collections.nil?
418
+ is_compact = true
419
+ if !column_aliases.empty? || rows_columns.empty?
420
+ has_value = true
421
+ clustering_size = comparator.results.size
422
+ else
423
+ has_value = false
424
+ clustering_size = 0
425
+ end
426
+ else
427
+ size = comparator.results.size
428
+ if !comparator.collections.empty?
429
+ is_compact = false
430
+ has_value = false
431
+ clustering_size = size - 2
432
+ elsif column_aliases.size == size - 1 &&
433
+ comparator.results.last.first == Cassandra::Types.varchar
434
+ is_compact = false
435
+ has_value = false
436
+ clustering_size = size - 1
437
+ else
438
+ is_compact = true
439
+ has_value = (!column_aliases.empty? || rows_columns.empty?)
440
+ clustering_size = size
441
+ end
442
+ end
443
+
444
+ # Separate out the partition-key, clustering-columns, and other-columns
445
+ partition_key = []
446
+ clustering_columns = []
447
+ clustering_order = []
448
+ other_columns = []
449
+
450
+ compaction_strategy = create_compaction_strategy(table_data)
451
+ table_options =
452
+ create_table_options(table_data, compaction_strategy, is_compact)
453
+
454
+ key_aliases = ::JSON.load(table_data['key_aliases'])
455
+
456
+ key_validator.results.each_with_index do |(type, order, is_frozen), i|
457
+ key_alias = key_aliases.fetch(i) { i.zero? ? 'key' : "key#{i + 1}" }
458
+
459
+ partition_key[i] = Column.new(key_alias, type, order, false, is_frozen)
460
+ end
461
+
462
+ clustering_size.times do |i|
463
+ column_alias = column_aliases.fetch(i) { "column#{i + 1}" }
464
+ type, order, is_frozen = comparator.results.fetch(i)
465
+
466
+ clustering_columns[i] =
467
+ Column.new(column_alias, type, order, false, is_frozen)
468
+ clustering_order[i] = order
469
+ end
470
+
471
+ if has_value
472
+ value_alias = table_data['value_alias']
473
+ value_alias ||= 'value'
474
+
475
+ unless value_alias.empty?
476
+ type, order, is_frozen =
477
+ @type_parser.parse(table_data['default_validator']).results.first
478
+ other_columns <<
479
+ Column.new(value_alias, type, order, false, is_frozen)
480
+ end
481
+ end
482
+
483
+ index_rows = []
484
+ rows_columns.each do |row|
485
+ column = create_column(row)
486
+ other_columns << column
487
+
488
+ # In C* 1.2.x, index info is in the column metadata; rows_indexes is [].
489
+ index_rows << [column, row] unless row['index_type'].nil?
490
+ end
491
+
492
+ table = Cassandra::Table.new(@schema.keyspace(keyspace_name),
493
+ table_name,
494
+ partition_key,
495
+ clustering_columns,
496
+ other_columns,
497
+ table_options,
498
+ clustering_order,
499
+ table_data['id'])
500
+
501
+ # Create Index objects and add them to the table.
502
+ index_rows.each do |column, row|
503
+ create_index(table, column, row)
504
+ end
505
+ table
506
+ end
507
+
508
+ def create_index(table, column, row_column)
509
+ # Most of this logic was taken from the Java driver.
510
+ options = {}
511
+ # For some versions of C*, this field could have a literal string 'null' value.
512
+ if !row_column['index_options'].nil? && row_column['index_options'] != 'null' &&
513
+ !row_column['index_options'].empty?
514
+ options = ::JSON.load(row_column['index_options'])
515
+ end
516
+ column_name = Util.escape_name(column.name)
517
+ target = if options.key?('index_keys')
518
+ "keys(#{column_name})"
519
+ elsif options.key?('index_keys_and_values')
520
+ "entries(#{column_name})"
521
+ elsif column.frozen? && (column.type == Cassandra::Types::Set ||
522
+ column.type == Cassandra::Types::List ||
523
+ column.type == Cassandra::Types::Map)
524
+ "full(#{column_name})"
525
+ else
526
+ column_name
527
+ end
528
+
529
+ table.add_index(Cassandra::Index.new(table,
530
+ row_column['index_name'],
531
+ row_column['index_type'].downcase.to_sym,
532
+ target,
533
+ options))
534
+ end
535
+
536
+ def create_column(column_data)
537
+ name = column_data['column_name']
538
+ is_static = (column_data['type'] == 'STATIC')
539
+ type, order, is_frozen =
540
+ @type_parser.parse(column_data['validator']).results.first
541
+ Column.new(name, type, order, is_static, is_frozen)
542
+ end
543
+
544
+ def create_compaction_strategy(table_data)
545
+ klass = table_data['compaction_strategy_class']
546
+ klass.slice!('org.apache.cassandra.db.compaction.')
547
+ options = ::JSON.load(table_data['compaction_strategy_options'])
548
+ ColumnContainer::Compaction.new(klass, options)
549
+ end
550
+
551
+ def create_table_options(table_data, compaction_strategy, is_compact)
552
+ compression_parameters = ::JSON.load(table_data['compression_parameters'])
553
+ if compression_parameters['sstable_compression']
554
+ compression_parameters['sstable_compression']
555
+ .slice!(COMPRESSION_PACKAGE_PREFIX)
556
+ end
557
+ Cassandra::ColumnContainer::Options.new(
558
+ table_data['comment'],
559
+ table_data['read_repair_chance'],
560
+ table_data['local_read_repair_chance'],
561
+ table_data['gc_grace_seconds'],
562
+ table_data['caching'],
563
+ table_data['bloom_filter_fp_chance'] || 0.01,
564
+ table_data['populate_io_cache_on_flush'],
565
+ table_data['memtable_flush_period_in_ms'],
566
+ table_data['default_time_to_live'],
567
+ nil,
568
+ nil,
569
+ table_data['replicate_on_write'],
570
+ nil,
571
+ nil,
572
+ compaction_strategy,
573
+ compression_parameters,
574
+ is_compact,
575
+ table_data['crc_check_chance'],
576
+ table_data['extensions'],
577
+ nil
578
+ )
579
+ end
580
+ end
581
+
582
+ class V2_0_x < V1_2_x
583
+ SELECT_TRIGGERS = 'SELECT * FROM system.schema_triggers'.freeze
584
+
585
+ SELECT_KEYSPACE =
586
+ 'SELECT * FROM system.schema_keyspaces WHERE keyspace_name = ?'.freeze
587
+ SELECT_KEYSPACE_TABLES =
588
+ 'SELECT * FROM system.schema_columnfamilies WHERE keyspace_name = ?'.freeze
589
+ SELECT_KEYSPACE_COLUMNS =
590
+ 'SELECT * FROM system.schema_columns WHERE keyspace_name = ?'.freeze
591
+ SELECT_KEYSPACE_TRIGGERS =
592
+ 'SELECT * FROM system.schema_triggers WHERE keyspace_name = ?'.freeze
593
+
594
+ SELECT_TABLE =
595
+ 'SELECT * ' \
596
+ 'FROM system.schema_columnfamilies ' \
597
+ 'WHERE keyspace_name = ? AND columnfamily_name = ?'.freeze
598
+ SELECT_TABLE_COLUMNS =
599
+ 'SELECT * ' \
600
+ 'FROM system.schema_columns ' \
601
+ 'WHERE keyspace_name = ? AND columnfamily_name = ?'.freeze
602
+ SELECT_TABLE_TRIGGERS =
603
+ 'SELECT * ' \
604
+ 'FROM system.schema_triggers ' \
605
+ 'WHERE keyspace_name = ? AND columnfamily_name = ?'.freeze
606
+
607
+ private
608
+
609
+ def create_table(table_data, rows_columns, rows_indexes, rows_triggers)
610
+ keyspace_name = table_data['keyspace_name']
611
+ table_name = table_data['columnfamily_name']
612
+ comparator = @type_parser.parse(table_data['comparator'])
613
+ clustering_size = 0
614
+
615
+ # Separate out partition-key, clustering columns, other columns.
616
+ partition_key = []
617
+ clustering_columns = []
618
+ clustering_order = []
619
+ other_columns = []
620
+
621
+ index_rows = []
622
+ rows_columns.each do |row|
623
+ next if row['column_name'].empty?
624
+
625
+ column = create_column(row)
626
+ type = row['type'].to_s
627
+ ind = row['component_index'] || 0
628
+
629
+ case type.upcase
630
+ when 'PARTITION_KEY'
631
+ partition_key[ind] = column
632
+ when 'CLUSTERING_KEY'
633
+ clustering_columns[ind] = column
634
+ clustering_order[ind] = column.order
635
+
636
+ clustering_size += 1
637
+ else
638
+ other_columns << column
639
+ end
640
+
641
+ # In C* 2.0.x, index info is in the column metadata; rows_indexes is nil.
642
+ index_rows << [column, row] unless row['index_type'].nil?
643
+ end
644
+
645
+ compaction_strategy = create_compaction_strategy(table_data)
646
+ is_compact = (clustering_size != comparator.results.size - 1) ||
647
+ !comparator.collections
648
+ table_options =
649
+ create_table_options(table_data, compaction_strategy, is_compact)
650
+
651
+ table = Cassandra::Table.new(@schema.keyspace(keyspace_name),
652
+ table_name,
653
+ partition_key,
654
+ clustering_columns,
655
+ other_columns,
656
+ table_options,
657
+ clustering_order,
658
+ table_data['id'])
659
+
660
+ # Create Index objects and add them to the table.
661
+ index_rows.each do |column, row|
662
+ create_index(table, column, row)
663
+ end
664
+
665
+ # Create Trigger objects and add them to the table.
666
+ rows_triggers.each do |row_trigger|
667
+ table.add_trigger(Cassandra::Trigger.new(table,
668
+ row_trigger['trigger_name'],
669
+ row_trigger['trigger_options']))
670
+ end
671
+
672
+ table
673
+ end
674
+
675
+ def select_triggers(connection)
676
+ send_select_request(connection, SELECT_TRIGGERS)
677
+ end
678
+
679
+ def select_keyspace(connection, keyspace_name)
680
+ params = [keyspace_name]
681
+ hints = [Types.varchar]
682
+ send_select_request(connection, SELECT_KEYSPACE, params, hints)
683
+ end
684
+
685
+ def select_keyspace_tables(connection, keyspace_name)
686
+ params = [keyspace_name]
687
+ hints = [Types.varchar]
688
+ send_select_request(connection, SELECT_KEYSPACE_TABLES, params, hints)
689
+ end
690
+
691
+ def select_keyspace_columns(connection, keyspace_name)
692
+ params = [keyspace_name]
693
+ hints = [Types.varchar]
694
+ send_select_request(connection, SELECT_KEYSPACE_COLUMNS, params, hints)
695
+ end
696
+
697
+ def select_keyspace_triggers(connection, keyspace_name)
698
+ params = [keyspace_name]
699
+ hints = [Types.varchar]
700
+ send_select_request(connection, SELECT_KEYSPACE_TRIGGERS, params, hints)
701
+ end
702
+
703
+ def select_table(connection, keyspace_name, table_name)
704
+ params = [keyspace_name, table_name]
705
+ hints = [Types.varchar, Types.varchar]
706
+ send_select_request(connection, SELECT_TABLE, params, hints)
707
+ end
708
+
709
+ def select_table_columns(connection, keyspace_name, table_name)
710
+ params = [keyspace_name, table_name]
711
+ hints = [Types.varchar, Types.varchar]
712
+ send_select_request(connection, SELECT_TABLE_COLUMNS, params, hints)
713
+ end
714
+
715
+ def select_table_triggers(connection, keyspace_name, table_name)
716
+ params = [keyspace_name, table_name]
717
+ hints = [Types.varchar, Types.varchar]
718
+ send_select_request(connection, SELECT_TABLE_TRIGGERS, params, hints)
719
+ end
720
+
721
+ def create_table_options(table_data, compaction_strategy, is_compact)
722
+ compression_parameters = ::JSON.load(table_data['compression_parameters'])
723
+ if compression_parameters['sstable_compression']
724
+ compression_parameters['sstable_compression']
725
+ .slice!(COMPRESSION_PACKAGE_PREFIX)
726
+ end
727
+ Cassandra::ColumnContainer::Options.new(
728
+ table_data['comment'],
729
+ table_data['read_repair_chance'],
730
+ table_data['local_read_repair_chance'],
731
+ table_data['gc_grace_seconds'],
732
+ table_data['caching'],
733
+ table_data['bloom_filter_fp_chance'],
734
+ table_data['populate_io_cache_on_flush'],
735
+ table_data['memtable_flush_period_in_ms'],
736
+ table_data['default_time_to_live'],
737
+ table_data['speculative_retry'],
738
+ table_data['index_interval'],
739
+ table_data['replicate_on_write'],
740
+ nil,
741
+ nil,
742
+ compaction_strategy,
743
+ compression_parameters,
744
+ is_compact,
745
+ table_data['crc_check_chance'],
746
+ table_data['extensions'],
747
+ nil
748
+ )
749
+ end
750
+ end
751
+
752
+ class V2_1_x < V2_0_x
753
+ SELECT_TYPES = 'SELECT * FROM system.schema_usertypes'.freeze
754
+ SELECT_KEYSPACE_TYPES =
755
+ 'SELECT * FROM system.schema_usertypes WHERE keyspace_name = ?'.freeze
756
+ SELECT_TYPE =
757
+ 'SELECT * ' \
758
+ 'FROM system.schema_usertypes ' \
759
+ 'WHERE keyspace_name = ? AND type_name = ?'.freeze
760
+
761
+ private
762
+
763
+ def create_type(type_data)
764
+ keyspace_name = type_data['keyspace_name']
765
+ type_name = type_data['type_name']
766
+ type_fields = ::Array.new
767
+
768
+ field_names = type_data['field_names']
769
+ field_types = type_data['field_types']
770
+
771
+ field_names.zip(field_types) do |(field_name, fqcn)|
772
+ field_type = @type_parser.parse(fqcn).results.first.first
773
+
774
+ type_fields << [field_name, field_type]
775
+ end
776
+
777
+ Types.udt(keyspace_name, type_name, type_fields)
778
+ end
779
+
780
+ def select_types(connection)
781
+ send_select_request(connection, SELECT_TYPES)
782
+ end
783
+
784
+ def select_keyspace_types(connection, keyspace_name)
785
+ params = [keyspace_name]
786
+ hints = [Types.varchar]
787
+ send_select_request(connection, SELECT_KEYSPACE_TYPES, params, hints)
788
+ end
789
+
790
+ def select_type(connection, keyspace_name, type_name)
791
+ params = [keyspace_name, type_name]
792
+ hints = [Types.varchar, Types.varchar]
793
+ send_select_request(connection, SELECT_TYPE, params, hints)
794
+ end
795
+
796
+ def create_table_options(table_data, compaction_strategy, is_compact)
797
+ compression_parameters = ::JSON.load(table_data['compression_parameters'])
798
+ if compression_parameters['sstable_compression']
799
+ compression_parameters['sstable_compression']
800
+ .slice!(COMPRESSION_PACKAGE_PREFIX)
801
+ end
802
+ Cassandra::ColumnContainer::Options.new(
803
+ table_data['comment'],
804
+ table_data['read_repair_chance'],
805
+ table_data['local_read_repair_chance'],
806
+ table_data['gc_grace_seconds'],
807
+ table_data['caching'],
808
+ table_data['bloom_filter_fp_chance'],
809
+ table_data['populate_io_cache_on_flush'],
810
+ table_data['memtable_flush_period_in_ms'],
811
+ table_data['default_time_to_live'],
812
+ table_data['speculative_retry'],
813
+ table_data['index_interval'],
814
+ table_data['replicate_on_write'],
815
+ table_data['min_index_interval'],
816
+ table_data['max_index_interval'],
817
+ compaction_strategy,
818
+ compression_parameters,
819
+ is_compact,
820
+ table_data['crc_check_chance'],
821
+ table_data['extensions'],
822
+ nil
823
+ )
824
+ end
825
+ end
826
+
827
+ class V2_2_x < V2_1_x
828
+ SELECT_FUNCTIONS = 'SELECT * FROM system.schema_functions'.freeze
829
+ SELECT_AGGREGATES = 'SELECT * FROM system.schema_aggregates'.freeze
830
+ SELECT_KEYSPACE_FUNCTIONS =
831
+ 'SELECT * FROM system.schema_functions WHERE keyspace_name = ?'.freeze
832
+ SELECT_KEYSPACE_AGGREGATES =
833
+ 'SELECT * FROM system.schema_aggregates WHERE keyspace_name = ?'.freeze
834
+ SELECT_FUNCTION =
835
+ 'SELECT * ' \
836
+ 'FROM system.schema_functions ' \
837
+ 'WHERE keyspace_name = ? AND function_name = ? ' \
838
+ 'AND argument_types = ?'.freeze
839
+ SELECT_AGGREGATE =
840
+ 'SELECT * ' \
841
+ 'FROM system.schema_aggregates ' \
842
+ 'WHERE keyspace_name = ? AND aggregate_name = ? ' \
843
+ 'AND argument_types = ?'.freeze
844
+
845
+ # parse an array of string argument types and return an array of
846
+ # [Cassandra::Type]s.
847
+ # @param connection a connection to a Cassandra node.
848
+ # @param keyspace_name [String] name of the keyspace.
849
+ # @param argument_types [Array<String>] array of argument types.
850
+ # @return [Array<Cassandra::Type>] array of parsed types.
851
+ def parse_argument_types(connection, keyspace_name, argument_types)
852
+ argument_types.map do |argument_type|
853
+ @type_parser.parse(argument_type).results.first.first
854
+ end
855
+ end
856
+
857
+ private
858
+
859
+ def create_function(function_data)
860
+ keyspace_name = function_data['keyspace_name']
861
+ function_name = function_data['function_name']
862
+ function_lang = function_data['language']
863
+ function_type =
864
+ @type_parser.parse(function_data['return_type']).results.first.first
865
+ function_body = function_data['body']
866
+ called_on_null = function_data['called_on_null_input']
867
+
868
+ arguments = []
869
+
870
+ Array(function_data['argument_names'])
871
+ .zip(Array(function_data['argument_types'])) do |argument_name, fqcn|
872
+ argument_type = @type_parser.parse(fqcn).results.first.first
873
+ arguments << Argument.new(argument_name, argument_type)
874
+ end
875
+
876
+ Cassandra::Function.new(keyspace_name,
877
+ function_name,
878
+ function_lang,
879
+ function_type,
880
+ arguments,
881
+ function_body,
882
+ called_on_null)
883
+ end
884
+
885
+ def create_aggregate(aggregate_data, functions)
886
+ keyspace_name = aggregate_data['keyspace_name']
887
+ aggregate_name = aggregate_data['aggregate_name']
888
+ aggregate_type =
889
+ @type_parser.parse(aggregate_data['return_type']).results.first.first
890
+ argument_types = aggregate_data['argument_types'].map do |fqcn|
891
+ @type_parser.parse(fqcn).results.first.first
892
+ end.freeze
893
+ state_type =
894
+ @type_parser.parse(aggregate_data['state_type']).results.first.first
895
+ initial_state = Util.encode_object(
896
+ Protocol::Coder.read_value_v4(
897
+ Protocol::CqlByteBuffer.new.append_bytes(aggregate_data['initcond']),
898
+ state_type, nil
899
+ )
900
+ )
901
+
902
+ # The state-function takes arguments: first the stype, then the args of the aggregate.
903
+ state_function = functions.get(aggregate_data['state_func'],
904
+ [state_type].concat(argument_types))
905
+
906
+ # The final-function takes an stype argument.
907
+ final_function = functions.get(aggregate_data['final_func'],
908
+ [state_type])
909
+
910
+ Aggregate.new(keyspace_name,
911
+ aggregate_name,
912
+ aggregate_type,
913
+ argument_types,
914
+ state_type,
915
+ initial_state,
916
+ state_function,
917
+ final_function)
918
+ end
919
+
920
+ def select_functions(connection)
921
+ send_select_request(connection, SELECT_FUNCTIONS)
922
+ end
923
+
924
+ def select_aggregates(connection)
925
+ send_select_request(connection, SELECT_AGGREGATES)
926
+ end
927
+
928
+ def select_keyspace_functions(connection, keyspace_name)
929
+ params = [keyspace_name]
930
+ hints = [Types.varchar]
931
+ send_select_request(connection, SELECT_KEYSPACE_FUNCTIONS, params, hints)
932
+ end
933
+
934
+ def select_keyspace_aggregates(connection, keyspace_name)
935
+ params = [keyspace_name]
936
+ hints = [Types.varchar]
937
+ send_select_request(connection, SELECT_KEYSPACE_AGGREGATES, params, hints)
938
+ end
939
+
940
+ def select_function(connection, keyspace_name, function_name, function_args)
941
+ params = [keyspace_name, function_name, function_args.map(&:to_s)]
942
+ hints = [Types.varchar, Types.varchar, Types.list(Types.varchar)]
943
+ send_select_request(connection, SELECT_FUNCTION, params, hints)
944
+ end
945
+
946
+ def select_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
947
+ params = [keyspace_name, aggregate_name, aggregate_args.map(&:to_s)]
948
+ hints = [Types.varchar, Types.varchar, Types.list(Types.varchar)]
949
+ send_select_request(connection, SELECT_AGGREGATE, params, hints)
950
+ end
951
+ end
952
+
953
+ class V3_0_x < V2_2_x
954
+ SELECT_KEYSPACES = 'SELECT * FROM system_schema.keyspaces'.freeze
955
+ SELECT_TABLES = 'SELECT * FROM system_schema.tables'.freeze
956
+ SELECT_COLUMNS = 'SELECT * FROM system_schema.columns'.freeze
957
+ SELECT_TYPES = 'SELECT * FROM system_schema.types'.freeze
958
+ SELECT_FUNCTIONS = 'SELECT * FROM system_schema.functions'.freeze
959
+ SELECT_AGGREGATES = 'SELECT * FROM system_schema.aggregates'.freeze
960
+ SELECT_INDEXES = 'SELECT * FROM system_schema.indexes'.freeze
961
+ SELECT_VIEWS = 'SELECT * FROM system_schema.views'.freeze
962
+ SELECT_TRIGGERS = 'SELECT * FROM system_schema.triggers'.freeze
963
+
964
+ SELECT_KEYSPACE =
965
+ 'SELECT * FROM system_schema.keyspaces WHERE keyspace_name = ?'.freeze
966
+ SELECT_KEYSPACE_TABLES =
967
+ 'SELECT * FROM system_schema.tables WHERE keyspace_name = ?'.freeze
968
+ SELECT_KEYSPACE_INDEXES =
969
+ 'SELECT * FROM system_schema.indexes WHERE keyspace_name = ?'.freeze
970
+ SELECT_KEYSPACE_COLUMNS =
971
+ 'SELECT * FROM system_schema.columns WHERE keyspace_name = ?'.freeze
972
+ SELECT_KEYSPACE_VIEWS =
973
+ 'SELECT * FROM system_schema.views WHERE keyspace_name = ?'.freeze
974
+ SELECT_KEYSPACE_TYPES =
975
+ 'SELECT * FROM system_schema.types WHERE keyspace_name = ?'.freeze
976
+ SELECT_KEYSPACE_FUNCTIONS =
977
+ 'SELECT * FROM system_schema.functions WHERE keyspace_name = ?'.freeze
978
+ SELECT_KEYSPACE_AGGREGATES =
979
+ 'SELECT * FROM system_schema.aggregates WHERE keyspace_name = ?'.freeze
980
+ SELECT_KEYSPACE_TRIGGERS =
981
+ 'SELECT * FROM system_schema.triggers WHERE keyspace_name = ?'.freeze
982
+
983
+ SELECT_TABLE =
984
+ 'SELECT * ' \
985
+ 'FROM system_schema.tables ' \
986
+ 'WHERE keyspace_name = ? AND table_name = ?'.freeze
987
+ SELECT_TABLE_COLUMNS =
988
+ 'SELECT * ' \
989
+ 'FROM system_schema.columns ' \
990
+ 'WHERE keyspace_name = ? AND table_name = ?'.freeze
991
+ SELECT_TABLE_INDEXES =
992
+ 'SELECT * ' \
993
+ 'FROM system_schema.indexes ' \
994
+ 'WHERE keyspace_name = ? AND table_name = ?'.freeze
995
+ SELECT_TABLE_TRIGGERS =
996
+ 'SELECT * ' \
997
+ 'FROM system_schema.triggers ' \
998
+ 'WHERE keyspace_name = ? AND table_name = ?'.freeze
999
+
1000
+ SELECT_VIEW =
1001
+ 'SELECT * ' \
1002
+ 'FROM system_schema.views ' \
1003
+ 'WHERE keyspace_name = ? AND view_name = ?'.freeze
1004
+
1005
+ SELECT_TYPE =
1006
+ 'SELECT * ' \
1007
+ 'FROM system_schema.types ' \
1008
+ 'WHERE keyspace_name = ? AND type_name = ?'.freeze
1009
+
1010
+ SELECT_FUNCTION =
1011
+ 'SELECT * ' \
1012
+ 'FROM system_schema.functions ' \
1013
+ 'WHERE keyspace_name = ? AND function_name = ? ' \
1014
+ 'AND argument_types = ?'.freeze
1015
+
1016
+ SELECT_AGGREGATE =
1017
+ 'SELECT * ' \
1018
+ 'FROM system_schema.aggregates ' \
1019
+ 'WHERE keyspace_name = ? AND aggregate_name = ? ' \
1020
+ 'AND argument_types = ?'.freeze
1021
+
1022
+ # parse an array of string argument types and return an array of
1023
+ # [Cassandra::Type]s.
1024
+ # @param connection a connection to a Cassandra node.
1025
+ # @param keyspace_name [String] name of the keyspace.
1026
+ # @param argument_types [Array<String>] array of argument types.
1027
+ # @return [Array<Cassandra::Type>] array of parsed types.
1028
+ def parse_argument_types(connection, keyspace_name, argument_types)
1029
+ types = @schema.keyspace(keyspace_name).send(:raw_types)
1030
+ argument_types.map do |argument_type|
1031
+ @type_parser.parse(argument_type, types).first
1032
+ end
1033
+ end
1034
+
1035
+ private
1036
+
1037
+ def select_keyspaces(connection)
1038
+ send_select_request(connection, SELECT_KEYSPACES)
1039
+ end
1040
+
1041
+ def select_tables(connection)
1042
+ send_select_request(connection, SELECT_TABLES)
1043
+ end
1044
+
1045
+ def select_indexes(connection)
1046
+ send_select_request(connection, SELECT_INDEXES)
1047
+ end
1048
+
1049
+ def select_materialized_views(connection)
1050
+ send_select_request(connection, SELECT_VIEWS)
1051
+ end
1052
+
1053
+ def select_columns(connection)
1054
+ send_select_request(connection, SELECT_COLUMNS)
1055
+ end
1056
+
1057
+ def select_triggers(connection)
1058
+ send_select_request(connection, SELECT_TRIGGERS)
1059
+ end
1060
+
1061
+ def select_types(connection)
1062
+ send_select_request(connection, SELECT_TYPES)
1063
+ end
1064
+
1065
+ def select_functions(connection)
1066
+ send_select_request(connection, SELECT_FUNCTIONS)
1067
+ end
1068
+
1069
+ def select_aggregates(connection)
1070
+ send_select_request(connection, SELECT_AGGREGATES)
1071
+ end
1072
+
1073
+ def select_keyspace(connection, keyspace_name)
1074
+ params = [keyspace_name]
1075
+ hints = [Types.varchar]
1076
+ send_select_request(connection, SELECT_KEYSPACE, params, hints)
1077
+ end
1078
+
1079
+ def select_keyspace_tables(connection, keyspace_name)
1080
+ params = [keyspace_name]
1081
+ hints = [Types.varchar]
1082
+ send_select_request(connection, SELECT_KEYSPACE_TABLES, params, hints)
1083
+ end
1084
+
1085
+ def select_keyspace_columns(connection, keyspace_name)
1086
+ params = [keyspace_name]
1087
+ hints = [Types.varchar]
1088
+ send_select_request(connection, SELECT_KEYSPACE_COLUMNS, params, hints)
1089
+ end
1090
+
1091
+ def select_keyspace_indexes(connection, keyspace_name)
1092
+ params = [keyspace_name]
1093
+ hints = [Types.varchar]
1094
+ send_select_request(connection, SELECT_KEYSPACE_INDEXES, params, hints)
1095
+ end
1096
+
1097
+ def select_keyspace_materialized_views(connection, keyspace_name)
1098
+ params = [keyspace_name]
1099
+ hints = [Types.varchar]
1100
+ send_select_request(connection, SELECT_KEYSPACE_VIEWS, params, hints)
1101
+ end
1102
+
1103
+ def select_keyspace_triggers(connection, keyspace_name)
1104
+ params = [keyspace_name]
1105
+ hints = [Types.varchar]
1106
+ send_select_request(connection, SELECT_KEYSPACE_TRIGGERS, params, hints)
1107
+ end
1108
+
1109
+ def select_keyspace_types(connection, keyspace_name)
1110
+ params = [keyspace_name]
1111
+ hints = [Types.varchar]
1112
+ send_select_request(connection, SELECT_KEYSPACE_TYPES, params, hints)
1113
+ end
1114
+
1115
+ def select_keyspace_functions(connection, keyspace_name)
1116
+ params = [keyspace_name]
1117
+ hints = [Types.varchar]
1118
+ send_select_request(connection, SELECT_KEYSPACE_FUNCTIONS, params, hints)
1119
+ end
1120
+
1121
+ def select_keyspace_aggregates(connection, keyspace_name)
1122
+ params = [keyspace_name]
1123
+ hints = [Types.varchar]
1124
+ send_select_request(connection, SELECT_KEYSPACE_AGGREGATES, params, hints)
1125
+ end
1126
+
1127
+ def select_table(connection, keyspace_name, table_name)
1128
+ params = [keyspace_name, table_name]
1129
+ hints = [Types.varchar, Types.varchar]
1130
+ send_select_request(connection, SELECT_TABLE, params, hints)
1131
+ end
1132
+
1133
+ def select_table_columns(connection, keyspace_name, table_name)
1134
+ # This is identical to the 2.0 impl, but the SELECT_TABLE_COLUMNS query
1135
+ # is different between the two, so we need two impls. :(
1136
+ # Also, this method works fine for finding view columns as well.
1137
+ params = [keyspace_name, table_name]
1138
+ hints = [Types.varchar, Types.varchar]
1139
+ send_select_request(connection, SELECT_TABLE_COLUMNS, params, hints)
1140
+ end
1141
+
1142
+ def select_table_indexes(connection, keyspace_name, table_name)
1143
+ params = [keyspace_name, table_name]
1144
+ hints = [Types.varchar, Types.varchar]
1145
+ send_select_request(connection, SELECT_TABLE_INDEXES, params, hints)
1146
+ end
1147
+
1148
+ def select_materialized_view(connection, keyspace_name, view_name)
1149
+ params = [keyspace_name, view_name]
1150
+ hints = [Types.varchar, Types.varchar]
1151
+ send_select_request(connection, SELECT_VIEW, params, hints)
1152
+ end
1153
+
1154
+ def select_table_triggers(connection, keyspace_name, table_name)
1155
+ params = [keyspace_name, table_name]
1156
+ hints = [Types.varchar, Types.varchar]
1157
+ send_select_request(connection, SELECT_TABLE_TRIGGERS, params, hints)
1158
+ end
1159
+
1160
+ def select_type(connection, keyspace_name, type_name)
1161
+ params = [keyspace_name, type_name]
1162
+ hints = [Types.varchar, Types.varchar]
1163
+ send_select_request(connection, SELECT_TYPE, params, hints)
1164
+ end
1165
+
1166
+ def select_function(connection, keyspace_name, function_name, function_args)
1167
+ params = [keyspace_name, function_name, function_args.map(&:to_s)]
1168
+ hints = [Types.varchar, Types.varchar, Types.list(Types.varchar)]
1169
+ send_select_request(connection, SELECT_FUNCTION, params, hints)
1170
+ end
1171
+
1172
+ def select_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
1173
+ params = [keyspace_name, aggregate_name, aggregate_args.map(&:to_s)]
1174
+ hints = [Types.varchar, Types.varchar, Types.list(Types.varchar)]
1175
+ send_select_request(connection, SELECT_AGGREGATE, params, hints)
1176
+ end
1177
+
1178
+ def create_function(function_data, types = nil)
1179
+ keyspace_name = function_data['keyspace_name']
1180
+ function_name = function_data['function_name']
1181
+ function_lang = function_data['language']
1182
+ types ||= @schema.keyspace(keyspace_name).send(:raw_types)
1183
+ function_type = @type_parser.parse(function_data['return_type'], types).first
1184
+ function_body = function_data['body']
1185
+ called_on_null = function_data['called_on_null_input']
1186
+
1187
+ arguments = []
1188
+
1189
+ function_data['argument_names']
1190
+ .zip(function_data['argument_types']) do |argument_name, argument_type|
1191
+ arguments << Argument.new(argument_name,
1192
+ @type_parser.parse(argument_type, types).first)
1193
+ end
1194
+
1195
+ Cassandra::Function.new(keyspace_name,
1196
+ function_name,
1197
+ function_lang,
1198
+ function_type,
1199
+ arguments,
1200
+ function_body,
1201
+ called_on_null)
1202
+ end
1203
+
1204
+ def create_aggregate(aggregate_data, functions, types = nil)
1205
+ keyspace_name = aggregate_data['keyspace_name']
1206
+ aggregate_name = aggregate_data['aggregate_name']
1207
+ types ||= @schema.keyspace(keyspace_name).send(:raw_types)
1208
+ aggregate_type =
1209
+ @type_parser.parse(aggregate_data['return_type'], types).first
1210
+ argument_types = aggregate_data['argument_types'].map do |argument_type|
1211
+ @type_parser.parse(argument_type, types).first
1212
+ end.freeze
1213
+ state_type = @type_parser.parse(aggregate_data['state_type'], types).first
1214
+ initial_state = aggregate_data['initcond'] || 'null'
1215
+
1216
+ # The state-function takes arguments: first the stype, then the args of the
1217
+ # aggregate.
1218
+ state_function = functions.get(aggregate_data['state_func'],
1219
+ [state_type].concat(argument_types))
1220
+
1221
+ # The final-function takes an stype argument.
1222
+ final_function = functions.get(aggregate_data['final_func'],
1223
+ [state_type])
1224
+
1225
+ Aggregate.new(keyspace_name,
1226
+ aggregate_name,
1227
+ aggregate_type,
1228
+ argument_types,
1229
+ state_type,
1230
+ initial_state,
1231
+ state_function,
1232
+ final_function)
1233
+ end
1234
+
1235
+ def create_types(rows_types, types)
1236
+ skipped_rows = ::Array.new
1237
+
1238
+ loop do
1239
+ rows_size = rows_types.size
1240
+
1241
+ until rows_types.empty?
1242
+ type_data = rows_types.shift
1243
+ type_name = type_data['type_name']
1244
+ type_keyspace = type_data['keyspace_name']
1245
+ type_fields = ::Array.new
1246
+
1247
+ begin
1248
+ field_names = type_data['field_names']
1249
+ field_types = type_data['field_types']
1250
+ field_names.each_with_index do |field_name, i|
1251
+ field_type = @type_parser.parse(field_types[i], types).first
1252
+ type_fields << [field_name, field_type]
1253
+ end
1254
+
1255
+ types[type_name] = Types.udt(type_keyspace, type_name, type_fields)
1256
+ rescue CQLTypeParser::IncompleteTypeError
1257
+ skipped_rows << type_data
1258
+ next
1259
+ end
1260
+ end
1261
+
1262
+ break if skipped_rows.empty?
1263
+
1264
+ raise 'Unable to resolve circular references among UDTs when parsing' if rows_size == skipped_rows.size
1265
+
1266
+ rows_types, skipped_rows = skipped_rows, rows_types
1267
+ end
1268
+ end
1269
+
1270
+ def create_keyspace(keyspace_data, rows_tables, rows_columns, rows_types,
1271
+ rows_functions, rows_aggregates, rows_views, rows_indexes, rows_triggers)
1272
+ keyspace_name = keyspace_data['keyspace_name']
1273
+ replication = create_replication(keyspace_data)
1274
+
1275
+ types = ::Hash.new
1276
+ create_types(rows_types, types)
1277
+
1278
+ # Create a FunctionCollection for the functions and aggregates.
1279
+ functions = Cassandra::FunctionCollection.new
1280
+ rows_functions.each do |row|
1281
+ functions.add_or_update(create_function(row, types))
1282
+ end
1283
+
1284
+ aggregates = Cassandra::FunctionCollection.new
1285
+ rows_aggregates.each do |row|
1286
+ aggregates.add_or_update(create_aggregate(row, functions, types))
1287
+ end
1288
+
1289
+ # lookup_columns is a hash of <table-name, rows_columns for that table>.
1290
+ # However, views are analogous to tables in this context, so we get
1291
+ # view columns organized by view-name also.
1292
+
1293
+ lookup_columns = map_rows_by(rows_columns, 'table_name')
1294
+ lookup_indexes = map_rows_by(rows_indexes, 'table_name')
1295
+ lookup_triggers = map_rows_by(rows_triggers, 'table_name')
1296
+ tables = rows_tables.each_with_object({}) do |row, h|
1297
+ table_name = row['table_name']
1298
+ h[table_name] = create_table(row, lookup_columns[table_name],
1299
+ lookup_indexes[table_name], lookup_triggers[table_name], types)
1300
+ end
1301
+
1302
+ views = rows_views.each_with_object({}) do |row, h|
1303
+ view_name = row['view_name']
1304
+ h[view_name] = create_materialized_view(row,
1305
+ lookup_columns[view_name],
1306
+ types)
1307
+ end
1308
+
1309
+ Keyspace.new(keyspace_name,
1310
+ keyspace_data['durable_writes'],
1311
+ replication,
1312
+ tables,
1313
+ types,
1314
+ functions,
1315
+ aggregates,
1316
+ views)
1317
+ end
1318
+
1319
+ def create_replication(keyspace_data)
1320
+ options = keyspace_data['replication']
1321
+ klass = options.delete('class')
1322
+ klass.slice!(REPLICATION_PACKAGE_PREFIX)
1323
+ Keyspace::Replication.new(klass, options)
1324
+ end
1325
+
1326
+ def create_compaction_strategy(table_data)
1327
+ options = table_data['compaction'] || {}
1328
+ klass = options.delete('class') || ''
1329
+ klass.slice!('org.apache.cassandra.db.compaction.')
1330
+ ColumnContainer::Compaction.new(klass, options)
1331
+ end
1332
+
1333
+ def create_table_options(table_data, compaction_strategy, is_compact)
1334
+ compression = table_data['compression'] || {}
1335
+ compression['class'].slice!(COMPRESSION_PACKAGE_PREFIX) if compression['class']
1336
+
1337
+ Cassandra::ColumnContainer::Options.new(
1338
+ table_data['comment'],
1339
+ table_data['read_repair_chance'],
1340
+ table_data['dclocal_read_repair_chance'],
1341
+ table_data['gc_grace_seconds'],
1342
+ table_data['caching'],
1343
+ table_data['bloom_filter_fp_chance'],
1344
+ nil,
1345
+ table_data['memtable_flush_period_in_ms'],
1346
+ table_data['default_time_to_live'],
1347
+ table_data['speculative_retry'],
1348
+ nil,
1349
+ nil,
1350
+ table_data['min_index_interval'],
1351
+ table_data['max_index_interval'],
1352
+ compaction_strategy,
1353
+ compression,
1354
+ is_compact,
1355
+ table_data['crc_check_chance'],
1356
+ table_data['extensions'],
1357
+ table_data['cdc']
1358
+ )
1359
+ end
1360
+
1361
+ def create_column(column_data, types)
1362
+ name = column_data['column_name']
1363
+ is_static = column_data['kind'].to_s.casecmp('STATIC').zero?
1364
+ order = column_data['clustering_order'] == 'desc' ? :desc : :asc
1365
+ if column_data['type'][0] == "'"
1366
+ # This is a custom column type.
1367
+ type = Types.custom(column_data['type'].slice(1, column_data['type'].length - 2))
1368
+ is_frozen = false
1369
+ else
1370
+ type, is_frozen = @type_parser.parse(column_data['type'], types)
1371
+ end
1372
+
1373
+ Column.new(name, type, order, is_static, is_frozen)
1374
+ end
1375
+
1376
+ def create_table(table_data, rows_columns, rows_indexes, rows_triggers, types = nil)
1377
+ keyspace_name = table_data['keyspace_name']
1378
+ table_name = table_data['table_name']
1379
+ table_flags = table_data['flags']
1380
+
1381
+ is_dense = table_flags.include?('dense')
1382
+ is_super = table_flags.include?('super')
1383
+ is_compound = table_flags.include?('compound')
1384
+ is_compact = is_super || is_dense || !is_compound
1385
+ is_static_compact = !is_super && !is_dense && !is_compound
1386
+
1387
+ # Separate out partition-key, clustering columns, other columns.
1388
+ partition_key = []
1389
+ clustering_columns = []
1390
+ clustering_order = []
1391
+ other_columns = []
1392
+ types ||= @schema.keyspace(keyspace_name).send(:raw_types)
1393
+
1394
+ rows_columns.each do |row|
1395
+ next if row['column_name'].empty?
1396
+
1397
+ kind = row['kind'].to_s
1398
+ index = row['position'] || 0
1399
+
1400
+ if is_static_compact
1401
+ if kind.casecmp('CLUSTERING').zero? || kind.casecmp('REGULAR').zero?
1402
+ # Skip clustering columns in static-compact tables; they are internal to C*.
1403
+ # Oddly so are regular columns.
1404
+ next
1405
+ end
1406
+ if kind.casecmp('STATIC').zero?
1407
+ # Coerce static type to regular.
1408
+ kind = 'REGULAR'
1409
+ row['kind'] = 'regular'
1410
+ end
1411
+ end
1412
+
1413
+ column = create_column(row, types)
1414
+ case kind.upcase
1415
+ when 'PARTITION_KEY'
1416
+ partition_key[index] = column
1417
+ when 'CLUSTERING'
1418
+ clustering_columns[index] = column
1419
+ clustering_order[index] = column.order
1420
+ else
1421
+ other_columns << column
1422
+ end
1423
+ end
1424
+
1425
+ # Default the crc_check_chance to 1.0 (Java driver does this, so we
1426
+ # should, too).
1427
+ table_data['crc_check_chance'] ||= 1.0
1428
+ compaction_strategy = create_compaction_strategy(table_data)
1429
+ table_options =
1430
+ create_table_options(table_data, compaction_strategy, is_compact)
1431
+
1432
+ table = Cassandra::Table.new(@schema.keyspace(keyspace_name),
1433
+ table_name,
1434
+ partition_key,
1435
+ clustering_columns,
1436
+ other_columns,
1437
+ table_options,
1438
+ clustering_order,
1439
+ table_data['id'])
1440
+ rows_indexes.each do |row|
1441
+ create_index(table, row)
1442
+ end
1443
+
1444
+ # Create Trigger objects and add them to the table.
1445
+ rows_triggers.each do |row_trigger|
1446
+ table.add_trigger(Cassandra::Trigger.new(table,
1447
+ row_trigger['trigger_name'],
1448
+ row_trigger['options']))
1449
+ end
1450
+
1451
+ table
1452
+ end
1453
+
1454
+ def create_index(table, row_index)
1455
+ options = row_index['options']
1456
+ table.add_index(Cassandra::Index.new(table, row_index['index_name'],
1457
+ row_index['kind'].downcase.to_sym,
1458
+ options['target'], options))
1459
+ end
1460
+
1461
+ def create_materialized_view(view_data, rows_columns, types = nil)
1462
+ keyspace_name = view_data['keyspace_name']
1463
+ view_name = view_data['view_name']
1464
+ base_table_name = view_data['base_table_name']
1465
+ include_all_columns = view_data['include_all_columns']
1466
+ where_clause = view_data['where_clause']
1467
+
1468
+ # Separate out partition key, clustering columns, other columns
1469
+ partition_key = []
1470
+ clustering_columns = []
1471
+ other_columns = []
1472
+ types ||= @schema.keyspace(keyspace_name).send(:raw_types)
1473
+
1474
+ rows_columns.each do |row|
1475
+ next if row['column_name'].empty?
1476
+
1477
+ column = create_column(row, types)
1478
+ kind = row['kind'].to_s
1479
+ index = row['position'] || 0
1480
+
1481
+ case kind.upcase
1482
+ when 'PARTITION_KEY'
1483
+ partition_key[index] = column
1484
+ when 'CLUSTERING'
1485
+ clustering_columns[index] = column
1486
+ else
1487
+ other_columns << column
1488
+ end
1489
+ end
1490
+
1491
+ compaction_strategy = create_compaction_strategy(view_data)
1492
+ view_options = create_table_options(view_data, compaction_strategy, false)
1493
+
1494
+ MaterializedView.new(@schema.keyspace(keyspace_name),
1495
+ view_name,
1496
+ partition_key,
1497
+ clustering_columns,
1498
+ other_columns,
1499
+ view_options,
1500
+ include_all_columns,
1501
+ where_clause,
1502
+ base_table_name,
1503
+ view_data['id'])
1504
+ end
1505
+ end
1506
+
1507
+ class MultiVersion
1508
+ class Version
1509
+ def initialize(version, constructor)
1510
+ @version = version
1511
+ @constructor = constructor
1512
+ @fetcher = nil
1513
+ end
1514
+
1515
+ def matches?(version)
1516
+ version.start_with?(@version)
1517
+ end
1518
+
1519
+ def fetcher
1520
+ @fetcher ||= @constructor.call
1521
+ end
1522
+ end
1523
+
1524
+ def initialize(registry)
1525
+ @registry = registry
1526
+ @versions = []
1527
+ @fetchers = {}
1528
+ end
1529
+
1530
+ def when(version, &block)
1531
+ @versions << Version.new(version, block)
1532
+ end
1533
+
1534
+ def fetch(connection)
1535
+ find_fetcher(connection)
1536
+ .fetch(connection)
1537
+ rescue => e
1538
+ return Ione::Future.failed(e)
1539
+ end
1540
+
1541
+ def fetch_keyspace(connection, keyspace_name)
1542
+ find_fetcher(connection)
1543
+ .fetch_keyspace(connection, keyspace_name)
1544
+ rescue => e
1545
+ return Ione::Future.failed(e)
1546
+ end
1547
+
1548
+ def fetch_table(connection, keyspace_name, table_name)
1549
+ find_fetcher(connection)
1550
+ .fetch_table(connection, keyspace_name, table_name)
1551
+ rescue => e
1552
+ return Ione::Future.failed(e)
1553
+ end
1554
+
1555
+ def fetch_materialized_view(connection, keyspace_name, view_name)
1556
+ find_fetcher(connection)
1557
+ .fetch_materialized_view(connection, keyspace_name, view_name)
1558
+ rescue => e
1559
+ return Ione::Future.failed(e)
1560
+ end
1561
+
1562
+ def fetch_type(connection, keyspace_name, type_name)
1563
+ find_fetcher(connection)
1564
+ .fetch_type(connection, keyspace_name, type_name)
1565
+ rescue => e
1566
+ return Ione::Future.failed(e)
1567
+ end
1568
+
1569
+ def fetch_function(connection, keyspace_name, function_name, function_args)
1570
+ find_fetcher(connection)
1571
+ .fetch_function(connection, keyspace_name, function_name, function_args)
1572
+ rescue => e
1573
+ return Ione::Future.failed(e)
1574
+ end
1575
+
1576
+ def fetch_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
1577
+ find_fetcher(connection)
1578
+ .fetch_aggregate(connection, keyspace_name, aggregate_name, aggregate_args)
1579
+ rescue => e
1580
+ return Ione::Future.failed(e)
1581
+ end
1582
+
1583
+ # parse an array of string argument types and return an array of
1584
+ # [Cassandra::Type]s.
1585
+ # @param connection a connection to a Cassandra node.
1586
+ # @param keyspace_name [String] name of the keyspace.
1587
+ # @param argument_types [Array<String>] array of argument types.
1588
+ # @return [Array<Cassandra::Type>] array of parsed types.
1589
+ def parse_argument_types(connection, keyspace_name, argument_types)
1590
+ find_fetcher(connection).parse_argument_types(connection,
1591
+ keyspace_name,
1592
+ argument_types)
1593
+ end
1594
+
1595
+ private
1596
+
1597
+ def find_fetcher(connection)
1598
+ host = @registry.host(connection.host)
1599
+
1600
+ unless host
1601
+ ips = @registry.hosts.map(&:ip)
1602
+ raise Errors::ClientError,
1603
+ 'unable to find release version for current host, ' \
1604
+ "connected to #{connection.host}, but cluster contains " \
1605
+ "#{ips}."
1606
+ end
1607
+
1608
+ version = host.release_version
1609
+ unless version
1610
+ raise Errors::ClientError, 'unable to determine release ' \
1611
+ "version for host: #{host.inspect}"
1612
+ end
1613
+
1614
+ @fetchers[version] ||= begin
1615
+ current = @versions.find {|v| v.matches?(version)}
1616
+ unless current
1617
+ raise Errors::ClientError, 'unsupported release version ' \
1618
+ "#{version.inspect}."
1619
+ end
1620
+ current.fetcher
1621
+ end
1622
+ end
1623
+ end
1624
+ end
1625
+ end
1626
+ end
1627
+ end