| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "metadata.hpp" |
| |
| #include "buffer.hpp" |
| #include "collection.hpp" |
| #include "collection_iterator.hpp" |
| #include "data_type_parser.hpp" |
| #include "external.hpp" |
| #include "iterator.hpp" |
| #include "json.hpp" |
| #include "logger.hpp" |
| #include "map_iterator.hpp" |
| #include "result_iterator.hpp" |
| #include "row.hpp" |
| #include "row_iterator.hpp" |
| #include "scoped_lock.hpp" |
| #include "string.hpp" |
| #include "utils.hpp" |
| #include "value.hpp" |
| |
| #include <algorithm> |
| #include <cmath> |
| #include <ctype.h> |
| #include <iterator> |
| |
| using namespace datastax; |
| using namespace datastax::internal; |
| using namespace datastax::internal::core; |
| |
| static String& append_arguments(String& full_name, const String& arguments) { |
| full_name.push_back('('); |
| bool first = true; |
| IStringStream stream(arguments); |
| while (!stream.eof()) { |
| String argument; |
| std::getline(stream, argument, ','); |
| // Remove white-space |
| argument.erase(std::remove_if(argument.begin(), argument.end(), ::isspace), argument.end()); |
| if (!argument.empty()) { |
| if (!first) full_name.push_back(','); |
| full_name.append(argument); |
| first = false; |
| } |
| } |
| full_name.push_back(')'); |
| return full_name; |
| } |
| |
| extern "C" { |
| |
| void cass_schema_meta_free(const CassSchemaMeta* schema_meta) { delete schema_meta->from(); } |
| |
| cass_uint32_t cass_schema_meta_snapshot_version(const CassSchemaMeta* schema_meta) { |
| return schema_meta->version(); |
| } |
| |
| CassVersion cass_schema_meta_version(const CassSchemaMeta* schema_meta) { |
| CassVersion version; |
| version.major_version = schema_meta->server_version().major_version(); |
| version.minor_version = schema_meta->server_version().minor_version(); |
| version.patch_version = schema_meta->server_version().patch_version(); |
| return version; |
| } |
| |
| const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name(const CassSchemaMeta* schema_meta, |
| const char* keyspace) { |
| return cass_schema_meta_keyspace_by_name_n(schema_meta, keyspace, SAFE_STRLEN(keyspace)); |
| } |
| |
| const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name_n(const CassSchemaMeta* schema_meta, |
| const char* keyspace, |
| size_t keyspace_length) { |
| return CassKeyspaceMeta::to(schema_meta->get_keyspace(String(keyspace, keyspace_length))); |
| } |
| |
| void cass_keyspace_meta_name(const CassKeyspaceMeta* keyspace_meta, const char** name, |
| size_t* name_length) { |
| *name = keyspace_meta->name().data(); |
| *name_length = keyspace_meta->name().size(); |
| } |
| |
| cass_bool_t cass_keyspace_meta_is_virtual(const CassKeyspaceMeta* keyspace_meta) { |
| return keyspace_meta->is_virtual() ? cass_true : cass_false; |
| } |
| |
| const CassTableMeta* cass_keyspace_meta_table_by_name(const CassKeyspaceMeta* keyspace_meta, |
| const char* table) { |
| return cass_keyspace_meta_table_by_name_n(keyspace_meta, table, SAFE_STRLEN(table)); |
| } |
| |
| const CassTableMeta* cass_keyspace_meta_table_by_name_n(const CassKeyspaceMeta* keyspace_meta, |
| const char* table, size_t table_length) { |
| |
| return CassTableMeta::to(keyspace_meta->get_table(String(table, table_length))); |
| } |
| |
| const CassMaterializedViewMeta* |
| cass_keyspace_meta_materialized_view_by_name(const CassKeyspaceMeta* keyspace_meta, |
| const char* view) { |
| return cass_keyspace_meta_materialized_view_by_name_n(keyspace_meta, view, SAFE_STRLEN(view)); |
| } |
| |
| const CassMaterializedViewMeta* |
| cass_keyspace_meta_materialized_view_by_name_n(const CassKeyspaceMeta* keyspace_meta, |
| const char* view, size_t view_length) { |
| |
| return CassMaterializedViewMeta::to(keyspace_meta->get_view(String(view, view_length))); |
| } |
| |
| const CassDataType* cass_keyspace_meta_user_type_by_name(const CassKeyspaceMeta* keyspace_meta, |
| const char* type) { |
| return cass_keyspace_meta_user_type_by_name_n(keyspace_meta, type, SAFE_STRLEN(type)); |
| } |
| |
| const CassDataType* cass_keyspace_meta_user_type_by_name_n(const CassKeyspaceMeta* keyspace_meta, |
| const char* type, size_t type_length) { |
| return CassDataType::to(keyspace_meta->get_user_type(String(type, type_length))); |
| } |
| |
| const CassFunctionMeta* cass_keyspace_meta_function_by_name(const CassKeyspaceMeta* keyspace_meta, |
| const char* name, |
| const char* arguments) { |
| return cass_keyspace_meta_function_by_name_n(keyspace_meta, name, SAFE_STRLEN(name), arguments, |
| SAFE_STRLEN(arguments)); |
| } |
| |
| const CassFunctionMeta* cass_keyspace_meta_function_by_name_n(const CassKeyspaceMeta* keyspace_meta, |
| const char* name, size_t name_length, |
| const char* arguments, |
| size_t arguments_length) { |
| String full_function_name(name, name_length); |
| return CassFunctionMeta::to(keyspace_meta->get_function( |
| append_arguments(full_function_name, String(arguments, arguments_length)))); |
| } |
| |
| const CassAggregateMeta* cass_keyspace_meta_aggregate_by_name(const CassKeyspaceMeta* keyspace_meta, |
| const char* name, |
| const char* arguments) { |
| return cass_keyspace_meta_aggregate_by_name_n(keyspace_meta, name, SAFE_STRLEN(name), arguments, |
| SAFE_STRLEN(arguments)); |
| } |
| |
| const CassAggregateMeta* |
| cass_keyspace_meta_aggregate_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* name, |
| size_t name_length, const char* arguments, |
| size_t arguments_length) { |
| String full_aggregate_name(name, name_length); |
| return CassAggregateMeta::to(keyspace_meta->get_aggregate( |
| append_arguments(full_aggregate_name, String(arguments, arguments_length)))); |
| } |
| |
| const CassValue* cass_keyspace_meta_field_by_name(const CassKeyspaceMeta* keyspace_meta, |
| const char* name) { |
| return cass_keyspace_meta_field_by_name_n(keyspace_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, |
| const char* name, size_t name_length) { |
| return CassValue::to(keyspace_meta->get_field(String(name, name_length))); |
| } |
| |
| void cass_table_meta_name(const CassTableMeta* table_meta, const char** name, size_t* name_length) { |
| *name = table_meta->name().data(); |
| *name_length = table_meta->name().size(); |
| } |
| |
| cass_bool_t cass_table_meta_is_virtual(const CassTableMeta* table_meta) { |
| return table_meta->is_virtual() ? cass_true : cass_false; |
| } |
| |
| const CassColumnMeta* cass_table_meta_column_by_name(const CassTableMeta* table_meta, |
| const char* column) { |
| return cass_table_meta_column_by_name_n(table_meta, column, SAFE_STRLEN(column)); |
| } |
| |
| const CassColumnMeta* cass_table_meta_column_by_name_n(const CassTableMeta* table_meta, |
| const char* column, size_t column_length) { |
| return CassColumnMeta::to(table_meta->get_column(String(column, column_length))); |
| } |
| |
| size_t cass_table_meta_column_count(const CassTableMeta* table_meta) { |
| return table_meta->columns().size(); |
| } |
| |
| const CassColumnMeta* cass_table_meta_column(const CassTableMeta* table_meta, size_t index) { |
| if (index >= table_meta->columns().size()) { |
| return NULL; |
| } |
| return CassColumnMeta::to(table_meta->columns()[index].get()); |
| } |
| |
| const CassIndexMeta* cass_table_meta_index_by_name(const CassTableMeta* table_meta, |
| const char* index) { |
| return cass_table_meta_index_by_name_n(table_meta, index, SAFE_STRLEN(index)); |
| } |
| |
| const CassIndexMeta* cass_table_meta_index_by_name_n(const CassTableMeta* table_meta, |
| const char* index, size_t index_length) { |
| return CassIndexMeta::to(table_meta->get_index(String(index, index_length))); |
| } |
| |
| size_t cass_table_meta_index_count(const CassTableMeta* table_meta) { |
| return table_meta->indexes().size(); |
| } |
| |
| const CassIndexMeta* cass_table_meta_index(const CassTableMeta* table_meta, size_t index) { |
| if (index >= table_meta->indexes().size()) { |
| return NULL; |
| } |
| return CassIndexMeta::to(table_meta->indexes()[index].get()); |
| } |
| |
| const CassMaterializedViewMeta* |
| cass_table_meta_materialized_view_by_name(const CassTableMeta* table_meta, const char* view) { |
| return cass_table_meta_materialized_view_by_name_n(table_meta, view, SAFE_STRLEN(view)); |
| } |
| |
| const CassMaterializedViewMeta* |
| cass_table_meta_materialized_view_by_name_n(const CassTableMeta* table_meta, const char* view, |
| size_t view_length) { |
| return CassMaterializedViewMeta::to(table_meta->get_view(String(view, view_length))); |
| } |
| |
| size_t cass_table_meta_materialized_view_count(const CassTableMeta* table_meta) { |
| return table_meta->views().size(); |
| } |
| |
| const CassMaterializedViewMeta* cass_table_meta_materialized_view(const CassTableMeta* table_meta, |
| size_t index) { |
| if (index >= table_meta->views().size()) { |
| return NULL; |
| } |
| return CassMaterializedViewMeta::to(table_meta->views()[index].get()); |
| } |
| |
| size_t cass_table_meta_partition_key_count(const CassTableMeta* table_meta) { |
| return table_meta->partition_key().size(); |
| } |
| |
| const CassColumnMeta* cass_table_meta_partition_key(const CassTableMeta* table_meta, size_t index) { |
| if (index >= table_meta->partition_key().size()) { |
| return NULL; |
| } |
| return CassColumnMeta::to(table_meta->partition_key()[index].get()); |
| } |
| |
| size_t cass_table_meta_clustering_key_count(const CassTableMeta* table_meta) { |
| return table_meta->clustering_key().size(); |
| } |
| |
| const CassColumnMeta* cass_table_meta_clustering_key(const CassTableMeta* table_meta, |
| size_t index) { |
| if (index >= table_meta->clustering_key().size()) { |
| return NULL; |
| } |
| return CassColumnMeta::to(table_meta->clustering_key()[index].get()); |
| } |
| |
| CassClusteringOrder cass_table_meta_clustering_key_order(const CassTableMeta* table_meta, |
| size_t index) { |
| if (index >= table_meta->clustering_key_order().size()) { |
| return CASS_CLUSTERING_ORDER_NONE; |
| } |
| return table_meta->clustering_key_order()[index]; |
| } |
| |
| const CassValue* cass_table_meta_field_by_name(const CassTableMeta* table_meta, const char* name) { |
| return cass_table_meta_field_by_name_n(table_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, const char* name, |
| size_t name_length) { |
| return CassValue::to(table_meta->get_field(String(name, name_length))); |
| } |
| |
| const CassColumnMeta* |
| cass_materialized_view_meta_column_by_name(const CassMaterializedViewMeta* view_meta, |
| const char* column) { |
| return cass_materialized_view_meta_column_by_name_n(view_meta, column, SAFE_STRLEN(column)); |
| } |
| |
| const CassColumnMeta* |
| cass_materialized_view_meta_column_by_name_n(const CassMaterializedViewMeta* view_meta, |
| const char* column, size_t column_length) { |
| return CassColumnMeta::to(view_meta->get_column(String(column, column_length))); |
| } |
| |
| void cass_materialized_view_meta_name(const CassMaterializedViewMeta* view_meta, const char** name, |
| size_t* name_length) { |
| *name = view_meta->name().data(); |
| *name_length = view_meta->name().size(); |
| } |
| |
| const CassTableMeta* |
| cass_materialized_view_meta_base_table(const CassMaterializedViewMeta* view_meta) { |
| if (view_meta == NULL) { // Materialized views may be NULL (Cassandra < v3.0.0) |
| return NULL; |
| } |
| return CassTableMeta::to(view_meta->base_table()); |
| } |
| |
| const CassValue* |
| cass_materialized_view_meta_field_by_name(const CassMaterializedViewMeta* view_meta, |
| const char* name) { |
| return cass_materialized_view_meta_field_by_name_n(view_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* |
| cass_materialized_view_meta_field_by_name_n(const CassMaterializedViewMeta* view_meta, |
| const char* name, size_t name_length) { |
| return CassValue::to(view_meta->get_field(String(name, name_length))); |
| } |
| |
| size_t cass_materialized_view_meta_column_count(const CassMaterializedViewMeta* view_meta) { |
| return view_meta->columns().size(); |
| } |
| |
| const CassColumnMeta* cass_materialized_view_meta_column(const CassMaterializedViewMeta* view_meta, |
| size_t index) { |
| if (index >= view_meta->columns().size()) { |
| return NULL; |
| } |
| return CassColumnMeta::to(view_meta->columns()[index].get()); |
| } |
| |
| size_t cass_materialized_view_meta_partition_key_count(const CassMaterializedViewMeta* view_meta) { |
| return view_meta->partition_key().size(); |
| } |
| |
| const CassColumnMeta* |
| cass_materialized_view_meta_partition_key(const CassMaterializedViewMeta* view_meta, size_t index) { |
| if (index >= view_meta->partition_key().size()) { |
| return NULL; |
| } |
| return CassColumnMeta::to(view_meta->partition_key()[index].get()); |
| } |
| |
| size_t cass_materialized_view_meta_clustering_key_count(const CassMaterializedViewMeta* view_meta) { |
| return view_meta->clustering_key().size(); |
| } |
| |
| const CassColumnMeta* |
| cass_materialized_view_meta_clustering_key(const CassMaterializedViewMeta* view_meta, |
| size_t index) { |
| if (index >= view_meta->clustering_key().size()) { |
| return NULL; |
| } |
| return CassColumnMeta::to(view_meta->clustering_key()[index].get()); |
| } |
| |
| CassClusteringOrder |
| cass_materialized_view_meta_clustering_key_order(const CassMaterializedViewMeta* view_meta, |
| size_t index) { |
| if (index >= view_meta->clustering_key_order().size()) { |
| return CASS_CLUSTERING_ORDER_NONE; |
| } |
| return view_meta->clustering_key_order()[index]; |
| } |
| |
| void cass_column_meta_name(const CassColumnMeta* column_meta, const char** name, |
| size_t* name_length) { |
| *name = column_meta->name().data(); |
| *name_length = column_meta->name().size(); |
| } |
| |
| CassColumnType cass_column_meta_type(const CassColumnMeta* column_meta) { |
| return column_meta->type(); |
| } |
| |
| const CassDataType* cass_column_meta_data_type(const CassColumnMeta* column_meta) { |
| return CassDataType::to(column_meta->data_type().get()); |
| } |
| |
| const CassValue* cass_column_meta_field_by_name(const CassColumnMeta* column_meta, |
| const char* name) { |
| return cass_column_meta_field_by_name_n(column_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* cass_column_meta_field_by_name_n(const CassColumnMeta* column_meta, |
| const char* name, size_t name_length) { |
| return CassValue::to(column_meta->get_field(String(name, name_length))); |
| } |
| |
| void cass_index_meta_name(const CassIndexMeta* index_meta, const char** name, size_t* name_length) { |
| *name = index_meta->name().data(); |
| *name_length = index_meta->name().size(); |
| } |
| |
| CassIndexType cass_index_meta_type(const CassIndexMeta* index_meta) { return index_meta->type(); } |
| |
| void cass_index_meta_target(const CassIndexMeta* index_meta, const char** target, |
| size_t* target_length) { |
| *target = index_meta->target().data(); |
| *target_length = index_meta->target().size(); |
| } |
| |
| const CassValue* cass_index_meta_options(const CassIndexMeta* index_meta) { |
| return CassValue::to(index_meta->options()); |
| } |
| |
| const CassValue* cass_index_meta_field_by_name(const CassIndexMeta* index_meta, const char* name) { |
| return cass_index_meta_field_by_name_n(index_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* cass_index_meta_field_by_name_n(const CassIndexMeta* index_meta, const char* name, |
| size_t name_length) { |
| return CassValue::to(index_meta->get_field(String(name, name_length))); |
| } |
| |
| void cass_function_meta_name(const CassFunctionMeta* function_meta, const char** name, |
| size_t* name_length) { |
| *name = function_meta->simple_name().data(); |
| *name_length = function_meta->simple_name().size(); |
| } |
| |
| void cass_function_meta_full_name(const CassFunctionMeta* function_meta, const char** full_name, |
| size_t* full_name_length) { |
| *full_name = function_meta->name().data(); |
| *full_name_length = function_meta->name().size(); |
| } |
| |
| void cass_function_meta_body(const CassFunctionMeta* function_meta, const char** body, |
| size_t* body_length) { |
| *body = function_meta->body().data(); |
| *body_length = function_meta->body().size(); |
| } |
| |
| void cass_function_meta_language(const CassFunctionMeta* function_meta, const char** language, |
| size_t* language_length) { |
| *language = function_meta->language().data(); |
| *language_length = function_meta->language().size(); |
| } |
| |
| cass_bool_t cass_function_meta_called_on_null_input(const CassFunctionMeta* function_meta) { |
| return function_meta->called_on_null_input() ? cass_true : cass_false; |
| } |
| |
| size_t cass_function_meta_argument_count(const CassFunctionMeta* function_meta) { |
| return function_meta->args().size(); |
| } |
| |
| CassError cass_function_meta_argument(const CassFunctionMeta* function_meta, size_t index, |
| const char** name, size_t* name_length, |
| const CassDataType** type) { |
| if (index >= function_meta->args().size()) { |
| return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS; |
| } |
| const FunctionMetadata::Argument& arg = function_meta->args()[index]; |
| *name = arg.name.data(); |
| *name_length = arg.name.size(); |
| *type = CassDataType::to(arg.type.get()); |
| return CASS_OK; |
| } |
| |
| const CassDataType* cass_function_meta_argument_type_by_name(const CassFunctionMeta* function_meta, |
| const char* name) { |
| return cass_function_meta_argument_type_by_name_n(function_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassDataType* |
| cass_function_meta_argument_type_by_name_n(const CassFunctionMeta* function_meta, const char* name, |
| size_t name_length) { |
| return CassDataType::to(function_meta->get_arg_type(StringRef(name, name_length))); |
| } |
| |
| const CassDataType* cass_function_meta_return_type(const CassFunctionMeta* function_meta) { |
| return CassDataType::to(function_meta->return_type().get()); |
| } |
| |
| const CassValue* cass_function_meta_field_by_name(const CassFunctionMeta* function_meta, |
| const char* name) { |
| return cass_function_meta_field_by_name_n(function_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* cass_function_meta_field_by_name_n(const CassFunctionMeta* function_meta, |
| const char* name, size_t name_length) { |
| return CassValue::to(function_meta->get_field(String(name, name_length))); |
| } |
| |
| void cass_aggregate_meta_name(const CassAggregateMeta* aggregate_meta, const char** name, |
| size_t* name_length) { |
| *name = aggregate_meta->simple_name().data(); |
| *name_length = aggregate_meta->simple_name().size(); |
| } |
| |
| void cass_aggregate_meta_full_name(const CassAggregateMeta* aggregate_meta, const char** full_name, |
| size_t* full_name_length) { |
| *full_name = aggregate_meta->name().data(); |
| *full_name_length = aggregate_meta->name().size(); |
| } |
| |
| size_t cass_aggregate_meta_argument_count(const CassAggregateMeta* aggregate_meta) { |
| return aggregate_meta->arg_types().size(); |
| } |
| |
| const CassDataType* cass_aggregate_meta_argument_type(const CassAggregateMeta* aggregate_meta, |
| size_t index) { |
| if (index >= aggregate_meta->arg_types().size()) { |
| return NULL; |
| } |
| return CassDataType::to(aggregate_meta->arg_types()[index].get()); |
| } |
| |
| const CassDataType* cass_aggregate_meta_return_type(const CassAggregateMeta* aggregate_meta) { |
| return CassDataType::to(aggregate_meta->return_type().get()); |
| } |
| |
| const CassDataType* cass_aggregate_meta_state_type(const CassAggregateMeta* aggregate_meta) { |
| return CassDataType::to(aggregate_meta->state_type().get()); |
| } |
| |
| const CassFunctionMeta* cass_aggregate_meta_state_func(const CassAggregateMeta* aggregate_meta) { |
| return CassFunctionMeta::to(aggregate_meta->state_func().get()); |
| } |
| |
| const CassFunctionMeta* cass_aggregate_meta_final_func(const CassAggregateMeta* aggregate_meta) { |
| return CassFunctionMeta::to(aggregate_meta->final_func().get()); |
| } |
| |
| const CassValue* cass_aggregate_meta_init_cond(const CassAggregateMeta* aggregate_meta) { |
| return CassValue::to(&aggregate_meta->init_cond()); |
| } |
| |
| const CassValue* cass_aggregate_meta_field_by_name(const CassAggregateMeta* aggregate_meta, |
| const char* name) { |
| return cass_aggregate_meta_field_by_name_n(aggregate_meta, name, SAFE_STRLEN(name)); |
| } |
| |
| const CassValue* cass_aggregate_meta_field_by_name_n(const CassAggregateMeta* aggregate_meta, |
| const char* name, size_t name_length) { |
| return CassValue::to(aggregate_meta->get_field(String(name, name_length))); |
| } |
| |
| CassIterator* cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta) { |
| return CassIterator::to(schema_meta->iterator_keyspaces()); |
| } |
| |
| CassIterator* cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { |
| return CassIterator::to(keyspace_meta->iterator_tables()); |
| } |
| |
| CassIterator* |
| cass_iterator_materialized_views_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { |
| return CassIterator::to(keyspace_meta->iterator_views()); |
| } |
| |
| CassIterator* cass_iterator_user_types_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { |
| return CassIterator::to(keyspace_meta->iterator_user_types()); |
| } |
| |
| CassIterator* cass_iterator_functions_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { |
| return CassIterator::to(keyspace_meta->iterator_functions()); |
| } |
| |
| CassIterator* cass_iterator_aggregates_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { |
| return CassIterator::to(keyspace_meta->iterator_aggregates()); |
| } |
| |
| CassIterator* cass_iterator_fields_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta) { |
| return CassIterator::to(keyspace_meta->iterator_fields()); |
| } |
| |
| CassIterator* cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta) { |
| return CassIterator::to(table_meta->iterator_columns()); |
| } |
| |
| CassIterator* cass_iterator_materialized_views_from_table_meta(const CassTableMeta* table_meta) { |
| return CassIterator::to(table_meta->iterator_views()); |
| } |
| |
| CassIterator* cass_iterator_indexes_from_table_meta(const CassTableMeta* table_meta) { |
| return CassIterator::to(table_meta->iterator_indexes()); |
| } |
| |
| CassIterator* cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta) { |
| return CassIterator::to(table_meta->iterator_fields()); |
| } |
| |
| CassIterator* |
| cass_iterator_columns_from_materialized_view_meta(const CassMaterializedViewMeta* view_meta) { |
| return CassIterator::to(view_meta->iterator_columns()); |
| } |
| |
| CassIterator* |
| cass_iterator_fields_from_materialized_view_meta(const CassMaterializedViewMeta* view_meta) { |
| return CassIterator::to(view_meta->iterator_fields()); |
| } |
| |
| CassIterator* cass_iterator_fields_from_column_meta(const CassColumnMeta* column_meta) { |
| return CassIterator::to(column_meta->iterator_fields()); |
| } |
| |
| CassIterator* cass_iterator_fields_from_index_meta(const CassIndexMeta* index_meta) { |
| return CassIterator::to(index_meta->iterator_fields()); |
| } |
| |
| CassIterator* cass_iterator_fields_from_function_meta(const CassFunctionMeta* function_meta) { |
| return CassIterator::to(function_meta->iterator_fields()); |
| } |
| |
| CassIterator* cass_iterator_fields_from_aggregate_meta(const CassAggregateMeta* aggregate_meta) { |
| return CassIterator::to(aggregate_meta->iterator_fields()); |
| } |
| |
| const CassKeyspaceMeta* cass_iterator_get_keyspace_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_KEYSPACE_META) { |
| return NULL; |
| } |
| return CassKeyspaceMeta::to( |
| static_cast<const Metadata::KeyspaceIterator*>(iterator->from())->keyspace()); |
| } |
| |
| const CassTableMeta* cass_iterator_get_table_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_TABLE_META) { |
| return NULL; |
| } |
| return CassTableMeta::to( |
| static_cast<const KeyspaceMetadata::TableIterator*>(iterator->from())->table()); |
| } |
| |
| const CassMaterializedViewMeta* |
| cass_iterator_get_materialized_view_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_MATERIALIZED_VIEW_META) { |
| return NULL; |
| } |
| return CassMaterializedViewMeta::to( |
| static_cast<const ViewIteratorBase*>(iterator->from())->view()); |
| } |
| |
| const CassDataType* cass_iterator_get_user_type(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_TYPE_META) { |
| return NULL; |
| } |
| return CassDataType::to( |
| static_cast<const KeyspaceMetadata::TypeIterator*>(iterator->from())->type()); |
| } |
| |
| const CassFunctionMeta* cass_iterator_get_function_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_FUNCTION_META) { |
| return NULL; |
| } |
| return CassFunctionMeta::to( |
| static_cast<const KeyspaceMetadata::FunctionIterator*>(iterator->from())->function()); |
| } |
| |
| const CassAggregateMeta* cass_iterator_get_aggregate_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_AGGREGATE_META) { |
| return NULL; |
| } |
| return CassAggregateMeta::to( |
| static_cast<const KeyspaceMetadata::AggregateIterator*>(iterator->from())->aggregate()); |
| } |
| |
| const CassColumnMeta* cass_iterator_get_column_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_COLUMN_META) { |
| return NULL; |
| } |
| return CassColumnMeta::to( |
| static_cast<const TableMetadata::ColumnIterator*>(iterator->from())->column()); |
| } |
| |
| const CassIndexMeta* cass_iterator_get_index_meta(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_INDEX_META) { |
| return NULL; |
| } |
| return CassIndexMeta::to( |
| static_cast<const TableMetadata::IndexIterator*>(iterator->from())->index()); |
| } |
| |
| CassError cass_iterator_get_meta_field_name(const CassIterator* iterator, const char** name, |
| size_t* name_length) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_META_FIELD) { |
| return CASS_ERROR_LIB_BAD_PARAMS; |
| } |
| const MetadataField* field = static_cast<const MetadataFieldIterator*>(iterator->from())->field(); |
| *name = field->name().data(); |
| *name_length = field->name().size(); |
| return CASS_OK; |
| } |
| |
| const CassValue* cass_iterator_get_meta_field_value(const CassIterator* iterator) { |
| if (iterator->type() != CASS_ITERATOR_TYPE_META_FIELD) { |
| return NULL; |
| } |
| return CassValue::to( |
| static_cast<const MetadataFieldIterator*>(iterator->from())->field()->value()); |
| } |
| |
| } // extern "C" |
| |
| static const char* table_column_name(const VersionNumber& server_version) { |
| return server_version >= VersionNumber(3, 0, 0) ? "table_name" : "columnfamily_name"; |
| } |
| |
| static const char* signature_column_name(const VersionNumber& server_version) { |
| return server_version >= VersionNumber(3, 0, 0) ? "argument_types" : "signature"; |
| } |
| |
| template <class T> |
| const T& as_const(const T& x) { |
| return x; |
| } |
| |
| const KeyspaceMetadata* Metadata::SchemaSnapshot::get_keyspace(const String& name) const { |
| KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(name); |
| if (i == keyspaces_->end()) return NULL; |
| return &i->second; |
| } |
| |
| const UserType* Metadata::SchemaSnapshot::get_user_type(const String& keyspace_name, |
| const String& type_name) const { |
| KeyspaceMetadata::Map::const_iterator i = keyspaces_->find(keyspace_name); |
| if (i == keyspaces_->end()) { |
| return NULL; |
| } |
| return i->second.get_user_type(type_name); |
| } |
| |
| String Metadata::full_function_name(const String& name, const StringVec& signature) { |
| String full_function_name(name); |
| full_function_name.push_back('('); |
| for (StringVec::const_iterator i = signature.begin(), end = signature.end(); i != end; ++i) { |
| String argument(*i); |
| // Remove white-space |
| argument.erase(std::remove_if(argument.begin(), argument.end(), ::isspace), argument.end()); |
| if (!argument.empty()) { |
| if (i != signature.begin()) full_function_name.push_back(','); |
| full_function_name.append(argument); |
| } |
| } |
| full_function_name.push_back(')'); |
| return full_function_name; |
| } |
| |
| Metadata::SchemaSnapshot Metadata::schema_snapshot() const { |
| ScopedMutex l(&mutex_); |
| return SchemaSnapshot(schema_snapshot_version_, server_version_, front_.keyspaces()); |
| } |
| |
| void Metadata::update_keyspaces(const ResultResponse* result, bool is_virtual) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_keyspaces(server_version_, result, is_virtual); |
| } else { |
| updating_->update_keyspaces(server_version_, result, is_virtual); |
| } |
| } |
| |
| void Metadata::update_tables(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_tables(server_version_, result); |
| } else { |
| updating_->update_tables(server_version_, result); |
| } |
| } |
| |
| void Metadata::update_views(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_views(server_version_, result); |
| } else { |
| updating_->update_views(server_version_, result); |
| } |
| } |
| |
| void Metadata::update_columns(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_columns(server_version_, cache_, result); |
| if (server_version_ < VersionNumber(3, 0, 0)) { |
| updating_->update_legacy_indexes(server_version_, result); |
| } |
| } else { |
| updating_->update_columns(server_version_, cache_, result); |
| if (server_version_ < VersionNumber(3, 0, 0)) { |
| updating_->update_legacy_indexes(server_version_, result); |
| } |
| } |
| } |
| |
| void Metadata::update_indexes(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_indexes(server_version_, result); |
| } else { |
| updating_->update_indexes(server_version_, result); |
| } |
| } |
| |
| void Metadata::update_user_types(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_user_types(server_version_, cache_, result); |
| } else { |
| updating_->update_user_types(server_version_, cache_, result); |
| } |
| } |
| |
| void Metadata::update_functions(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_functions(server_version_, cache_, result); |
| } else { |
| updating_->update_functions(server_version_, cache_, result); |
| } |
| } |
| |
| void Metadata::update_aggregates(const ResultResponse* result) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->update_aggregates(server_version_, cache_, result); |
| } else { |
| updating_->update_aggregates(server_version_, cache_, result); |
| } |
| } |
| |
| void Metadata::drop_keyspace(const String& keyspace_name) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->drop_keyspace(keyspace_name); |
| } else { |
| updating_->drop_keyspace(keyspace_name); |
| } |
| } |
| |
| void Metadata::drop_table_or_view(const String& keyspace_name, const String& table_or_view_name) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->drop_table_or_view(keyspace_name, table_or_view_name); |
| } else { |
| updating_->drop_table_or_view(keyspace_name, table_or_view_name); |
| } |
| } |
| |
| void Metadata::drop_user_type(const String& keyspace_name, const String& type_name) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->drop_user_type(keyspace_name, type_name); |
| } else { |
| updating_->drop_user_type(keyspace_name, type_name); |
| } |
| } |
| |
| void Metadata::drop_function(const String& keyspace_name, const String& full_function_name) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->drop_function(keyspace_name, full_function_name); |
| } else { |
| updating_->drop_function(keyspace_name, full_function_name); |
| } |
| } |
| |
| void Metadata::drop_aggregate(const String& keyspace_name, const String& full_aggregate_name) { |
| schema_snapshot_version_++; |
| |
| if (is_front_buffer()) { |
| ScopedMutex l(&mutex_); |
| updating_->drop_aggregate(keyspace_name, full_aggregate_name); |
| } else { |
| updating_->drop_aggregate(keyspace_name, full_aggregate_name); |
| } |
| } |
| |
| void Metadata::clear_and_update_back(const VersionNumber& server_version) { |
| { |
| ScopedMutex l(&mutex_); |
| server_version_ = server_version; |
| } |
| back_.clear(); |
| updating_ = &back_; |
| } |
| |
| void Metadata::swap_to_back_and_update_front() { |
| { |
| ScopedMutex l(&mutex_); |
| schema_snapshot_version_++; |
| front_.swap(back_); |
| } |
| back_.clear(); |
| updating_ = &front_; |
| } |
| |
| void Metadata::clear() { |
| { |
| ScopedMutex l(&mutex_); |
| schema_snapshot_version_ = 0; |
| front_.clear(); |
| } |
| back_.clear(); |
| } |
| |
| const Value* MetadataBase::get_field(const String& name) const { |
| MetadataField::Map::const_iterator it = fields_.find(name); |
| if (it == fields_.end()) return NULL; |
| return it->second.value(); |
| } |
| |
| String MetadataBase::get_string_field(const String& name) const { |
| const Value* value = get_field(name); |
| if (value == NULL) return String(); |
| return value->to_string(); |
| } |
| |
| const Value* MetadataBase::add_field(const RefBuffer::Ptr& buffer, const Row* row, |
| const String& name) { |
| const Value* value = row->get_by_name(name); |
| if (value == NULL) return NULL; |
| if (value->is_null()) { |
| fields_[name] = MetadataField(name); |
| return NULL; // Return NULL for "null" columns |
| } else { |
| fields_[name] = MetadataField(name, *value, buffer); |
| return value; |
| } |
| } |
| |
| void MetadataBase::add_field(const RefBuffer::Ptr& buffer, const Value& value, const String& name) { |
| fields_[name] = MetadataField(name, value, buffer); |
| } |
| |
| void MetadataBase::add_json_list_field(const Row* row, const String& name) { |
| const Value* value = row->get_by_name(name); |
| if (value == NULL) return; |
| if (value->is_null()) { |
| fields_[name] = MetadataField(name); |
| return; |
| } |
| |
| Vector<char> buf = value->decoder().as_vector(); |
| json::Document d; |
| d.ParseInsitu(&buf[0]); |
| |
| if (d.HasParseError()) { |
| LOG_ERROR("Unable to parse JSON (array) for column '%s'", name.c_str()); |
| return; |
| } |
| |
| if (!d.IsArray()) { |
| LOG_DEBUG("Expected JSON array for column '%s' (probably null or empty)", name.c_str()); |
| fields_[name] = MetadataField(name); |
| return; |
| } |
| |
| Collection collection( |
| CollectionType::list(DataType::Ptr(new DataType(CASS_VALUE_TYPE_TEXT)), false), d.Size()); |
| for (json::Value::ConstValueIterator i = d.Begin(); i != d.End(); ++i) { |
| collection.append(CassString(i->GetString(), i->GetStringLength())); |
| } |
| |
| size_t encoded_size = collection.get_items_size(); |
| RefBuffer::Ptr encoded(RefBuffer::create(encoded_size)); |
| |
| collection.encode_items(encoded->data()); |
| |
| Value list(collection.data_type(), d.Size(), |
| Decoder(encoded->data(), encoded_size, value->protocol_version())); |
| fields_[name] = MetadataField(name, list, encoded); |
| } |
| |
| const Value* MetadataBase::add_json_map_field(const Row* row, const String& name) { |
| const Value* value = row->get_by_name(name); |
| if (value == NULL) return NULL; |
| if (value->is_null()) { |
| return (fields_[name] = MetadataField(name)).value(); |
| } |
| |
| Vector<char> buf = value->decoder().as_vector(); |
| json::Document d; |
| d.ParseInsitu(&buf[0]); |
| |
| if (d.HasParseError()) { |
| LOG_ERROR("Unable to parse JSON (object) for column '%s'", name.c_str()); |
| return (fields_[name] = MetadataField(name)).value(); |
| } |
| |
| if (!d.IsObject()) { |
| LOG_DEBUG("Expected JSON object for column '%s' (probably null or empty)", name.c_str()); |
| fields_[name] = MetadataField(name); |
| return (fields_[name] = MetadataField(name)).value(); |
| } |
| |
| Collection collection(CollectionType::map(DataType::Ptr(new DataType(CASS_VALUE_TYPE_TEXT)), |
| DataType::Ptr(new DataType(CASS_VALUE_TYPE_TEXT)), |
| false), |
| 2 * d.MemberCount()); |
| for (json::Value::ConstMemberIterator i = d.MemberBegin(); i != d.MemberEnd(); ++i) { |
| collection.append(CassString(i->name.GetString(), i->name.GetStringLength())); |
| collection.append(CassString(i->value.GetString(), i->value.GetStringLength())); |
| } |
| |
| size_t encoded_size = collection.get_items_size(); |
| RefBuffer::Ptr encoded(RefBuffer::create(encoded_size)); |
| |
| collection.encode_items(encoded->data()); |
| |
| Value map(collection.data_type(), d.MemberCount(), |
| Decoder(encoded->data(), encoded_size, value->protocol_version())); |
| |
| return (fields_[name] = MetadataField(name, map, encoded)).value(); |
| } |
| |
| const TableMetadata* KeyspaceMetadata::get_table(const String& name) const { |
| TableMetadata::Map::const_iterator i = tables_->find(name); |
| if (i == tables_->end()) return NULL; |
| return i->second.get(); |
| } |
| |
| const TableMetadata::Ptr& KeyspaceMetadata::get_table(const String& name) { |
| TableMetadata::Map::iterator i = tables_->find(name); |
| if (i == tables_->end()) return TableMetadata::NIL; |
| return i->second; |
| } |
| |
| void KeyspaceMetadata::add_table(const TableMetadata::Ptr& table) { |
| TableMetadata::Map::iterator table_it = tables_->find(table->name()); |
| |
| // If there's a previous version of this table then copy its views |
| // to the new version of the table, and update the table back-refs |
| // in the views. |
| if (table_it != tables_->end()) { |
| TableMetadata::Ptr old_table(table_it->second); |
| internal_add_table(table, old_table->views()); |
| } else { |
| (*tables_)[table->name()] = table; // Add new table |
| } |
| } |
| |
| void KeyspaceMetadata::internal_add_table(const TableMetadata::Ptr& table, |
| const ViewMetadata::Vec& views) { |
| // Copy all the views and update the table and keyspace views |
| for (ViewMetadata::Vec::const_iterator i = views.begin(); i != views.end(); ++i) { |
| ViewMetadata::Ptr view(new ViewMetadata(**i, table.get())); |
| table->add_view(view); |
| (*views_)[view->name()] = view; |
| } |
| (*tables_)[table->name()] = table; |
| } |
| |
| const ViewMetadata* KeyspaceMetadata::get_view(const String& name) const { |
| ViewMetadata::Map::const_iterator i = views_->find(name); |
| if (i == views_->end()) return NULL; |
| return i->second.get(); |
| } |
| |
| const ViewMetadata::Ptr& KeyspaceMetadata::get_view(const String& name) { |
| ViewMetadata::Map::iterator i = views_->find(name); |
| if (i == views_->end()) return ViewMetadata::NIL; |
| return i->second; |
| } |
| |
| void KeyspaceMetadata::add_view(const ViewMetadata::Ptr& view) { (*views_)[view->name()] = view; } |
| |
| void KeyspaceMetadata::drop_table_or_view(const String& table_or_view_name) { |
| TableMetadata::Map::iterator table_it = tables_->find(table_or_view_name); |
| if (table_it != tables_->end()) { // The name is for a table, remove the |
| // table and views from keyspace |
| TableMetadata::Ptr table(table_it->second); |
| // Cassandra doesn't allow for tables to be dropped while it has active |
| // views, but it could be possible for the drop events to arrive out of |
| // order. |
| for (ViewMetadata::Vec::const_iterator i = table->views().begin(), end = table->views().end(); |
| i != end; ++i) { |
| views_->erase((*i)->name()); |
| } |
| tables_->erase(table_it); |
| } else { // The name is for a view, remove the view from the table and keyspace |
| ViewMetadata::Map::iterator view_it = views_->find(table_or_view_name); |
| if (view_it != views_->end()) { |
| ViewMetadata::Ptr view(view_it->second); |
| |
| // Remove view from the base table's views |
| ViewMetadata::Vec views(view->base_table()->views()); |
| ViewMetadata::Vec::iterator i = |
| std::lower_bound(views.begin(), views.end(), table_or_view_name); |
| if (i != views.end() && (*i)->name() == table_or_view_name) { |
| views.erase(i); |
| } |
| |
| // Create and add a new copy of the base table |
| TableMetadata::Ptr table(new TableMetadata(*view->base_table())); |
| internal_add_table(table, views); |
| |
| // Remove the dropped view |
| views_->erase(view_it); |
| } |
| } |
| } |
| |
| const UserType::Ptr& KeyspaceMetadata::get_or_create_user_type(const String& name, bool is_frozen) { |
| UserType::Map::iterator i = user_types_->find(name); |
| if (i == user_types_->end()) { |
| i = user_types_ |
| ->insert(std::make_pair( |
| name, UserType::Ptr(new UserType(MetadataBase::name(), name, is_frozen)))) |
| .first; |
| } |
| return i->second; |
| } |
| |
| const UserType* KeyspaceMetadata::get_user_type(const String& name) const { |
| UserType::Map::const_iterator i = user_types_->find(name); |
| if (i == user_types_->end()) return NULL; |
| return i->second.get(); |
| } |
| |
| void KeyspaceMetadata::update(const VersionNumber& server_version, const RefBuffer::Ptr& buffer, |
| const Row* row) { |
| add_field(buffer, row, "keyspace_name"); |
| add_field(buffer, row, "durable_writes"); |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| const Value* map = add_field(buffer, row, "replication"); |
| if (map != NULL && map->value_type() == CASS_VALUE_TYPE_MAP && |
| is_string_type(map->primary_value_type()) && is_string_type(map->secondary_value_type())) { |
| MapIterator iterator(map); |
| while (iterator.next()) { |
| const Value* key = iterator.key(); |
| const Value* value = iterator.value(); |
| if (key->to_string_ref() == "class") { |
| strategy_class_ = value->to_string_ref(); |
| } |
| } |
| strategy_options_ = *map; |
| } |
| } else { |
| const Value* value = add_field(buffer, row, "strategy_class"); |
| if (value != NULL && is_string_type(value->value_type())) { |
| strategy_class_ = value->to_string_ref(); |
| } |
| const Value* map = add_json_map_field(row, "strategy_options"); |
| if (map != NULL) { |
| strategy_options_ = *map; |
| } |
| } |
| } |
| |
| void KeyspaceMetadata::drop_user_type(const String& type_name) { user_types_->erase(type_name); } |
| |
| void KeyspaceMetadata::add_function(const FunctionMetadata::Ptr& function) { |
| (*functions_)[function->name()] = function; |
| } |
| |
| const FunctionMetadata* KeyspaceMetadata::get_function(const String& full_function_name) const { |
| FunctionMetadata::Map::const_iterator i = functions_->find(full_function_name); |
| if (i == functions_->end()) return NULL; |
| return i->second.get(); |
| } |
| |
| void KeyspaceMetadata::drop_function(const String& full_function_name) { |
| functions_->erase(full_function_name); |
| } |
| |
| const AggregateMetadata* KeyspaceMetadata::get_aggregate(const String& full_aggregate_name) const { |
| AggregateMetadata::Map::const_iterator i = aggregates_->find(full_aggregate_name); |
| if (i == aggregates_->end()) return NULL; |
| return i->second.get(); |
| } |
| |
| void KeyspaceMetadata::add_aggregate(const AggregateMetadata::Ptr& aggregate) { |
| (*aggregates_)[aggregate->name()] = aggregate; |
| } |
| |
| void KeyspaceMetadata::drop_aggregate(const String& full_aggregate_name) { |
| aggregates_->erase(full_aggregate_name); |
| } |
| |
| TableMetadataBase::TableMetadataBase(const VersionNumber& server_version, const String& name, |
| const RefBuffer::Ptr& buffer, const Row* row, bool is_virtual) |
| : MetadataBase(name) |
| , is_virtual_(is_virtual) { |
| add_field(buffer, row, "keyspace_name"); |
| add_field(buffer, row, "bloom_filter_fp_chance"); |
| add_field(buffer, row, "caching"); |
| add_field(buffer, row, "comment"); |
| add_field(buffer, row, "default_time_to_live"); |
| add_field(buffer, row, "gc_grace_seconds"); |
| add_field(buffer, row, "id"); |
| add_field(buffer, row, "speculative_retry"); |
| add_field(buffer, row, "max_index_interval"); |
| add_field(buffer, row, "min_index_interval"); |
| add_field(buffer, row, "memtable_flush_period_in_ms"); |
| add_field(buffer, row, "read_repair_chance"); |
| |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| add_field(buffer, row, "dclocal_read_repair_chance"); |
| add_field(buffer, row, "crc_check_chance"); |
| add_field(buffer, row, "compaction"); |
| add_field(buffer, row, "compression"); |
| add_field(buffer, row, "extensions"); |
| } else { |
| add_field(buffer, row, "cf_id"); |
| add_field(buffer, row, "local_read_repair_chance"); |
| |
| add_field(buffer, row, "compaction_strategy_class"); |
| add_json_map_field(row, "compaction_strategy_options"); |
| add_json_map_field(row, "compression_parameters"); |
| |
| add_json_list_field(row, "column_aliases"); |
| add_field(buffer, row, "comparator"); |
| add_field(buffer, row, "subcomparator"); |
| add_field(buffer, row, "default_validator"); |
| add_field(buffer, row, "key_alias"); |
| add_json_list_field(row, "key_aliases"); |
| add_field(buffer, row, "value_alias"); |
| add_field(buffer, row, "key_validator"); |
| add_field(buffer, row, "type"); |
| |
| add_field(buffer, row, "dropped_columns"); |
| add_field(buffer, row, "index_interval"); |
| add_field(buffer, row, "is_dense"); |
| add_field(buffer, row, "max_compaction_threshold"); |
| add_field(buffer, row, "min_compaction_threshold"); |
| add_field(buffer, row, "populate_io_cache_on_flush"); |
| add_field(buffer, row, "replicate_on_write"); |
| } |
| } |
| |
| const ColumnMetadata* TableMetadataBase::get_column(const String& name) const { |
| ColumnMetadata::Map::const_iterator i = columns_by_name_.find(name); |
| if (i == columns_by_name_.end()) return NULL; |
| return i->second.get(); |
| } |
| |
| void TableMetadataBase::add_column(const VersionNumber& server_version, |
| const ColumnMetadata::Ptr& column) { |
| if (columns_by_name_.insert(std::make_pair(column->name(), column)).second) { |
| columns_.push_back(column); |
| } |
| } |
| |
| void TableMetadataBase::clear_columns() { |
| columns_.clear(); |
| columns_by_name_.clear(); |
| partition_key_.clear(); |
| clustering_key_.clear(); |
| } |
| |
| size_t get_column_count(const ColumnMetadata::Vec& columns, CassColumnType type) { |
| size_t count = 0; |
| for (ColumnMetadata::Vec::const_iterator i = columns.begin(), end = columns.end(); i != end; |
| ++i) { |
| if ((*i)->type() == type) count++; |
| } |
| return count; |
| } |
| |
| void TableMetadataBase::build_keys_and_sort(const VersionNumber& server_version, |
| SimpleDataTypeCache& cache) { |
| // Also, Reorders columns so that the order is: |
| // 1) Parition key |
| // 2) Clustering keys |
| // 3) Other columns |
| |
| if (server_version.major_version() >= 2) { |
| partition_key_.resize(get_column_count(columns_, CASS_COLUMN_TYPE_PARTITION_KEY)); |
| clustering_key_.resize(get_column_count(columns_, CASS_COLUMN_TYPE_CLUSTERING_KEY)); |
| clustering_key_order_.resize(clustering_key_.size(), CASS_CLUSTERING_ORDER_NONE); |
| for (ColumnMetadata::Vec::const_iterator i = columns_.begin(), end = columns_.end(); i != end; |
| ++i) { |
| const ColumnMetadata::Ptr& column(*i); |
| if (column->type() == CASS_COLUMN_TYPE_PARTITION_KEY && column->position() >= 0 && |
| static_cast<size_t>(column->position()) < partition_key_.size()) { |
| partition_key_[column->position()] = column; |
| } else if (column->type() == CASS_COLUMN_TYPE_CLUSTERING_KEY && column->position() >= 0 && |
| static_cast<size_t>(column->position()) < clustering_key_.size()) { |
| clustering_key_[column->position()] = column; |
| clustering_key_order_[column->position()] = |
| column->is_reversed() ? CASS_CLUSTERING_ORDER_DESC : CASS_CLUSTERING_ORDER_ASC; |
| } |
| } |
| |
| ColumnMetadata::Vec columns; |
| columns.reserve(columns_.size()); |
| |
| std::copy(partition_key_.begin(), partition_key_.end(), |
| std::back_inserter<ColumnMetadata::Vec>(columns)); |
| std::copy(clustering_key_.begin(), clustering_key_.end(), |
| std::back_inserter<ColumnMetadata::Vec>(columns)); |
| |
| for (ColumnMetadata::Vec::const_iterator i = columns_.begin(), end = columns_.end(); i != end; |
| ++i) { |
| const ColumnMetadata::Ptr& column(*i); |
| if (column->type() != CASS_COLUMN_TYPE_PARTITION_KEY && |
| column->type() != CASS_COLUMN_TYPE_CLUSTERING_KEY) { |
| columns.push_back(column); |
| } |
| } |
| |
| columns_.swap(columns); |
| } else { |
| // Cassandra 1.2 requires a lot more work because "system.schema_columns" only |
| // contains regular columns. |
| |
| // Partition key |
| { |
| StringRefVec key_aliases; |
| const Value* key_aliases_value = get_field("key_aliases"); |
| if (key_aliases_value != NULL) { |
| CollectionIterator iterator(key_aliases_value); |
| while (iterator.next()) { |
| key_aliases.push_back(iterator.value()->to_string_ref()); |
| } |
| } |
| |
| ParseResult::Ptr key_validator = |
| DataTypeClassNameParser::parse_with_composite(get_string_field("key_validator"), cache); |
| size_t size = key_validator->types().size(); |
| partition_key_.reserve(size); |
| for (size_t i = 0; i < size; ++i) { |
| String key_alias; |
| if (i < key_aliases.size()) { |
| key_alias = key_aliases[i].to_string(); |
| } else { |
| OStringStream ss("key"); |
| if (i > 0) { |
| ss << i + 1; |
| } |
| key_alias = ss.str(); |
| } |
| partition_key_.push_back(ColumnMetadata::Ptr( |
| new ColumnMetadata(key_alias, partition_key_.size(), CASS_COLUMN_TYPE_PARTITION_KEY, |
| key_validator->types()[i]))); |
| } |
| } |
| |
| // Clustering key |
| { |
| StringRefVec column_aliases; |
| const Value* column_aliases_value = get_field("column_aliases"); |
| if (column_aliases_value != NULL) { |
| CollectionIterator iterator(column_aliases_value); |
| while (iterator.next()) { |
| column_aliases.push_back(iterator.value()->to_string_ref()); |
| } |
| } |
| |
| // TODO: Figure out how to test these special cases and properly document them here |
| ParseResult::Ptr comparator = |
| DataTypeClassNameParser::parse_with_composite(get_string_field("comparator"), cache); |
| size_t size = comparator->types().size(); |
| if (comparator->is_composite()) { |
| if (!comparator->collections().empty() || |
| (column_aliases.size() == size - 1 && |
| comparator->types().back()->value_type() == CASS_VALUE_TYPE_TEXT)) { |
| size = size - 1; |
| } |
| } else { |
| size = !column_aliases.empty() || columns_.empty() ? size : 0; |
| } |
| clustering_key_.reserve(size); |
| for (size_t i = 0; i < size; ++i) { |
| String column_alias; |
| if (i < column_aliases.size()) { |
| column_alias = column_aliases[i].to_string(); |
| } else { |
| OStringStream ss("column"); |
| if (i > 0) { |
| ss << i + 1; |
| } |
| column_alias = ss.str(); |
| } |
| clustering_key_.push_back(ColumnMetadata::Ptr( |
| new ColumnMetadata(column_alias, clustering_key_.size(), |
| CASS_COLUMN_TYPE_CLUSTERING_KEY, comparator->types()[i]))); |
| clustering_key_order_.push_back(comparator->reversed()[i] ? CASS_CLUSTERING_ORDER_DESC |
| : CASS_CLUSTERING_ORDER_ASC); |
| } |
| } |
| |
| // TODO: Handle value alias column |
| |
| ColumnMetadata::Vec columns(partition_key_.size() + clustering_key_.size() + columns_.size()); |
| |
| ColumnMetadata::Vec::iterator pos = columns.begin(); |
| pos = std::copy(partition_key_.begin(), partition_key_.end(), pos); |
| pos = std::copy(clustering_key_.begin(), clustering_key_.end(), pos); |
| std::copy(columns_.begin(), columns_.end(), pos); |
| |
| columns_.swap(columns); |
| } |
| } |
| |
| const TableMetadata::Ptr TableMetadata::NIL; |
| |
| TableMetadata::TableMetadata(const VersionNumber& server_version, const String& name, |
| const RefBuffer::Ptr& buffer, const Row* row, bool is_virtual) |
| : TableMetadataBase(server_version, name, buffer, row, is_virtual) { |
| add_field(buffer, row, table_column_name(server_version)); |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| add_field(buffer, row, "flags"); |
| } |
| } |
| |
| void TableMetadata::add_column(const VersionNumber& server_version, |
| const ColumnMetadata::Ptr& column) { |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| if (column->type() == CASS_COLUMN_TYPE_REGULAR && column->data_type()->is_custom()) { |
| const CustomType* customType = static_cast<const CustomType*>(column->data_type().get()); |
| if (customType->class_name() == EMPTY_TYPE) { |
| // Don't add this column; it's a surrogate column in a dense table and |
| // should not be exposed to the user. |
| return; |
| } |
| } |
| } else if (column->type() == CASS_COLUMN_TYPE_COMPACT_VALUE && column->name().empty()) { |
| // Don't add this column; it's a surrogate column in a dense table and |
| // should not be exposed to the user. |
| return; |
| } |
| TableMetadataBase::add_column(server_version, column); |
| } |
| |
| const ViewMetadata* TableMetadata::get_view(const String& name) const { |
| ViewMetadata::Vec::const_iterator i = std::lower_bound(views_.begin(), views_.end(), name); |
| if (i == views_.end() || (*i)->name() != name) return NULL; |
| return i->get(); |
| } |
| |
| void TableMetadata::add_view(const ViewMetadata::Ptr& view) { views_.push_back(view); } |
| |
| void TableMetadata::sort_views() { std::sort(views_.begin(), views_.end()); } |
| |
| void TableMetadata::key_aliases(SimpleDataTypeCache& cache, KeyAliases* output) const { |
| const Value* aliases = get_field("key_aliases"); |
| if (aliases != NULL) { |
| output->reserve(aliases->count()); |
| CollectionIterator itr(aliases); |
| while (itr.next()) { |
| output->push_back(itr.value()->to_string()); |
| } |
| } |
| if (output->empty()) { // C* 1.2 tables created via CQL2 or thrift don't have col meta or key |
| // aliases |
| ParseResult::Ptr key_validator_type = |
| DataTypeClassNameParser::parse_with_composite(get_string_field("key_validator"), cache); |
| const size_t count = key_validator_type->types().size(); |
| OStringStream ss("key"); |
| for (size_t i = 0; i < count; ++i) { |
| if (i > 0) { |
| ss.seekp(3); // position after "key" |
| ss << i + 1; |
| } |
| output->push_back(ss.str()); |
| } |
| } |
| } |
| |
| const ViewMetadata::Ptr ViewMetadata::NIL; |
| |
| ViewMetadata::ViewMetadata(const VersionNumber& server_version, const TableMetadata* table, |
| const String& name, const RefBuffer::Ptr& buffer, const Row* row, |
| bool is_virtual) |
| : TableMetadataBase(server_version, name, buffer, row, is_virtual) |
| , base_table_(table) { |
| add_field(buffer, row, "keyspace_name"); |
| add_field(buffer, row, "view_name"); |
| add_field(buffer, row, "base_table_name"); |
| add_field(buffer, row, "base_table_id"); |
| add_field(buffer, row, "include_all_columns"); |
| add_field(buffer, row, "where_clause"); |
| } |
| |
| const IndexMetadata* TableMetadata::get_index(const String& name) const { |
| IndexMetadata::Map::const_iterator i = indexes_by_name_.find(name); |
| if (i == indexes_by_name_.end()) return NULL; |
| return i->second.get(); |
| } |
| |
| void TableMetadata::add_index(const IndexMetadata::Ptr& index) { |
| if (indexes_by_name_.insert(std::make_pair(index->name(), index)).second) { |
| indexes_.push_back(index); |
| } |
| } |
| |
| void TableMetadata::clear_indexes() { |
| indexes_.clear(); |
| indexes_by_name_.clear(); |
| } |
| |
| FunctionMetadata::FunctionMetadata(const VersionNumber& server_version, SimpleDataTypeCache& cache, |
| const String& name, const Value* signature, |
| KeyspaceMetadata* keyspace, const RefBuffer::Ptr& buffer, |
| const Row* row) |
| : MetadataBase(Metadata::full_function_name(name, signature->as_stringlist())) |
| , simple_name_(name) { |
| const Value* value1; |
| const Value* value2; |
| |
| add_field(buffer, row, "keyspace_name"); |
| add_field(buffer, row, "function_name"); |
| |
| value1 = add_field(buffer, row, "argument_names"); |
| value2 = add_field(buffer, row, "argument_types"); |
| if (value1 != NULL && value1->value_type() == CASS_VALUE_TYPE_LIST && |
| value1->primary_value_type() == CASS_VALUE_TYPE_VARCHAR && value2 != NULL && |
| value2->value_type() == CASS_VALUE_TYPE_LIST && |
| value2->primary_value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| CollectionIterator iterator1(value1); |
| CollectionIterator iterator2(value2); |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| while (iterator1.next() && iterator2.next()) { |
| StringRef arg_name(iterator1.value()->to_string_ref()); |
| DataType::ConstPtr arg_type( |
| DataTypeCqlNameParser::parse(iterator2.value()->to_string(), cache, keyspace)); |
| args_.push_back(Argument(arg_name, arg_type)); |
| } |
| } else { |
| while (iterator1.next() && iterator2.next()) { |
| StringRef arg_name(iterator1.value()->to_string_ref()); |
| DataType::ConstPtr arg_type( |
| DataTypeClassNameParser::parse_one(iterator2.value()->to_string(), cache)); |
| args_.push_back(Argument(arg_name, arg_type)); |
| } |
| } |
| } |
| |
| value1 = add_field(buffer, row, "return_type"); |
| if (value1 != NULL && value1->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| return_type_ = DataTypeCqlNameParser::parse(value1->to_string(), cache, keyspace); |
| } else { |
| return_type_ = DataTypeClassNameParser::parse_one(value1->to_string(), cache); |
| } |
| } |
| |
| value1 = add_field(buffer, row, "body"); |
| if (value1 != NULL && value1->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| body_ = value1->to_string_ref(); |
| } |
| |
| value1 = add_field(buffer, row, "language"); |
| if (value1 != NULL && value1->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| language_ = value1->to_string_ref(); |
| } |
| |
| value1 = add_field(buffer, row, "called_on_null_input"); |
| if (value1 != NULL && value1->value_type() == CASS_VALUE_TYPE_BOOLEAN) { |
| called_on_null_input_ = value1->as_bool(); |
| } |
| } |
| |
| const DataType* FunctionMetadata::get_arg_type(StringRef name) const { |
| Argument::Vec::const_iterator i = std::find(args_.begin(), args_.end(), name); |
| if (i == args_.end()) return NULL; |
| return i->type.get(); |
| } |
| |
| AggregateMetadata::AggregateMetadata(const VersionNumber& server_version, |
| SimpleDataTypeCache& cache, const String& name, |
| const Value* signature, KeyspaceMetadata* keyspace, |
| const RefBuffer::Ptr& buffer, const Row* row) |
| : MetadataBase(Metadata::full_function_name(name, signature->as_stringlist())) |
| , simple_name_(name) { |
| const Value* value; |
| const FunctionMetadata::Map& functions = keyspace->functions(); |
| |
| add_field(buffer, row, "keyspace_name"); |
| add_field(buffer, row, "aggregate_name"); |
| |
| value = add_field(buffer, row, "argument_types"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_LIST && |
| value->primary_value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| CollectionIterator iterator(value); |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| while (iterator.next()) { |
| arg_types_.push_back( |
| DataTypeCqlNameParser::parse(iterator.value()->to_string(), cache, keyspace)); |
| } |
| } else { |
| while (iterator.next()) { |
| arg_types_.push_back( |
| DataTypeClassNameParser::parse_one(iterator.value()->to_string(), cache)); |
| } |
| } |
| } |
| |
| value = add_field(buffer, row, "return_type"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| return_type_ = DataTypeCqlNameParser::parse(value->to_string(), cache, keyspace); |
| } else { |
| return_type_ = DataTypeClassNameParser::parse_one(value->to_string(), cache); |
| } |
| } |
| |
| value = add_field(buffer, row, "state_type"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| state_type_ = DataTypeCqlNameParser::parse(value->to_string(), cache, keyspace); |
| } else { |
| state_type_ = DataTypeClassNameParser::parse_one(value->to_string(), cache); |
| } |
| } |
| |
| value = add_field(buffer, row, "final_func"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| StringVec final_func_signature; |
| final_func_signature.push_back(state_type_->to_string()); |
| String full_final_func_name( |
| Metadata::full_function_name(value->to_string(), final_func_signature)); |
| FunctionMetadata::Map::const_iterator i = functions.find(full_final_func_name); |
| if (i != functions.end()) final_func_ = i->second; |
| } |
| |
| value = add_field(buffer, row, "state_func"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| StringVec state_func_signature; |
| state_func_signature.push_back(state_type_->to_string()); |
| CollectionIterator iterator(signature); |
| while (iterator.next()) { |
| state_func_signature.push_back(iterator.value()->to_string()); |
| } |
| String full_state_func_name( |
| Metadata::full_function_name(value->to_string(), state_func_signature)); |
| FunctionMetadata::Map::const_iterator i = functions.find(full_state_func_name); |
| if (i != functions.end()) state_func_ = i->second; |
| } |
| |
| value = add_field(buffer, row, "initcond"); |
| if (value != NULL) { |
| if (value->value_type() == CASS_VALUE_TYPE_BLOB) { |
| init_cond_ = Value(state_type_, value->decoder()); |
| } else if (server_version >= VersionNumber(3, 0, 0) && |
| value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| init_cond_ = Value(cache.by_value_type(CASS_VALUE_TYPE_VARCHAR), value->decoder()); |
| } |
| } |
| } |
| |
| IndexMetadata::Ptr IndexMetadata::from_row(const String& index_name, const RefBuffer::Ptr& buffer, |
| const Row* row) { |
| IndexMetadata::Ptr index(new IndexMetadata(index_name)); |
| |
| StringRef kind; |
| const Value* value = index->add_field(buffer, row, "kind"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| kind = value->to_string_ref(); |
| } |
| |
| const Value* options = index->add_field(buffer, row, "options"); |
| index->update(kind, options); |
| |
| return index; |
| } |
| |
| void IndexMetadata::update(StringRef kind, const Value* options) { |
| type_ = index_type_from_string(kind); |
| |
| if (options != NULL && options->value_type() == CASS_VALUE_TYPE_MAP) { |
| MapIterator iterator(options); |
| while (iterator.next()) { |
| if (iterator.key()->to_string_ref() == "target") { |
| target_ = iterator.value()->to_string(); |
| } |
| } |
| } |
| |
| options_ = *options; |
| } |
| |
| IndexMetadata::Ptr IndexMetadata::from_legacy(const String& index_name, |
| const ColumnMetadata* column, |
| const RefBuffer::Ptr& buffer, const Row* row) { |
| IndexMetadata::Ptr index(new IndexMetadata(index_name)); |
| |
| index->add_field(buffer, row, "index_name"); |
| |
| StringRef index_type; |
| const Value* value = index->add_field(buffer, row, "index_type"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| index_type = value->to_string_ref(); |
| } |
| |
| const Value* options = index->add_json_map_field(row, "index_options"); |
| index->update_legacy(index_type, column, options); |
| |
| return index; |
| } |
| |
| void IndexMetadata::update_legacy(StringRef index_type, const ColumnMetadata* column, |
| const Value* options) { |
| type_ = index_type_from_string(index_type); |
| target_ = target_from_legacy(column, options); |
| options_ = *options; |
| } |
| |
| String IndexMetadata::target_from_legacy(const ColumnMetadata* column, const Value* options) { |
| String column_name(column->name()); |
| |
| escape_id(column_name); |
| |
| if (options != NULL && options->value_type() == CASS_VALUE_TYPE_MAP) { |
| MapIterator iterator(options); |
| |
| while (iterator.next()) { |
| String key(iterator.key()->to_string()); |
| if (key.find("index_keys") != String::npos) { |
| return "keys(" + column_name + ")"; |
| } else if (key.find("index_keys_and_values") != String::npos) { |
| return "entries(" + column_name + ")"; |
| } else if (column->data_type()->is_collection()) { // TODO(mpenick): && is_frozen() |
| return "full(" + column_name + ")"; |
| } |
| } |
| } |
| |
| return column_name; |
| } |
| |
| CassIndexType IndexMetadata::index_type_from_string(StringRef index_type) { |
| if (index_type.iequals("keys")) { |
| return CASS_INDEX_TYPE_KEYS; |
| } else if (index_type.iequals("custom")) { |
| return CASS_INDEX_TYPE_CUSTOM; |
| } else if (index_type.iequals("composites")) { |
| return CASS_INDEX_TYPE_COMPOSITES; |
| } |
| return CASS_INDEX_TYPE_UNKNOWN; |
| } |
| |
| ColumnMetadata::ColumnMetadata(const VersionNumber& server_version, SimpleDataTypeCache& cache, |
| const String& name, KeyspaceMetadata* keyspace, |
| const RefBuffer::Ptr& buffer, const Row* row) |
| : MetadataBase(name) |
| , type_(CASS_COLUMN_TYPE_REGULAR) |
| , position_(0) |
| , is_reversed_(false) { |
| const Value* value; |
| |
| add_field(buffer, row, "keyspace_name"); |
| add_field(buffer, row, table_column_name(server_version)); |
| add_field(buffer, row, "column_name"); |
| |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| value = add_field(buffer, row, "clustering_order"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR && |
| value->to_string_ref().iequals("desc")) { |
| is_reversed_ = true; |
| } |
| |
| add_field(buffer, row, "column_name_bytes"); |
| |
| value = add_field(buffer, row, "kind"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| StringRef type = value->to_string_ref(); |
| if (type == "partition_key") { |
| type_ = CASS_COLUMN_TYPE_PARTITION_KEY; |
| } else if (type == "clustering") { |
| type_ = CASS_COLUMN_TYPE_CLUSTERING_KEY; |
| } else if (type == "static") { |
| type_ = CASS_COLUMN_TYPE_STATIC; |
| } else { |
| type_ = CASS_COLUMN_TYPE_REGULAR; |
| } |
| } |
| |
| value = add_field(buffer, row, "position"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_INT) { |
| position_ = value->as_int32(); |
| if (position_ < 0) position_ = 0; |
| } |
| |
| value = add_field(buffer, row, "type"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| String type(value->to_string()); |
| data_type_ = DataTypeCqlNameParser::parse(type, cache, keyspace); |
| } |
| } else { |
| value = add_field(buffer, row, "type"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| StringRef type = value->to_string_ref(); |
| if (type == "partition_key") { |
| type_ = CASS_COLUMN_TYPE_PARTITION_KEY; |
| } else if (type == "clustering_key") { |
| type_ = CASS_COLUMN_TYPE_CLUSTERING_KEY; |
| } else if (type == "static") { |
| type_ = CASS_COLUMN_TYPE_STATIC; |
| } else if (type == "compact_value") { |
| type_ = CASS_COLUMN_TYPE_COMPACT_VALUE; |
| } else { |
| type_ = CASS_COLUMN_TYPE_REGULAR; |
| } |
| } |
| |
| value = add_field(buffer, row, "component_index"); |
| // For C* 2.0 to 2.2 this is "null" for single component partition keys |
| // so the default position of 0 works. C* 1.2 and below don't use this. |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_INT) { |
| position_ = value->as_int32(); |
| } |
| |
| value = add_field(buffer, row, "validator"); |
| if (value != NULL && value->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| String validator(value->to_string()); |
| data_type_ = DataTypeClassNameParser::parse_one(validator, cache); |
| is_reversed_ = DataTypeClassNameParser::is_reversed(validator); |
| } |
| |
| add_field(buffer, row, "index_type"); |
| add_field(buffer, row, "index_name"); |
| add_json_map_field(row, "index_options"); |
| } |
| } |
| |
| void Metadata::InternalData::update_keyspaces(const VersionNumber& server_version, |
| const ResultResponse* result, bool is_virtual) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| ResultIterator rows(result); |
| |
| while (rows.next()) { |
| String keyspace_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &keyspace_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name'"); |
| continue; |
| } |
| |
| KeyspaceMetadata* keyspace = get_or_create_keyspace(keyspace_name, is_virtual); |
| keyspace->update(server_version, buffer, row); |
| } |
| } |
| |
| void Metadata::InternalData::update_tables(const VersionNumber& server_version, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| String table_name; |
| KeyspaceMetadata* keyspace = NULL; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name(table_column_name(server_version), &table_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name' or '%s'", |
| table_column_name(server_version)); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| } |
| |
| keyspace->add_table(TableMetadata::Ptr( |
| new TableMetadata(server_version, table_name, buffer, row, keyspace->is_virtual()))); |
| } |
| } |
| |
| void Metadata::InternalData::update_views(const VersionNumber& server_version, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| String view_name; |
| KeyspaceMetadata* keyspace = NULL; |
| |
| TableMetadata::Vec updated_tables; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String base_table_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name("view_name", &view_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name' and 'view_name'"); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| } |
| |
| if (!row->get_string_by_name("base_table_name", &base_table_name)) { |
| LOG_ERROR("Unable to get column value for 'base_table_name'"); |
| continue; |
| } |
| |
| // Properly remove the previous view if it exists. This needs to be done |
| // before the next step of finding the table because it could create a |
| // new copy of the old table. |
| keyspace->drop_table_or_view(view_name); |
| |
| TableMetadata::Ptr table(keyspace->get_table(base_table_name)); |
| if (!table) { |
| LOG_ERROR("No table metadata for view with base table name '%s'", base_table_name.c_str()); |
| continue; |
| } |
| |
| ViewMetadata::Ptr view(new ViewMetadata(server_version, table.get(), view_name, buffer, row, |
| keyspace->is_virtual())); |
| keyspace->add_view(view); |
| table->add_view(view); |
| updated_tables.push_back(table); |
| } |
| |
| for (TableMetadata::Vec::iterator i = updated_tables.begin(), end = updated_tables.end(); |
| i != end; ++i) { |
| (*i)->sort_views(); |
| } |
| } |
| |
| void Metadata::InternalData::update_user_types(const VersionNumber& server_version, |
| SimpleDataTypeCache& cache, |
| const ResultResponse* result) { |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| KeyspaceMetadata* keyspace = NULL; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String type_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name("type_name", &type_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name' or 'type_name'"); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| } |
| |
| const Value* names_value = row->get_by_name("field_names"); |
| if (names_value == NULL || names_value->is_null()) { |
| LOG_ERROR("'field_name's column for keyspace \"%s\" and type \"%s\" is null", |
| keyspace_name.c_str(), type_name.c_str()); |
| continue; |
| } |
| |
| const Value* types_value = row->get_by_name("field_types"); |
| if (types_value == NULL || types_value->is_null()) { |
| LOG_ERROR("'field_type's column for keyspace '%s' and type '%s' is null", |
| keyspace_name.c_str(), type_name.c_str()); |
| continue; |
| } |
| |
| CollectionIterator names(names_value); |
| CollectionIterator types(types_value); |
| |
| UserType::FieldVec fields; |
| |
| while (names.next()) { |
| if (!types.next()) { |
| LOG_ERROR("The number of 'field_type's doesn\"t match the number of field_names for " |
| "keyspace \"%s\" and type \"%s\"", |
| keyspace_name.c_str(), type_name.c_str()); |
| break; |
| } |
| |
| const Value* name = names.value(); |
| const Value* type = types.value(); |
| |
| if (name->is_null() || type->is_null()) { |
| LOG_ERROR("'field_name' or 'field_type' is null for keyspace \"%s\" and type \"%s\"", |
| keyspace_name.c_str(), type_name.c_str()); |
| break; |
| } |
| |
| String field_name(name->to_string()); |
| |
| DataType::ConstPtr data_type; |
| |
| if (server_version >= VersionNumber(3, 0, 0)) { |
| data_type = DataTypeCqlNameParser::parse(type->to_string(), cache, keyspace); |
| } else { |
| data_type = DataTypeClassNameParser::parse_one(type->to_string(), cache); |
| } |
| |
| if (!data_type) { |
| LOG_ERROR("Invalid 'field_type' for field \"%s\", keyspace \"%s\" and type \"%s\"", |
| field_name.c_str(), keyspace_name.c_str(), type_name.c_str()); |
| break; |
| } |
| |
| fields.push_back(UserType::Field(field_name, data_type)); |
| } |
| |
| keyspace->get_or_create_user_type(type_name, false)->set_fields(fields); |
| } |
| } |
| |
| void Metadata::InternalData::update_functions(const VersionNumber& server_version, |
| SimpleDataTypeCache& cache, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| KeyspaceMetadata* keyspace = NULL; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String function_name; |
| const Row* row = rows.row(); |
| |
| const Value* signature = row->get_by_name(signature_column_name(server_version)); |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name("function_name", &function_name) || signature == NULL) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name', 'function_name' or 'signature'"); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| } |
| |
| keyspace->add_function(FunctionMetadata::Ptr(new FunctionMetadata( |
| server_version, cache, function_name, signature, keyspace, buffer, row))); |
| } |
| } |
| |
| void Metadata::InternalData::update_aggregates(const VersionNumber& server_version, |
| SimpleDataTypeCache& cache, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| KeyspaceMetadata* keyspace = NULL; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String aggregate_name; |
| const Row* row = rows.row(); |
| |
| const Value* signature = row->get_by_name(signature_column_name(server_version)); |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name("aggregate_name", &aggregate_name) || signature == NULL) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name', 'aggregate_name' or 'signature'"); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| } |
| |
| keyspace->add_aggregate(AggregateMetadata::Ptr(new AggregateMetadata( |
| server_version, cache, aggregate_name, signature, keyspace, buffer, row))); |
| } |
| } |
| |
| void Metadata::InternalData::drop_keyspace(const String& keyspace_name) { |
| keyspaces_->erase(keyspace_name); |
| } |
| |
| void Metadata::InternalData::drop_table_or_view(const String& keyspace_name, |
| const String& table_or_view_name) { |
| KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); |
| if (i == keyspaces_->end()) return; |
| i->second.drop_table_or_view(table_or_view_name); |
| } |
| |
| void Metadata::InternalData::drop_user_type(const String& keyspace_name, const String& type_name) { |
| KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); |
| if (i == keyspaces_->end()) return; |
| i->second.drop_user_type(type_name); |
| } |
| |
| void Metadata::InternalData::drop_function(const String& keyspace_name, |
| const String& full_function_name) { |
| KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); |
| if (i == keyspaces_->end()) return; |
| i->second.drop_function(full_function_name); |
| } |
| |
| void Metadata::InternalData::drop_aggregate(const String& keyspace_name, |
| const String& full_aggregate_name) { |
| KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); |
| if (i == keyspaces_->end()) return; |
| i->second.drop_aggregate(full_aggregate_name); |
| } |
| |
| void Metadata::InternalData::update_columns(const VersionNumber& server_version, |
| SimpleDataTypeCache& cache, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| String table_or_view_name; |
| String column_name; |
| |
| KeyspaceMetadata* keyspace = NULL; |
| TableMetadataBase::Ptr table_or_view; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String temp_table_or_view_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name(table_column_name(server_version), &temp_table_or_view_name) || |
| !row->get_string_by_name("column_name", &column_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name', '%s' or 'column_name'", |
| table_column_name(server_version)); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| table_or_view_name.clear(); |
| } |
| |
| if (table_or_view_name != temp_table_or_view_name) { |
| // Build keys for the previous table |
| if (table_or_view) { |
| table_or_view->build_keys_and_sort(server_version, cache); |
| } |
| table_or_view_name = temp_table_or_view_name; |
| table_or_view = TableMetadataBase::Ptr(keyspace->get_table(table_or_view_name)); |
| if (!table_or_view) { |
| table_or_view = TableMetadataBase::Ptr(keyspace->get_view(table_or_view_name)); |
| if (!table_or_view) continue; |
| } |
| table_or_view->clear_columns(); |
| } |
| |
| if (table_or_view) { |
| table_or_view->add_column( |
| server_version, ColumnMetadata::Ptr(new ColumnMetadata(server_version, cache, column_name, |
| keyspace, buffer, row))); |
| } |
| } |
| |
| // Build keys for the last table |
| if (table_or_view) { |
| table_or_view->build_keys_and_sort(server_version, cache); |
| } |
| } |
| |
| void Metadata::InternalData::update_legacy_indexes(const VersionNumber& server_version, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| String table_name; |
| String column_name; |
| |
| KeyspaceMetadata* keyspace = NULL; |
| TableMetadata::Ptr table; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String temp_table_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name(table_column_name(server_version), &temp_table_name) || |
| !row->get_string_by_name("column_name", &column_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name', '%s' or 'column_name'", |
| table_column_name(server_version)); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| table_name.clear(); |
| } |
| |
| if (table_name != temp_table_name) { |
| table_name = temp_table_name; |
| table = keyspace->get_table(table_name); |
| if (!table) continue; |
| table->clear_indexes(); |
| } |
| |
| if (table) { |
| const ColumnMetadata* column = table->get_column(column_name); |
| if (column != NULL) { |
| const Value* index_type = column->get_field("index_type"); |
| if (index_type != NULL && index_type->value_type() == CASS_VALUE_TYPE_VARCHAR) { |
| String index_name = column->get_string_field("index_name"); |
| table->add_index(IndexMetadata::from_legacy(index_name, column, buffer, row)); |
| } |
| } |
| } |
| } |
| } |
| |
| void Metadata::InternalData::update_indexes(const VersionNumber& server_version, |
| const ResultResponse* result) { |
| RefBuffer::Ptr buffer = result->buffer(); |
| |
| ResultIterator rows(result); |
| |
| String keyspace_name; |
| String table_name; |
| String index_name; |
| |
| KeyspaceMetadata* keyspace = NULL; |
| TableMetadata::Ptr table; |
| |
| while (rows.next()) { |
| String temp_keyspace_name; |
| String temp_table_name; |
| const Row* row = rows.row(); |
| |
| if (!row->get_string_by_name("keyspace_name", &temp_keyspace_name) || |
| !row->get_string_by_name("table_name", &temp_table_name) || |
| !row->get_string_by_name("index_name", &index_name)) { |
| LOG_ERROR("Unable to get column value for 'keyspace_name', 'table_name' or 'index_name'"); |
| continue; |
| } |
| |
| if (keyspace_name != temp_keyspace_name) { |
| keyspace_name = temp_keyspace_name; |
| keyspace = get_or_create_keyspace(keyspace_name); |
| table_name.clear(); |
| } |
| |
| if (table_name != temp_table_name) { |
| table_name = temp_table_name; |
| table = keyspace->get_table(table_name); |
| if (!table) continue; |
| table->clear_indexes(); |
| } |
| |
| table->add_index(IndexMetadata::from_row(index_name, buffer, row)); |
| } |
| } |
| |
| KeyspaceMetadata* Metadata::InternalData::get_or_create_keyspace(const String& name, |
| bool is_virtual) { |
| KeyspaceMetadata::Map::iterator i = keyspaces_->find(name); |
| if (i == keyspaces_->end()) { |
| i = keyspaces_->insert(std::make_pair(name, KeyspaceMetadata(name, is_virtual))).first; |
| } |
| return &i->second; |
| } |