From b91f3bcc78369785e032c12dbccc29cb574d8dcf Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Tue, 23 Feb 2016 16:09:29 -0700 Subject: [PATCH 1/5] Added support for materialized view metadata --- include/cassandra.h | 368 ++++++++++++++- src/control_connection.cpp | 77 ++-- src/control_connection.hpp | 8 +- src/data_type_parser.cpp | 4 +- src/external_types.hpp | 1 + src/metadata.cpp | 418 ++++++++++++++---- src/metadata.hpp | 154 +++++-- .../src/test_schema_metadata.cpp | 207 ++++++++- 8 files changed, 1076 insertions(+), 161 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index 8d1153e8c..937b66306 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -346,6 +346,13 @@ typedef struct CassKeyspaceMeta_ CassKeyspaceMeta; */ typedef struct CassTableMeta_ CassTableMeta; +/** + * @struct CassMaterializedViewMeta + * + * MaterializedView metadata + */ +typedef struct CassMaterializedViewMeta_ CassMaterializedViewMeta; + /** * @struct CassColumnMeta * @@ -526,7 +533,8 @@ typedef enum CassIteratorType_ { CASS_ITERATOR_TYPE_TYPE_META, CASS_ITERATOR_TYPE_FUNCTION_META, CASS_ITERATOR_TYPE_AGGREGATE_META, - CASS_ITERATOR_TYPE_COLUMN_META + CASS_ITERATOR_TYPE_COLUMN_META, + CASS_ITERATOR_TYPE_MATERIALIZED_VIEW_META } CassIteratorType; #define CASS_LOG_LEVEL_MAP(XX) \ @@ -1674,6 +1682,38 @@ cass_keyspace_meta_table_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* table, size_t table_length); +/** + * Gets the materialized view metadata for the provided view name. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] view + * + * @return The metadata for a view. NULL if view does not exist. + */ +CASS_EXPORT const CassMaterializedViewMeta* +cass_keyspace_meta_materialized_view_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* view); + +/** + * Same as cass_keyspace_meta_materialized_view_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @param[in] view + * @param[in] view_length + * @return same as cass_keyspace_meta_materialized_view_by_name() + * + * @see cass_keyspace_meta_materialized_view_by_name() + */ +CASS_EXPORT const CassMaterializedViewMeta* +cass_keyspace_meta_materialized_view_by_name_n(const CassKeyspaceMeta* keyspace_meta, + const char* view, + size_t view_length); + /** * Gets the data type for the provided type name. * @@ -1830,6 +1870,20 @@ cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keyspace_meta, const char* name, size_t name_length); +/** + * Gets the name of the table. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_table_meta_name(const CassTableMeta* table_meta, + const char** name, + size_t* name_length); + /** * Gets the column metadata for the provided column name. * @@ -1862,20 +1916,6 @@ cass_table_meta_column_by_name_n(const CassTableMeta* table_meta, const char* column, size_t column_length); -/** - * Gets the name of the table. - * - * @public @memberof CassTableMeta - * - * @param[in] table_meta - * @param[out] name - * @param[out] name_length - */ -CASS_EXPORT void -cass_table_meta_name(const CassTableMeta* table_meta, - const char** name, - size_t* name_length); - /** * Gets the total number of columns for the table. * @@ -1900,6 +1940,62 @@ CASS_EXPORT const CassColumnMeta* cass_table_meta_column(const CassTableMeta* table_meta, size_t index); +/** + * Gets the materialized view metadata for the provided view name. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] view + * + * @return The metadata for a view. NULL if view does not exist. + */ +CASS_EXPORT const CassMaterializedViewMeta* +cass_table_meta_materialized_view_by_name(const CassTableMeta* table_meta, + const char* view); + +/** + * Same as cass_table_meta_materialized_view_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] view + * @param[in] view_length + * @return same as cass_table_meta_materialized_view_by_name() + * + * @see cass_table_meta_materialized_view_by_name() + */ +CASS_EXPORT const CassMaterializedViewMeta* +cass_table_meta_materialized_view_by_name_n(const CassTableMeta* table_meta, + const char* view, + size_t view_length); + +/** + * Gets the total number of views for the table. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @return The total view count. + */ +CASS_EXPORT size_t +cass_table_meta_materialized_view_count(const CassTableMeta* table_meta); + +/** + * Gets the materialized view metadata for the provided index. + * + * @public @memberof CassTableMeta + * + * @param[in] table_meta + * @param[in] index + * @return The metadata for a view. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassMaterializedViewMeta* +cass_table_meta_materialized_view(const CassTableMeta* table_meta, + size_t index); + /** * Gets the number of columns for the table's partition key. * @@ -1981,6 +2077,171 @@ cass_table_meta_field_by_name_n(const CassTableMeta* table_meta, const char* name, size_t name_length); +/** + * Gets the column metadata for the provided column name. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] column + * + * @return The metadata for a column. NULL if column does not exist. + */ +CASS_EXPORT const CassColumnMeta* +cass_materialized_view_meta_column_by_name(const CassMaterializedViewMeta* view_meta, + const char* column); + +/** + * Same as cass_materialized_view_meta_column_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] column + * @param[in] column_length + * @return same as cass_materialized_view_meta_column_by_name() + * + * @see cass_materialized_view_meta_column_by_name() + */ +CASS_EXPORT const CassColumnMeta* +cass_materialized_view_meta_column_by_name_n(const CassMaterializedViewMeta* view_meta, + const char* column, + size_t column_length); + +/** + * Gets the name of the view. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_materialized_view_meta_name(const CassMaterializedViewMeta* view_meta, + const char** name, + size_t* name_length); + +/** + * Gets the base table name of the view. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[out] name + * @param[out] name_length + */ +CASS_EXPORT void +cass_materialized_view_meta_base_table_name(const CassMaterializedViewMeta* view_meta, + const char** name, + size_t* name_length); + +/** + * Gets the total number of columns for the view. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @return The total column count. + */ +CASS_EXPORT size_t +cass_materialized_view_meta_column_count(const CassMaterializedViewMeta* view_meta); + +/** + * Gets the column metadata for the provided index. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] index + * @return The metadata for a column. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassColumnMeta* +cass_materialized_view_meta_column(const CassMaterializedViewMeta* view_meta, + size_t index); + +/** + * Gets the number of columns for the view's partition key. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @return The count for the number of columns in the partition key. + */ +CASS_EXPORT size_t +cass_materialized_view_meta_partition_key_count(const CassMaterializedViewMeta* view_meta); + +/** + * Gets the partition key column metadata for the provided index. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] index + * @return The metadata for a column. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassColumnMeta* +cass_materialized_view_meta_partition_key(const CassMaterializedViewMeta* view_meta, + size_t index); + +/** + * Gets the number of columns for the view's clustering key. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @return The count for the number of columns in the clustering key. + */ +CASS_EXPORT size_t +cass_materialized_view_meta_clustering_key_count(const CassMaterializedViewMeta* view_meta); + +/** + * Gets the clustering key column metadata for the provided index. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] index + * @return The metadata for a column. NULL returned if the index is out of range. + */ +CASS_EXPORT const CassColumnMeta* +cass_materialized_view_meta_clustering_key(const CassMaterializedViewMeta* view_meta, + size_t index); + +/** + * Gets a metadata field for the provided name. Metadata fields allow direct + * access to the column data found in the underlying "views" metadata view. + + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] name + * @return A metadata field value. NULL if the field does not exist. + */ +CASS_EXPORT const CassValue* +cass_materialized_view_meta_field_by_name(const CassMaterializedViewMeta* view_meta, + const char* name); + +/** + * Same as cass_materialized_view_meta_field_by_name(), but with lengths for string + * parameters. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @param[in] name + * @param[in] name_length + * @return same as cass_materialized_view_meta_field_by_name() + * + * @see cass_materialized_view_meta_field_by_name() + */ +CASS_EXPORT const CassValue* +cass_materialized_view_meta_field_by_name_n(const CassMaterializedViewMeta* view_meta, + const char* name, + size_t name_length); + /** * Gets the name of the column. * @@ -6533,6 +6794,21 @@ cass_iterator_keyspaces_from_schema_meta(const CassSchemaMeta* schema_meta); CASS_EXPORT CassIterator* cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); +/** + * Creates a new iterator for the specified keyspace metadata. + * This can be used to iterate over views. + * + * @public @memberof CassKeyspaceMeta + * + * @param[in] keyspace_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_materialized_view_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_materialized_views_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); + /** * Creates a new iterator for the specified keyspace metadata. * This can be used to iterate over types. @@ -6611,6 +6887,21 @@ cass_iterator_fields_from_keyspace_meta(const CassKeyspaceMeta* keyspace_meta); CASS_EXPORT CassIterator* cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta); +/** + * Creates a new iterator for the specified materialized view metadata. + * This can be used to iterate over columns. + * + * @public @memberof CassTableMeta + * + * @param[in] view_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_materialized_view_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_materialized_views_from_table_meta(const CassTableMeta* table_meta); + /** * Creates a new fields iterator for the specified table metadata. Metadata * fields allow direct access to the column data found in the underlying @@ -6629,6 +6920,39 @@ cass_iterator_columns_from_table_meta(const CassTableMeta* table_meta); CASS_EXPORT CassIterator* cass_iterator_fields_from_table_meta(const CassTableMeta* table_meta); +/** + * Creates a new iterator for the specified materialized view metadata. + * This can be used to iterate over columns. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_column_meta() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_columns_from_materialized_view_meta(const CassMaterializedViewMeta* view_meta); + +/** + * Creates a new fields iterator for the specified materialized view metadata. + * Metadata fields allow direct access to the column data found in the + * underlying "views" metadata view. This can be used to iterate those metadata + * field entries. + * + * @public @memberof CassMaterializedViewMeta + * + * @param[in] view_meta + * @return A new iterator that must be freed. + * + * @see cass_iterator_get_meta_field_name() + * @see cass_iterator_get_meta_field_value() + * @see cass_iterator_free() + */ +CASS_EXPORT CassIterator* +cass_iterator_fields_from_materialized_view_meta(const CassMaterializedViewMeta* view_meta); + /** * Creates a new fields iterator for the specified column metadata. Metadata * fields allow direct access to the column data found in the underlying @@ -6823,6 +7147,20 @@ cass_iterator_get_keyspace_meta(const CassIterator* iterator); CASS_EXPORT const CassTableMeta* cass_iterator_get_table_meta(const CassIterator* iterator); +/** + * Gets the materialized view metadata entry at the iterator's current position. + * + * Calling cass_iterator_next() will invalidate the previous + * value returned by this method. + * + * @public @memberof CassIterator + * + * @param[in] iterator + * @return A materialized view metadata entry + */ +CASS_EXPORT const CassMaterializedViewMeta* +cass_iterator_get_materialized_view_meta(const CassIterator* iterator); + /** * Gets the type metadata entry at the iterator's current position. * diff --git a/src/control_connection.cpp b/src/control_connection.cpp index 32f262be5..36580b68a 100644 --- a/src/control_connection.cpp +++ b/src/control_connection.cpp @@ -47,6 +47,7 @@ #define SELECT_KEYSPACES_30 "SELECT * FROM system_schema.keyspaces" #define SELECT_TABLES_30 "SELECT * FROM system_schema.tables" +#define SELECT_VIEWS_30 "SELECT * FROM system_schema.views" #define SELECT_COLUMNS_30 "SELECT * FROM system_schema.columns" #define SELECT_USERTYPES_30 "SELECT * FROM system_schema.types" #define SELECT_FUNCTIONS_30 "SELECT * FROM system_schema.functions" @@ -316,7 +317,7 @@ void ControlConnection::on_event(EventResponse* response) { refresh_keyspace(response->keyspace()); break; case EventResponse::TABLE: - refresh_table(response->keyspace(), response->target()); + refresh_table_or_view(response->keyspace(), response->target()); break; case EventResponse::TYPE: refresh_type(response->keyspace(), response->target()); @@ -337,8 +338,8 @@ void ControlConnection::on_event(EventResponse* response) { session_->metadata().drop_keyspace(response->keyspace().to_string()); break; case EventResponse::TABLE: - session_->metadata().drop_table(response->keyspace().to_string(), - response->target().to_string()); + session_->metadata().drop_table_or_view(response->keyspace().to_string(), + response->target().to_string()); break; case EventResponse::TYPE: session_->metadata().drop_user_type(response->keyspace().to_string(), @@ -469,6 +470,7 @@ void ControlConnection::query_meta_schema() { if (session_->metadata().cassandra_version() >= VersionNumber(3, 0, 0)) { handler->execute_query("keyspaces", SELECT_KEYSPACES_30); handler->execute_query("tables", SELECT_TABLES_30); + handler->execute_query("views", SELECT_VIEWS_30); handler->execute_query("columns", SELECT_COLUMNS_30); handler->execute_query("user_types", SELECT_USERTYPES_30); handler->execute_query("functions", SELECT_FUNCTIONS_30); @@ -508,9 +510,17 @@ void ControlConnection::on_query_meta_schema(ControlConnection* control_connecti ResultResponse* tables_result; if (MultipleRequestHandler::get_result_response(responses, "tables", &tables_result)) { - ResultResponse* columns_result = NULL; - MultipleRequestHandler::get_result_response(responses, "columns", &columns_result); - session->metadata().update_tables(tables_result, columns_result); + session->metadata().update_tables(tables_result); + } + + ResultResponse* views_result; + if (MultipleRequestHandler::get_result_response(responses, "views", &views_result)) { + session->metadata().update_views(views_result); + } + + ResultResponse* columns_result = NULL; + if (MultipleRequestHandler::get_result_response(responses, "columns", &columns_result)) { + session->metadata().update_columns(columns_result); } ResultResponse* user_types_result; @@ -745,57 +755,72 @@ void ControlConnection::on_refresh_keyspace(ControlConnection* control_connectio control_connection->session_->metadata().update_keyspaces(result); } -void ControlConnection::refresh_table(const StringRef& keyspace_name, - const StringRef& table_name) { +void ControlConnection::refresh_table_or_view(const StringRef& keyspace_name, + const StringRef& table_or_view_name) { std::string table_query; + std::string view_query; std::string column_query; if (session_->metadata().cassandra_version() >= VersionNumber(3, 0, 0)) { table_query.assign(SELECT_TABLES_30); table_query.append(" WHERE keyspace_name='").append(keyspace_name.data(), keyspace_name.size()) - .append("' AND table_name='").append(table_name.data(), table_name.size()).append("'"); + .append("' AND table_name='").append(table_or_view_name.data(), table_or_view_name.size()).append("'"); + + view_query.assign(SELECT_VIEWS_30); + view_query.append(" WHERE keyspace_name='").append(keyspace_name.data(), keyspace_name.size()) + .append("' AND view_name='").append(table_or_view_name.data(), table_or_view_name.size()).append("'"); column_query.assign(SELECT_COLUMNS_30); column_query.append(" WHERE keyspace_name='").append(keyspace_name.data(), keyspace_name.size()) - .append("' AND table_name='").append(table_name.data(), table_name.size()).append("'"); + .append("' AND table_name='").append(table_or_view_name.data(), table_or_view_name.size()).append("'"); - LOG_DEBUG("Refreshing table %s; %s", table_query.c_str(), column_query.c_str()); + LOG_DEBUG("Refreshing table/view %s; %s; %s", table_query.c_str(), view_query.c_str(), column_query.c_str()); } else { table_query.assign(SELECT_COLUMN_FAMILIES_20); table_query.append(" WHERE keyspace_name='").append(keyspace_name.data(), keyspace_name.size()) - .append("' AND columnfamily_name='").append(table_name.data(), table_name.size()).append("'"); + .append("' AND columnfamily_name='").append(table_or_view_name.data(), table_or_view_name.size()).append("'"); column_query.assign(SELECT_COLUMNS_20); column_query.append(" WHERE keyspace_name='").append(keyspace_name.data(), keyspace_name.size()) - .append("' AND columnfamily_name='").append(table_name.data(), table_name.size()).append("'"); + .append("' AND columnfamily_name='").append(table_or_view_name.data(), table_or_view_name.size()).append("'"); LOG_DEBUG("Refreshing table %s; %s", table_query.c_str(), column_query.c_str()); } ScopedRefPtr > handler( new ControlMultipleRequestHandler(this, - ControlConnection::on_refresh_table, - RefreshTableData(keyspace_name.to_string(), table_name.to_string()))); + ControlConnection::on_refresh_table_or_view, + RefreshTableData(keyspace_name.to_string(), table_or_view_name.to_string()))); handler->execute_query("tables", table_query); + if (!view_query.empty()) { + handler->execute_query("views", view_query); + } handler->execute_query("columns", column_query); } -void ControlConnection::on_refresh_table(ControlConnection* control_connection, - const RefreshTableData& data, - const MultipleRequestHandler::ResponseMap& responses) { +void ControlConnection::on_refresh_table_or_view(ControlConnection* control_connection, + const RefreshTableData& data, + const MultipleRequestHandler::ResponseMap& responses) { ResultResponse* tables_result; + Session* session = control_connection->session_; if (!MultipleRequestHandler::get_result_response(responses, "tables", &tables_result) || tables_result->row_count() == 0) { - LOG_ERROR("No row found for column family %s.%s in system schema table.", - data.keyspace_name.c_str(), data.table_name.c_str()); - return; + ResultResponse* views_result; + if (!MultipleRequestHandler::get_result_response(responses, "views", &views_result) || + views_result->row_count() == 0) { + LOG_ERROR("No row found for table (or view) %s.%s in system schema tables.", + data.keyspace_name.c_str(), data.table_or_view_name.c_str()); + return; + } + session->metadata().update_views(views_result); + } else { + session->metadata().update_tables(tables_result); } - ResultResponse* columns_result = NULL; - MultipleRequestHandler::get_result_response(responses, "columns", &columns_result); - - Session* session = control_connection->session_; - session->metadata().update_tables(tables_result, columns_result); + ResultResponse* columns_result; + if (MultipleRequestHandler::get_result_response(responses, "columns", &columns_result)) { + session->metadata().update_columns(columns_result); + } } diff --git a/src/control_connection.hpp b/src/control_connection.hpp index deb4c3731..65385aa06 100644 --- a/src/control_connection.hpp +++ b/src/control_connection.hpp @@ -101,9 +101,9 @@ class ControlConnection : public Connection::Listener { RefreshTableData(const std::string& keyspace_name, const std::string& table_name) : keyspace_name(keyspace_name) - , table_name(table_name) {} + , table_or_view_name(table_name) {} std::string keyspace_name; - std::string table_name; + std::string table_or_view_name; }; struct UnusedData {}; @@ -211,9 +211,9 @@ class ControlConnection : public Connection::Listener { void refresh_keyspace(const StringRef& keyspace_name); static void on_refresh_keyspace(ControlConnection* control_connection, const std::string& keyspace_name, Response* response); - void refresh_table(const StringRef& keyspace_name, + void refresh_table_or_view(const StringRef& keyspace_name, const StringRef& table_name); - static void on_refresh_table(ControlConnection* control_connection, + static void on_refresh_table_or_view(ControlConnection* control_connection, const RefreshTableData& data, const MultipleRequestHandler::ResponseMap& responses); diff --git a/src/data_type_parser.cpp b/src/data_type_parser.cpp index f233a10d6..921ddd6a9 100644 --- a/src/data_type_parser.cpp +++ b/src/data_type_parser.cpp @@ -65,8 +65,8 @@ bool from_hex(const std::string& hex, std::string* result) { } DataType::ConstPtr DataTypeCqlNameParser::parse(const std::string& type, - const NativeDataTypes& native_types, - KeyspaceMetadata* keyspace) { + const NativeDataTypes& native_types, + KeyspaceMetadata* keyspace) { Parser parser(type, 0); std::string type_name; Parser::TypeParamsVec params; diff --git a/src/external_types.hpp b/src/external_types.hpp index 3e6002be5..0564f8ed6 100644 --- a/src/external_types.hpp +++ b/src/external_types.hpp @@ -74,6 +74,7 @@ EXTERNAL_TYPE(cass::SslContext, CassSsl); EXTERNAL_TYPE(cass::Metadata::SchemaSnapshot, CassSchemaMeta); EXTERNAL_TYPE(cass::KeyspaceMetadata, CassKeyspaceMeta); EXTERNAL_TYPE(cass::TableMetadata, CassTableMeta); +EXTERNAL_TYPE(cass::ViewMetadata, CassMaterializedViewMeta); EXTERNAL_TYPE(cass::ColumnMetadata, CassColumnMeta); EXTERNAL_TYPE(cass::FunctionMetadata, CassFunctionMeta); EXTERNAL_TYPE(cass::AggregateMetadata, CassAggregateMeta); diff --git a/src/metadata.cpp b/src/metadata.cpp index 9af2bb829..2c6862877 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -71,23 +71,35 @@ const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name(const CassSchemaMeta* } const CassKeyspaceMeta* cass_schema_meta_keyspace_by_name_n(const CassSchemaMeta* schema_meta, - const char* keyspace, - size_t keyspace_length) { + const char* keyspace, + size_t keyspace_length) { return CassKeyspaceMeta::to(schema_meta->get_keyspace(std::string(keyspace, keyspace_length))); } const CassTableMeta* cass_keyspace_meta_table_by_name(const CassKeyspaceMeta* keyspace_meta, - const char* table) { + const char* table) { return CassTableMeta::to(keyspace_meta->get_table(table)); } const CassTableMeta* cass_keyspace_meta_table_by_name_n(const CassKeyspaceMeta* keyspace_meta, - const char* table, - size_t table_length) { + const char* table, + size_t table_length) { return CassTableMeta::to(keyspace_meta->get_table(std::string(table, table_length))); } +const CassMaterializedViewMeta* cass_keyspace_meta_materialized_view_by_name(const CassKeyspaceMeta* keyspace_meta, + const char* view) { + return CassMaterializedViewMeta::to(keyspace_meta->get_view(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(std::string(view, view_length))); +} + const CassDataType* cass_keyspace_meta_user_type_by_name(const CassKeyspaceMeta* keyspace_meta, const char* type) { return CassDataType::to(keyspace_meta->get_user_type(type)); @@ -153,6 +165,11 @@ const CassValue* cass_keyspace_meta_field_by_name_n(const CassKeyspaceMeta* keys return CassValue::to(keyspace_meta->get_field(std::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(); +} const CassColumnMeta* cass_table_meta_column_by_name(const CassTableMeta* table_meta, const char* column) { @@ -165,22 +182,6 @@ const CassColumnMeta* cass_table_meta_column_by_name_n(const CassTableMeta* tabl return CassColumnMeta::to(table_meta->get_column(std::string(column, column_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(); -} - -const CassValue* cass_table_meta_field_by_name(const CassTableMeta* table_meta, - const char* name) { - return CassValue::to(table_meta->get_field(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(std::string(name, name_length))); -} - size_t cass_table_meta_column_count(const CassTableMeta* table_meta) { return table_meta->columns().size(); } @@ -193,6 +194,29 @@ const CassColumnMeta* cass_table_meta_column(const CassTableMeta* table_meta, return CassColumnMeta::to(table_meta->columns()[index].get()); } +const CassMaterializedViewMeta* cass_table_meta_materialized_view_by_name(const CassTableMeta* table_meta, + const char* view) { + return CassMaterializedViewMeta::to(table_meta->get_view(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(std::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(); } @@ -217,6 +241,86 @@ const CassColumnMeta* cass_table_meta_clustering_key(const CassTableMeta* table_ return CassColumnMeta::to(table_meta->clustering_key()[index].get()); } +const CassValue* cass_table_meta_field_by_name(const CassTableMeta* table_meta, + const char* name) { + return CassValue::to(table_meta->get_field(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(std::string(name, name_length))); +} + + +const CassColumnMeta* cass_materialized_view_meta_column_by_name(const CassMaterializedViewMeta* view_meta, + const char* column) { + return CassColumnMeta::to(view_meta->get_column(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(std::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(); +} + +void cass_materialized_view_meta_base_table_name(const CassMaterializedViewMeta* view_meta, + const char** name, size_t* name_length) { + *name = view_meta->base_table_name().data(); + *name_length = view_meta->base_table_name().size(); +} + +const CassValue* cass_materialized_view_meta_field_by_name(const CassMaterializedViewMeta* view_meta, + const char* name) { + return CassValue::to(view_meta->get_field(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(std::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()); +} + void cass_column_meta_name(const CassColumnMeta* column_meta, const char** name, size_t* name_length) { *name = column_meta->name().data(); @@ -385,6 +489,10 @@ CassIterator* cass_iterator_tables_from_keyspace_meta(const CassKeyspaceMeta* ke 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()); } @@ -405,10 +513,22 @@ CassIterator* cass_iterator_columns_from_table_meta(const CassTableMeta* table_m 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_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()); } @@ -439,6 +559,15 @@ const CassTableMeta* cass_iterator_get_table_meta(const CassIterator* iterator) 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( + iterator->from())->view()); +} + const CassDataType* cass_iterator_get_user_type(const CassIterator* iterator) { if (iterator->type() != CASS_ITERATOR_TYPE_TYPE_META) { return NULL; @@ -587,14 +716,36 @@ void Metadata::update_keyspaces(ResultResponse* result) { } } -void Metadata::update_tables(ResultResponse* tables_result, ResultResponse* columns_result) { +void Metadata::update_tables(ResultResponse* result) { schema_snapshot_version_++; if (is_front_buffer()) { ScopedMutex l(&mutex_); - updating_->update_tables(config_, tables_result, columns_result); + updating_->update_tables(config_, result); } else { - updating_->update_tables(config_, tables_result, columns_result); + updating_->update_tables(config_, result); + } +} + +void Metadata::update_views(ResultResponse* result) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_views(config_, result); + } else { + updating_->update_views(config_, result); + } +} + +void Metadata::update_columns(ResultResponse* result) { + schema_snapshot_version_++; + + if (is_front_buffer()) { + ScopedMutex l(&mutex_); + updating_->update_columns(config_, result); + } else { + updating_->update_columns(config_, result); } } @@ -642,14 +793,14 @@ void Metadata::drop_keyspace(const std::string& keyspace_name) { } } -void Metadata::drop_table(const std::string& keyspace_name, const std::string& table_name) { +void Metadata::drop_table_or_view(const std::string& keyspace_name, const std::string& table_or_view_name) { schema_snapshot_version_++; if (is_front_buffer()) { ScopedMutex l(&mutex_); - updating_->drop_table(keyspace_name, table_name); + updating_->drop_table_or_view(keyspace_name, table_or_view_name); } else { - updating_->drop_table(keyspace_name, table_name); + updating_->drop_table_or_view(keyspace_name, table_or_view_name); } } @@ -845,12 +996,9 @@ const TableMetadata* KeyspaceMetadata::get_table(const std::string& name) const return i->second.get(); } -const TableMetadata::Ptr& KeyspaceMetadata::get_or_create_table(const std::string& name) { +const TableMetadata::Ptr& KeyspaceMetadata::get_table(const std::string& name) { TableMetadata::Map::iterator i = tables_->find(name); - if (i == tables_->end()) { - i = tables_->insert(std::make_pair(name, - TableMetadata::Ptr(new TableMetadata(name)))).first; - } + if (i == tables_->end()) return TableMetadata::NIL; return i->second; } @@ -858,8 +1006,29 @@ void KeyspaceMetadata::add_table(const TableMetadata::Ptr& table) { (*tables_)[table->name()] = table; } -void KeyspaceMetadata::drop_table(const std::string& table_name) { - tables_->erase(table_name); +const ViewMetadata* KeyspaceMetadata::get_view(const std::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 std::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 std::string& table_or_view_name) { + if (tables_->erase(table_or_view_name) == 0) { + ViewMetadata::Map::iterator i = views_->find(table_or_view_name); + views_->erase(i); + TableMetadata::Ptr table = get_table(i->second->base_table_name()); + if (table) table->drop_view(table_or_view_name); + } } const UserType::Ptr& KeyspaceMetadata::get_or_create_user_type(const std::string& name) { @@ -950,11 +1119,10 @@ void KeyspaceMetadata::drop_aggregate(const std::string& full_aggregate_name) { aggregates_->erase(full_aggregate_name); } -TableMetadata::TableMetadata(const MetadataConfig& config, - const std::string& name, const SharedRefPtr& buffer, const Row* row) +TableMetadataBase::TableMetadataBase(const MetadataConfig& config, + const std::string& name, const SharedRefPtr& buffer, const Row* row) : MetadataBase(name) { add_field(buffer, row, "keyspace_name"); - add_field(buffer, row, table_column_name(config.cassandra_version)); add_field(buffer, row, "bloom_filter_fp_chance"); add_field(buffer, row, "caching"); add_field(buffer, row, "comment"); @@ -973,7 +1141,6 @@ TableMetadata::TableMetadata(const MetadataConfig& config, add_field(buffer, row, "compaction"); add_field(buffer, row, "compression"); add_field(buffer, row, "extensions"); - add_field(buffer, row, "flags"); } else { add_field(buffer, row, "cf_id"); add_field(buffer, row, "local_read_repair_chance"); @@ -1002,30 +1169,18 @@ TableMetadata::TableMetadata(const MetadataConfig& config, } } -const ColumnMetadata* TableMetadata::get_column(const std::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(); -} - -const ColumnMetadata::Ptr& TableMetadata::get_or_create_column(const std::string& name) { - ColumnMetadata::Map::iterator i = columns_by_name_.find(name); - if (i == columns_by_name_.end()) { - ColumnMetadata::Ptr column(new ColumnMetadata(name)); - i = columns_by_name_.insert(std::make_pair(name, column)).first; - columns_.push_back(column); - } - return i->second; +const ColumnMetadata* TableMetadataBase::get_column(const std::string& name) const { + ColumnMetadata::Vec::const_iterator i = std::find(columns_.begin(), columns_.end(), name); + if (i == columns_.end()) return NULL; + return i->get(); } -void TableMetadata::add_column(const ColumnMetadata::Ptr& column) { +void TableMetadataBase::add_column(const ColumnMetadata::Ptr& column) { columns_.push_back(column); - columns_by_name_[column->name()] = column; } -void TableMetadata::clear_columns() { +void TableMetadataBase::clear_columns() { columns_.clear(); - columns_by_name_.clear(); partition_key_.clear(); clustering_key_.clear(); } @@ -1039,7 +1194,7 @@ size_t get_column_count(const ColumnMetadata::Vec& columns, CassColumnType type) return count; } -void TableMetadata::build_keys_and_sort(const MetadataConfig& config) { +void TableMetadataBase::build_keys_and_sort(const MetadataConfig& config) { // Also, Reorders columns so that the order is: // 1) Parition key // 2) Clustering keys @@ -1100,7 +1255,7 @@ void TableMetadata::build_keys_and_sort(const MetadataConfig& config) { } } - // Clustring key + // Clustering key { StringRefVec column_aliases; const Value* column_aliases_value = get_field("column_aliases"); @@ -1155,6 +1310,38 @@ void TableMetadata::build_keys_and_sort(const MetadataConfig& config) { } } +const TableMetadata::Ptr TableMetadata::NIL; + +TableMetadata::TableMetadata(const MetadataConfig& config, + const std::string& name, const SharedRefPtr& buffer, const Row* row) + : TableMetadataBase(config, name, buffer, row) { + add_field(buffer, row, table_column_name(config.cassandra_version)); + if (config.cassandra_version >= VersionNumber(3, 0, 0)) { + add_field(buffer, row, "flags"); + } +} + +const ViewMetadata* TableMetadata::get_view(const std::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::drop_view(const std::string& name) { + ViewMetadata::Vec::const_iterator i = std::lower_bound(views_.begin(), views_.end(), name); + if (i != views_.end() && (*i)->name() == name) { + views_.erase(i); + } +} + +void TableMetadata::sort_views() { + std::sort(views_.begin(), views_.end()); +} + void TableMetadata::key_aliases(const NativeDataTypes& native_types, KeyAliases* output) const { const Value* aliases = get_field("key_aliases"); if (aliases != NULL) { @@ -1179,6 +1366,23 @@ void TableMetadata::key_aliases(const NativeDataTypes& native_types, KeyAliases* } } +const ViewMetadata::Ptr ViewMetadata::NIL; + +ViewMetadata::ViewMetadata(const MetadataConfig& config, + const std::string& name, const SharedRefPtr& buffer, const Row* row) + : TableMetadataBase(config, name, buffer, row) { + const Value* value; + add_field(buffer, row, "view_name"); + value = add_field(buffer, row, "base_table_name"); + if (value != NULL && + value->value_type() == CASS_VALUE_TYPE_VARCHAR) { + base_table_name_ = value->to_string(); + } + add_field(buffer, row, "base_table_id"); + add_field(buffer, row, "include_all_columns"); + add_field(buffer, row, "where_clause"); +} + FunctionMetadata::FunctionMetadata(const MetadataConfig& config, const std::string& name, const Value* signature, KeyspaceMetadata* keyspace, @@ -1206,14 +1410,12 @@ FunctionMetadata::FunctionMetadata(const MetadataConfig& config, StringRef arg_name(iterator1.value()->to_string_ref()); DataType::ConstPtr arg_type(DataTypeCqlNameParser::parse(iterator2.value()->to_string(), config.native_types, keyspace)); args_.push_back(Argument(arg_name, arg_type)); - args_by_name_[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(), config.native_types)); args_.push_back(Argument(arg_name, arg_type)); - args_by_name_[arg_name] = arg_type; } } } @@ -1248,9 +1450,9 @@ FunctionMetadata::FunctionMetadata(const MetadataConfig& config, } const DataType* FunctionMetadata::get_arg_type(StringRef name) const { - Argument::Map::const_iterator i = args_by_name_.find(name); - if (i == args_by_name_.end()) return NULL; - return i->second.get(); + 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 MetadataConfig& config, @@ -1444,11 +1646,11 @@ void Metadata::InternalData::update_keyspaces(const MetadataConfig& config, } void Metadata::InternalData::update_tables(const MetadataConfig& config, - ResultResponse* tables_result, ResultResponse* columns_result) { - SharedRefPtr buffer = tables_result->buffer(); + ResultResponse* result) { + SharedRefPtr buffer = result->buffer(); - tables_result->decode_first_row(); - ResultIterator rows(tables_result); + result->decode_first_row(); + ResultIterator rows(result); std::string keyspace_name; std::string table_name; @@ -1471,8 +1673,50 @@ void Metadata::InternalData::update_tables(const MetadataConfig& config, keyspace->add_table(TableMetadata::Ptr(new TableMetadata(config, table_name, buffer, row))); } +} + +void Metadata::InternalData::update_views(const MetadataConfig& config, + ResultResponse* result) { + SharedRefPtr buffer = result->buffer(); - update_columns(config, columns_result); + result->decode_first_row(); + ResultIterator rows(result); + + std::string keyspace_name; + std::string view_name; + KeyspaceMetadata* keyspace = NULL; + + TableMetadata::Vec updated_tables; + + while (rows.next()) { + std::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("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); + } + + ViewMetadata::Ptr view(new ViewMetadata(config, view_name, buffer, row)); + keyspace->add_view(view); + + TableMetadata::Ptr table(keyspace->get_table(view->base_table_name())); + if (table) { + 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 MetadataConfig& config, ResultResponse* result) { @@ -1632,10 +1876,11 @@ void Metadata::InternalData::drop_keyspace(const std::string& keyspace_name) { keyspaces_->erase(keyspace_name); } -void Metadata::InternalData::drop_table(const std::string& keyspace_name, const std::string& table_name) { +void Metadata::InternalData::drop_table_or_view(const std::string& keyspace_name, + const std::string& table_or_view_name) { KeyspaceMetadata::Map::iterator i = keyspaces_->find(keyspace_name); if (i == keyspaces_->end()) return; - i->second.drop_table(table_name); + i->second.drop_table_or_view(table_or_view_name); } void Metadata::InternalData::drop_user_type(const std::string& keyspace_name, const std::string& type_name) { @@ -1663,19 +1908,19 @@ void Metadata::InternalData::update_columns(const MetadataConfig& config, Result ResultIterator rows(result); std::string keyspace_name; - std::string table_name; + std::string table_or_view_name; std::string column_name; KeyspaceMetadata* keyspace = NULL; - TableMetadata::Ptr table; + TableMetadataBase::Ptr table_or_view; while (rows.next()) { std::string temp_keyspace_name; - std::string temp_table_name; + std::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(config.cassandra_version), &temp_table_name) || + !row->get_string_by_name(table_column_name(config.cassandra_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(config.cassandra_version)); @@ -1687,23 +1932,28 @@ void Metadata::InternalData::update_columns(const MetadataConfig& config, Result keyspace = get_or_create_keyspace(keyspace_name); } - if (table_name != temp_table_name) { + if (table_or_view_name != temp_table_or_view_name) { // Build keys for the previous table - if (table) { - table->build_keys_and_sort(config); + if (table_or_view) { + table_or_view->build_keys_and_sort(config); } - table_name = temp_table_name; - table = keyspace->get_or_create_table(table_name); - table->clear_columns(); + 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(); } - table->add_column(ColumnMetadata::Ptr(new ColumnMetadata(config, column_name, - keyspace, buffer, row))); + if (table_or_view) { + table_or_view->add_column(ColumnMetadata::Ptr(new ColumnMetadata(config, column_name, + keyspace, buffer, row))); + } } // Build keys for the last table - if (table) { - table->build_keys_and_sort(config); + if (table_or_view) { + table_or_view->build_keys_and_sort(config); } } diff --git a/src/metadata.hpp b/src/metadata.hpp index 60004d95b..f4c335d27 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -197,7 +197,6 @@ class FunctionMetadata : public MetadataBase, public RefCounted Vec; - typedef std::map Map; Argument(const StringRef& name, const DataType::ConstPtr& type) : name(name) @@ -223,13 +222,16 @@ class FunctionMetadata : public MetadataBase, public RefCounted { public: typedef SharedRefPtr Ptr; @@ -262,7 +264,6 @@ class AggregateMetadata : public MetadataBase, public RefCounted { public: typedef SharedRefPtr Ptr; - typedef std::map Map; typedef std::vector Vec; ColumnMetadata(const std::string& name) @@ -297,24 +298,23 @@ class ColumnMetadata : public MetadataBase, public RefCounted { DISALLOW_COPY_AND_ASSIGN(ColumnMetadata); }; -class TableMetadata : public MetadataBase, public RefCounted { +inline bool operator==(const ColumnMetadata::Ptr& a, const std::string& b) { + return a->name() == b; +} + +class TableMetadataBase : public MetadataBase, public RefCounted { public: - typedef SharedRefPtr Ptr; - typedef std::map Map; - typedef std::vector KeyAliases; + typedef SharedRefPtr Ptr; class ColumnIterator : public MetadataIteratorImpl > { public: - ColumnIterator(const ColumnIterator::Collection& collection) - : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_COLUMN_META, collection) { } + ColumnIterator(const ColumnIterator::Collection& collection) + : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_COLUMN_META, collection) { } const ColumnMetadata* column() const { return impl_.item().get(); } }; - TableMetadata(const std::string& name) - : MetadataBase(name) { } - - TableMetadata(const MetadataConfig& config, - const std::string& name, const SharedRefPtr& buffer, const Row* row); + TableMetadataBase(const MetadataConfig& config, + const std::string& name, const SharedRefPtr& buffer, const Row* row); const ColumnMetadata::Vec& columns() const { return columns_; } const ColumnMetadata::Vec& partition_key() const { return partition_key_; } @@ -322,20 +322,106 @@ class TableMetadata : public MetadataBase, public RefCounted { Iterator* iterator_columns() const { return new ColumnIterator(columns_); } const ColumnMetadata* get_column(const std::string& name) const; - const ColumnMetadata::Ptr& get_or_create_column(const std::string& name); void add_column(const ColumnMetadata::Ptr& column); void clear_columns(); void build_keys_and_sort(const MetadataConfig& config); - void key_aliases(const NativeDataTypes& native_types, KeyAliases* output) const; -private: +protected: ColumnMetadata::Vec columns_; - ColumnMetadata::Map columns_by_name_; ColumnMetadata::Vec partition_key_; ColumnMetadata::Vec clustering_key_; private: - DISALLOW_COPY_AND_ASSIGN(TableMetadata); + DISALLOW_COPY_AND_ASSIGN(TableMetadataBase); +}; + +class ViewMetadata : public TableMetadataBase { +public: + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector Vec; + + static const ViewMetadata::Ptr NIL; + + ViewMetadata(const MetadataConfig& config, const std::string& name, + const SharedRefPtr& buffer, const Row* row); + + const std::string& base_table_name() const { return base_table_name_; } + +private: + std::string base_table_name_; +}; + +class ViewIteratorBase : public Iterator { +public: + ViewIteratorBase(CassIteratorType type) + : Iterator(type) { } + + virtual ViewMetadata* view() const = 0; +}; + +class ViewIteratorVec : public ViewIteratorBase { +public: + ViewIteratorVec(const ViewMetadata::Vec& views) + : ViewIteratorBase(CASS_ITERATOR_TYPE_MATERIALIZED_VIEW_META) + , impl_(views) { } + + virtual ViewMetadata* view() const { return impl_.item().get(); } + virtual bool next() { return impl_.next(); } + +private: + VecIteratorImpl impl_; +}; + +class ViewIteratorMap : public ViewIteratorBase { +public: + ViewIteratorMap(const ViewMetadata::Map& views) + : ViewIteratorBase(CASS_ITERATOR_TYPE_MATERIALIZED_VIEW_META) + , impl_(views) { } + + virtual ViewMetadata* view() const { return impl_.item().get(); } + virtual bool next() { return impl_.next(); } + +private: + MapIteratorImpl impl_; +}; + +inline bool operator<(const ViewMetadata::Ptr& a, const ViewMetadata::Ptr& b) { + return a->name() < b->name(); +} + +inline bool operator<(const ViewMetadata::Ptr& a, const std::string& b) { + return a->name() < b; +} + +inline bool operator==(const ViewMetadata::Ptr& a, const ViewMetadata::Ptr& b) { + return a->name() == b->name(); +} + +class TableMetadata : public TableMetadataBase { +public: + typedef SharedRefPtr Ptr; + typedef std::map Map; + typedef std::vector Vec; + typedef std::vector KeyAliases; + + static const TableMetadata::Ptr NIL; + + TableMetadata(const MetadataConfig& config, const std::string& name, + const SharedRefPtr& buffer, const Row* row); + + const ViewMetadata::Vec& views() const { return views_; } + + Iterator* iterator_views() const { return new ViewIteratorVec(views_); } + const ViewMetadata* get_view(const std::string& name) const; + void add_view(const ViewMetadata::Ptr& view); + void drop_view(const std::string& name); + void sort_views(); + + void key_aliases(const NativeDataTypes& native_types, KeyAliases* output) const; + +private: + ViewMetadata::Vec views_; }; class KeyspaceMetadata : public MetadataBase { @@ -348,7 +434,7 @@ class KeyspaceMetadata : public MetadataBase { public: TableIterator(const TableIterator::Collection& collection) : MetadataIteratorImpl >(CASS_ITERATOR_TYPE_TABLE_META, collection) { } - const TableMetadata* table() const { return impl_.item().get(); } + const TableMetadata* table() const { return static_cast(impl_.item().get()); } }; class TypeIterator : public MetadataIteratorImpl > { @@ -375,6 +461,7 @@ class KeyspaceMetadata : public MetadataBase { KeyspaceMetadata(const std::string& name) : MetadataBase(name) , tables_(new TableMetadata::Map) + , views_(new ViewMetadata::Map) , user_types_(new UserType::Map) , functions_(new FunctionMetadata::Map) , aggregates_(new AggregateMetadata::Map) { } @@ -386,10 +473,16 @@ class KeyspaceMetadata : public MetadataBase { const UserType::Map& user_types() const { return *user_types_; } Iterator* iterator_tables() const { return new TableIterator(*tables_); } - const TableMetadata* get_table(const std::string& table_name) const; - const TableMetadata::Ptr& get_or_create_table(const std::string& name); + const TableMetadata* get_table(const std::string& name) const; + const TableMetadata::Ptr& get_table(const std::string& name); void add_table(const TableMetadata::Ptr& table); - void drop_table(const std::string& table_name); + + Iterator* iterator_views() const { return new ViewIteratorMap(*views_); } + const ViewMetadata* get_view(const std::string& name) const; + const ViewMetadata::Ptr& get_view(const std::string& name); + void add_view(const ViewMetadata::Ptr& view); + + void drop_table_or_view(const std::string& table_name); Iterator* iterator_user_types() const { return new TypeIterator(*user_types_); } const UserType* get_user_type(const std::string& type_name) const; @@ -414,6 +507,7 @@ class KeyspaceMetadata : public MetadataBase { OptionsMap strategy_options_; CopyOnWritePtr tables_; + CopyOnWritePtr views_; CopyOnWritePtr user_types_; CopyOnWritePtr functions_; CopyOnWritePtr aggregates_; @@ -468,13 +562,15 @@ class Metadata { SchemaSnapshot schema_snapshot() const; void update_keyspaces(ResultResponse* result); - void update_tables(ResultResponse* tables_result, ResultResponse* columns_result); + void update_tables(ResultResponse* result); + void update_views(ResultResponse* result); + void update_columns(ResultResponse* result); void update_user_types(ResultResponse* result); void update_functions(ResultResponse* result); void update_aggregates(ResultResponse* result); void drop_keyspace(const std::string& keyspace_name); - void drop_table(const std::string& keyspace_name, const std::string& table_name); + void drop_table_or_view(const std::string& keyspace_name, const std::string& table_or_view_name); void drop_user_type(const std::string& keyspace_name, const std::string& type_name); void drop_function(const std::string& keyspace_name, const std::string& full_function_name); void drop_aggregate(const std::string& keyspace_name, const std::string& full_aggregate_name); @@ -517,13 +613,15 @@ class Metadata { const KeyspaceMetadata::MapPtr& keyspaces() const { return keyspaces_; } void update_keyspaces(const MetadataConfig& config, ResultResponse* result, KeyspaceMetadata::Map& updates); - void update_tables(const MetadataConfig& config, ResultResponse* tables_result, ResultResponse* columns_result); + void update_tables(const MetadataConfig& config, ResultResponse* result); + void update_views(const MetadataConfig& config, ResultResponse* result); + void update_columns(const MetadataConfig& config, ResultResponse* result); void update_user_types(const MetadataConfig& config, ResultResponse* result); void update_functions(const MetadataConfig& config, ResultResponse* result); void update_aggregates(const MetadataConfig& config, ResultResponse* result); void drop_keyspace(const std::string& keyspace_name); - void drop_table(const std::string& keyspace_name, const std::string& table_name); + void drop_table_or_view(const std::string& keyspace_name, const std::string& table_or_view_name); void drop_user_type(const std::string& keyspace_name, const std::string& type_name); void drop_function(const std::string& keyspace_name, const std::string& full_function_name); void drop_aggregate(const std::string& keyspace_name, const std::string& full_aggregate_name); @@ -537,8 +635,6 @@ class Metadata { } private: - void update_columns(const MetadataConfig& config, ResultResponse* result); - KeyspaceMetadata* get_or_create_keyspace(const std::string& name); private: diff --git a/test/integration_tests/src/test_schema_metadata.cpp b/test/integration_tests/src/test_schema_metadata.cpp index 5186facb7..262e05d3f 100644 --- a/test/integration_tests/src/test_schema_metadata.cpp +++ b/test/integration_tests/src/test_schema_metadata.cpp @@ -42,6 +42,14 @@ #define USER_DEFINED_AGGREGATE_NAME "user_defined_aggregate" #define USER_DEFINED_AGGREGATE_FINAL_FUNCTION_NAME "uda_udf_final" +namespace std { + +std::ostream& operator<<(std::ostream& os, const CassString& str) { + return os << std::string(str.data, str.length); +} + +} // namespace std + /** * Schema Metadata Test Class * @@ -439,6 +447,86 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { BOOST_CHECK(!table_meta); } + void verify_materialized_view_count(const std::string& keyspace_name, + size_t count) { + const CassKeyspaceMeta* keyspace_meta = schema_get_keyspace("materialized_views"); + test_utils::CassIteratorPtr iterator(cass_iterator_materialized_views_from_keyspace_meta(keyspace_meta)); + + size_t actual_count = 0; + while (cass_iterator_next(iterator.get())) { + actual_count++; + } + BOOST_CHECK_EQUAL(actual_count, count); + + } + + void verify_materialized_view(const CassMaterializedViewMeta* view, + const std::string& view_name, + const std::string& view_base_table_name, + const std::string& view_columns, + const std::string& view_partition_key, + const std::string& view_clustering_key) { + BOOST_REQUIRE(view != NULL); + + CassString name; + cass_materialized_view_meta_name(view, &name.data, &name.length); + BOOST_CHECK(name == CassString(view_name.c_str())); + + CassString base_table_name; + cass_materialized_view_meta_base_table_name(view, &base_table_name.data, &base_table_name.length); + BOOST_CHECK(base_table_name == CassString(view_base_table_name.c_str())); + + std::vector columns; + cass::explode(view_columns, columns); + BOOST_REQUIRE_EQUAL(cass_materialized_view_meta_column_count(view), columns.size()); + + test_utils::CassIteratorPtr iterator(cass_iterator_columns_from_materialized_view_meta(view)); + for (std::vector::const_iterator i = columns.begin(), + end = columns.end(); i != end; ++i) { + BOOST_REQUIRE(cass_iterator_next(iterator.get())); + const CassColumnMeta* column = cass_iterator_get_column_meta(iterator.get()); + + CassString column_name; + cass_column_meta_name(column, &column_name.data, &column_name.length); + + BOOST_CHECK(column_name == CassString(i->c_str())); + } + BOOST_CHECK(cass_iterator_next(iterator.get()) == cass_false); + + for (size_t i = 0; i < columns.size(); ++i) { + const CassColumnMeta* column = cass_materialized_view_meta_column(view, i); + + CassString column_name; + cass_column_meta_name(column, &column_name.data, &column_name.length); + + BOOST_CHECK_EQUAL(column_name, CassString(columns[i].c_str())); + } + + std::vector partition_key; + cass::explode(view_partition_key, partition_key); + BOOST_REQUIRE_EQUAL(cass_materialized_view_meta_partition_key_count(view), partition_key.size()); + for (size_t i = 0; i < partition_key.size(); ++i) { + const CassColumnMeta* column = cass_materialized_view_meta_partition_key(view, i); + + CassString column_name; + cass_column_meta_name(column, &column_name.data, &column_name.length); + + BOOST_CHECK_EQUAL(column_name, CassString(partition_key[i].c_str())); + } + + std::vector clustering_key; + cass::explode(view_clustering_key, clustering_key); + BOOST_REQUIRE_EQUAL(cass_materialized_view_meta_clustering_key_count(view), clustering_key.size()); + for (size_t i = 0; i < clustering_key.size(); ++i) { + const CassColumnMeta* column = cass_materialized_view_meta_clustering_key(view, i); + + CassString column_name; + cass_column_meta_name(column, &column_name.data, &column_name.length); + + BOOST_CHECK_EQUAL(column_name, CassString(clustering_key[i].c_str())); + } + } + const std::set& keyspace_fields() { static std::set fields; if (fields.empty()) { @@ -972,5 +1060,122 @@ BOOST_AUTO_TEST_CASE(disable) { test_utils::execute_query_with_error(session, str(boost::format(test_utils::DROP_KEYSPACE_FORMAT) % "ks2")); } -BOOST_AUTO_TEST_SUITE_END() +/** + * @since 2.3.0 + * @jira_ticket CPP-331 + * @test_category schema + * @cassandra_version 3.0.x + */ +BOOST_AUTO_TEST_CASE(materialized_views) { + { + if (version < "3.0.0") return; + + test_utils::execute_query(session, "CREATE KEYSPACE materialized_views WITH replication = " + "{ 'class' : 'SimpleStrategy', 'replication_factor' : 3 }"); + + test_utils::execute_query(session, "CREATE TABLE materialized_views.table1 (key1 text, value1 int, PRIMARY KEY(key1))"); + test_utils::execute_query(session, "CREATE TABLE materialized_views.table2 (key1 text, key2 int, value1 int, PRIMARY KEY(key1, key2))"); + + refresh_schema_meta(); + + verify_materialized_view_count("materialized_views", 0); + + const CassTableMeta* table_meta = schema_get_table("materialized_views", "table1"); + BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 0); + BOOST_CHECK(cass_table_meta_materialized_view_by_name(table_meta, "invalid") == NULL); + BOOST_CHECK(cass_table_meta_materialized_view(table_meta, 0) == NULL); + } + // Simple materialized view + { + test_utils::execute_query(session, "CREATE MATERIALIZED VIEW materialized_views.view1 AS " + "SELECT key1 FROM materialized_views.table1 WHERE value1 IS NOT NULL " + "PRIMARY KEY(value1, key1)"); + refresh_schema_meta(); + + verify_materialized_view_count("materialized_views", 1); + + const CassTableMeta* table_meta = schema_get_table("materialized_views", "table1"); + BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 1); + + verify_materialized_view(cass_table_meta_materialized_view_by_name(table_meta, "view1"), + "view1", "table1", + "value1,key1", "value1", "key1"); + } + + // Materialized view with composite partition key + { + test_utils::execute_query(session, "CREATE MATERIALIZED VIEW materialized_views.view2 AS " + "SELECT key1 FROM materialized_views.table2 WHERE key2 IS NOT NULL AND value1 IS NOT NULL " + "PRIMARY KEY((value1, key2), key1)"); + + refresh_schema_meta(); + + verify_materialized_view_count("materialized_views", 2); + + const CassTableMeta* table_meta = schema_get_table("materialized_views", "table2"); + BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 1); + + verify_materialized_view(cass_table_meta_materialized_view_by_name(table_meta, "view2"), + "view2", "table2", + "value1,key2,key1", "value1,key2", "key1"); + } + + // Materialized view with composite clustering key + { + test_utils::execute_query(session, "CREATE MATERIALIZED VIEW materialized_views.view3 AS " + "SELECT key1 FROM materialized_views.table2 WHERE key2 IS NOT NULL AND value1 IS NOT NULL " + "PRIMARY KEY(value1, key2, key1) " + "WITH CLUSTERING ORDER BY (key2 DESC)"); + + refresh_schema_meta(); + + verify_materialized_view_count("materialized_views", 3); + + const CassTableMeta* table_meta = schema_get_table("materialized_views", "table2"); + BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 2); + + verify_materialized_view(cass_table_meta_materialized_view_by_name(table_meta, "view3"), + "view3", "table2", + "value1,key2,key1", "value1", "key2,key1"); + } + + // Iterator + { + const CassTableMeta* table_meta = schema_get_table("materialized_views", "table2"); + + test_utils::CassIteratorPtr iterator(cass_iterator_materialized_views_from_table_meta(table_meta)); + + while (cass_iterator_next(iterator.get())) { + const CassMaterializedViewMeta* view_meta = cass_iterator_get_materialized_view_meta(iterator.get()); + BOOST_REQUIRE(view_meta != NULL); + + CassString name; + cass_materialized_view_meta_name(view_meta, &name.data, &name.length); + + if (name == CassString("view2")) { + verify_materialized_view(view_meta, "view2", "table2", + "value1,key2,key1", "value1,key2", "key1"); + } else if (name == CassString("view3")) { + verify_materialized_view(view_meta, "view3", "table2", + "value1,key2,key1", "value1", "key2,key1"); + } else { + BOOST_CHECK(false); + } + } + } + + // Drop view + { + test_utils::execute_query(session, "DROP MATERIALIZED VIEW materialized_views.view2"); + + refresh_schema_meta(); + + verify_materialized_view_count("materialized_views", 2); + + const CassTableMeta* table_meta = schema_get_table("materialized_views", "table2"); + BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 1); + } +} + +BOOST_AUTO_TEST_SUITE_END() From 4e713292e1fa5c556c39142518bf63d94b1b11b0 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Thu, 25 Feb 2016 09:22:17 -0700 Subject: [PATCH 2/5] Fix: std::vector::erase() only supports const iterator in C++11 --- src/metadata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metadata.cpp b/src/metadata.cpp index 2c6862877..de363746b 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -1332,7 +1332,7 @@ void TableMetadata::add_view(const ViewMetadata::Ptr& view) { } void TableMetadata::drop_view(const std::string& name) { - ViewMetadata::Vec::const_iterator i = std::lower_bound(views_.begin(), views_.end(), name); + ViewMetadata::Vec::iterator i = std::lower_bound(views_.begin(), views_.end(), name); if (i != views_.end() && (*i)->name() == name) { views_.erase(i); } From 2e558ca7e1dbfc6151f4ef5909c8543c20703373 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Fri, 26 Feb 2016 11:13:47 -0700 Subject: [PATCH 3/5] Update materialized view test documentation --- test/integration_tests/src/test_schema_metadata.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/integration_tests/src/test_schema_metadata.cpp b/test/integration_tests/src/test_schema_metadata.cpp index 262e05d3f..0973944d9 100644 --- a/test/integration_tests/src/test_schema_metadata.cpp +++ b/test/integration_tests/src/test_schema_metadata.cpp @@ -1061,6 +1061,10 @@ BOOST_AUTO_TEST_CASE(disable) { } /** + * Test materialized views. + * + * Verifies that materialized view metadata is correctly updated and returned. + * * @since 2.3.0 * @jira_ticket CPP-331 * @test_category schema From c7ea1eac55b10826dbd9a547276a6706b92a2970 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Tue, 1 Mar 2016 11:04:51 -0700 Subject: [PATCH 4/5] Return the base table itself instead of the base table name --- include/cassandra.h | 12 ++-- src/metadata.cpp | 64 ++++++++++++------- src/metadata.hpp | 14 +++- .../src/test_schema_metadata.cpp | 23 ++++++- 4 files changed, 77 insertions(+), 36 deletions(-) diff --git a/include/cassandra.h b/include/cassandra.h index 937b66306..07b84008e 100644 --- a/include/cassandra.h +++ b/include/cassandra.h @@ -2124,18 +2124,16 @@ cass_materialized_view_meta_name(const CassMaterializedViewMeta* view_meta, size_t* name_length); /** - * Gets the base table name of the view. + * Gets the base table of the view. * * @public @memberof CassMaterializedViewMeta * * @param[in] view_meta - * @param[out] name - * @param[out] name_length + * + * @return The base table for the view. */ -CASS_EXPORT void -cass_materialized_view_meta_base_table_name(const CassMaterializedViewMeta* view_meta, - const char** name, - size_t* name_length); +CASS_EXPORT const CassTableMeta* +cass_materialized_view_meta_base_table(const CassMaterializedViewMeta* view_meta); /** * Gets the total number of columns for the view. diff --git a/src/metadata.cpp b/src/metadata.cpp index de363746b..5078e2a9d 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -269,10 +269,8 @@ void cass_materialized_view_meta_name(const CassMaterializedViewMeta* view_meta, *name_length = view_meta->name().size(); } -void cass_materialized_view_meta_base_table_name(const CassMaterializedViewMeta* view_meta, - const char** name, size_t* name_length) { - *name = view_meta->base_table_name().data(); - *name_length = view_meta->base_table_name().size(); +const CassTableMeta* cass_materialized_view_meta_base_table(const CassMaterializedViewMeta* view_meta) { + return CassTableMeta::to(view_meta->base_table()); } const CassValue* cass_materialized_view_meta_field_by_name(const CassMaterializedViewMeta* view_meta, @@ -1023,11 +1021,25 @@ void KeyspaceMetadata::add_view(const ViewMetadata::Ptr& view) { } void KeyspaceMetadata::drop_table_or_view(const std::string& table_or_view_name) { - if (tables_->erase(table_or_view_name) == 0) { - ViewMetadata::Map::iterator i = views_->find(table_or_view_name); - views_->erase(i); - TableMetadata::Ptr table = get_table(i->second->base_table_name()); - if (table) table->drop_view(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); + view->base_table()->drop_view(table_or_view_name); + views_->erase(view_it); + } } } @@ -1369,15 +1381,13 @@ void TableMetadata::key_aliases(const NativeDataTypes& native_types, KeyAliases* const ViewMetadata::Ptr ViewMetadata::NIL; ViewMetadata::ViewMetadata(const MetadataConfig& config, + TableMetadata* table, const std::string& name, const SharedRefPtr& buffer, const Row* row) - : TableMetadataBase(config, name, buffer, row) { - const Value* value; + : TableMetadataBase(config, name, buffer, row) + , base_table_(table) { + add_field(buffer, row, "keyspace_name"); add_field(buffer, row, "view_name"); - value = add_field(buffer, row, "base_table_name"); - if (value != NULL && - value->value_type() == CASS_VALUE_TYPE_VARCHAR) { - base_table_name_ = value->to_string(); - } + 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"); @@ -1690,11 +1700,12 @@ void Metadata::InternalData::update_views(const MetadataConfig& config, while (rows.next()) { std::string temp_keyspace_name; + std::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"); + LOG_ERROR("Unable to get column value for 'keyspace_name' and 'view_name'"); continue; } @@ -1703,14 +1714,21 @@ void Metadata::InternalData::update_views(const MetadataConfig& config, keyspace = get_or_create_keyspace(keyspace_name); } - ViewMetadata::Ptr view(new ViewMetadata(config, view_name, buffer, row)); - keyspace->add_view(view); + if (!row->get_string_by_name("base_table_name", &base_table_name)) { + LOG_ERROR("Unable to get column value for 'base_table_name'"); + continue; + } - TableMetadata::Ptr table(keyspace->get_table(view->base_table_name())); - if (table) { - table->add_view(view); - updated_tables.push_back(table); + 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(config, table.get(), view_name, buffer, row)); + keyspace->add_view(view); + table->add_view(view); + updated_tables.push_back(table); } for (TableMetadata::Vec::iterator i = updated_tables.begin(), diff --git a/src/metadata.hpp b/src/metadata.hpp index f4c335d27..a6283af7f 100644 --- a/src/metadata.hpp +++ b/src/metadata.hpp @@ -35,6 +35,7 @@ namespace cass { class KeyspaceMetadata; +class TableMetadata; class Row; class ResultResponse; @@ -343,13 +344,20 @@ class ViewMetadata : public TableMetadataBase { static const ViewMetadata::Ptr NIL; - ViewMetadata(const MetadataConfig& config, const std::string& name, + ViewMetadata(const MetadataConfig& config, + TableMetadata* table, + const std::string& name, const SharedRefPtr& buffer, const Row* row); - const std::string& base_table_name() const { return base_table_name_; } + const TableMetadata* base_table() const { return base_table_; } + TableMetadata* base_table() { return base_table_; } private: - std::string base_table_name_; + // This cannot be a reference counted pointer because it would cause a cycle. + // This is okay because the lifetime of the table will exceed the lifetime + // of a table's view. That is, a table's views will be removed when a table is + // removed. + TableMetadata* base_table_; }; class ViewIteratorBase : public Iterator { diff --git a/test/integration_tests/src/test_schema_metadata.cpp b/test/integration_tests/src/test_schema_metadata.cpp index 0973944d9..57d02db37 100644 --- a/test/integration_tests/src/test_schema_metadata.cpp +++ b/test/integration_tests/src/test_schema_metadata.cpp @@ -472,8 +472,9 @@ struct TestSchemaMetadata : public test_utils::SingleSessionTest { cass_materialized_view_meta_name(view, &name.data, &name.length); BOOST_CHECK(name == CassString(view_name.c_str())); + const CassTableMeta* base_table = cass_materialized_view_meta_base_table(view); CassString base_table_name; - cass_materialized_view_meta_base_table_name(view, &base_table_name.data, &base_table_name.length); + cass_table_meta_name(base_table, &base_table_name.data, &base_table_name.length); BOOST_CHECK(base_table_name == CassString(view_base_table_name.c_str())); std::vector columns; @@ -1169,17 +1170,33 @@ BOOST_AUTO_TEST_CASE(materialized_views) { } } - // Drop view + // Drop views { + const CassTableMeta* table_meta; + test_utils::execute_query(session, "DROP MATERIALIZED VIEW materialized_views.view2"); refresh_schema_meta(); verify_materialized_view_count("materialized_views", 2); - const CassTableMeta* table_meta = schema_get_table("materialized_views", "table2"); + table_meta = schema_get_table("materialized_views", "table2"); BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 1); + + test_utils::execute_query(session, "DROP MATERIALIZED VIEW materialized_views.view1"); + + refresh_schema_meta(); + + verify_materialized_view_count("materialized_views", 1); + + table_meta = schema_get_table("materialized_views", "table1"); + BOOST_CHECK(cass_table_meta_materialized_view_count(table_meta) == 0); } + + // Note: Cassandra doesn't allow for dropping tables with active views. + // It's also difficult and unpredictable to get DROP TABLE/MATERIALIZE VIEW + // events to reorder so that the DROP TABLE event happens before the + // DROP MATERIALIZE VIEW event. } BOOST_AUTO_TEST_SUITE_END() From 4bdd1b8700a7ff5e84c35b347cc9d12a424e29f7 Mon Sep 17 00:00:00 2001 From: Michael Penick Date: Thu, 3 Mar 2016 09:23:42 -0700 Subject: [PATCH 5/5] Fix: Invalid formatting, find view if a table doesn't exist --- src/metadata.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/metadata.cpp b/src/metadata.cpp index 5078e2a9d..1509a7b7c 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -1957,9 +1957,10 @@ void Metadata::InternalData::update_columns(const MetadataConfig& config, Result } 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; + 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(); }