yugabyte-ycql-driver 3.2.3.1

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.
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