<NME> value.hpp
<BEF> /*
  Copyright (c) DataStax, Inc.

  Licensed 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.
*/

#ifndef DATASTAX_INTERNAL_VALUE_HPP
#define DATASTAX_INTERNAL_VALUE_HPP

#include "cassandra.h"
#include "decoder.hpp"
#include "external.hpp"
#include "result_metadata.hpp"
#include "string_ref.hpp"

namespace datastax { namespace internal { namespace core {
public:
  Value()
      : type_(CASS_VALUE_TYPE_UNKNOWN)
      , def_(NULL)
      , count_(0) {}

  Value(CassValueType type, char* data, size_t size)
      : type_(type)
      , def_(NULL)
      , count_(0)
      , buffer_(data, size) {}

  Value(const ColumnDefinition* definition, int32_t count, char* data, size_t size)
    : type_(static_cast<CassValueType>(definition->type))
    , def_(definition)
    , count_(count)
    , buffer_(data, size) {}

  CassValueType type() const { return type_; }

  CassValueType primary_type() const {
    if (def_ == NULL) {
      return CASS_VALUE_TYPE_UNKNOWN;
    }
    return static_cast<CassValueType>(def_->collection_primary_type);
  }

  CassValueType secondary_type() const {
    if (def_ == NULL) {
      return CASS_VALUE_TYPE_UNKNOWN;
    }
    return static_cast<CassValueType>(def_->collection_secondary_type);
  }

  bool is_null() const {
    if (!primary) {
      return CASS_VALUE_TYPE_UNKNOWN;
    }
    return primary->value_type();
  }

  const DataType::ConstPtr& primary_data_type() const {
    if (!data_type_ || !data_type_->is_collection()) {
      return DataType::NIL;
    }
    const CollectionType::ConstPtr& collection_type(data_type_);
    if (collection_type->types().size() < 1) {
      return DataType::NIL;

private:
  CassValueType type_;
  const ColumnDefinition* def_;
  int32_t count_;
  BufferPiece buffer_;
};
    }
    return secondary->value_type();
  }

  const DataType::ConstPtr& secondary_data_type() const {
    if (!data_type_ || !data_type_->is_map()) {
      return DataType::NIL;
    }
    const CollectionType::ConstPtr& collection_type(data_type_);
    if (collection_type->types().size() < 2) {
      return DataType::NIL;
    }
    return collection_type->types()[1];
  }

  bool is_null() const { return is_null_; }

  bool is_collection() const {
    if (!data_type_) return false;
    return data_type_->is_collection();
  }

  bool is_map() const {
    if (!data_type_) return false;
    return data_type_->is_map();
  }

  bool is_tuple() const {
    if (!data_type_) return false;
    return data_type_->is_tuple();
  }

  bool is_user_type() const {
    if (!data_type_) return false;
    return data_type_->is_user_type();
  }

  int32_t count() const { return count_; }

  StringRef to_string_ref() const {
    if (is_null()) return StringRef();
    return decoder_.as_string_ref();
  }

  String to_string() const { return to_string_ref().to_string(); }

  bool as_bool() const;
  int32_t as_int32() const;
  CassUuid as_uuid() const;
  StringVec as_stringlist() const;

private:
  friend class Decoder;
  bool update(const Decoder& decoder);

private:
  DataType::ConstPtr data_type_;
  int32_t count_;
  Decoder decoder_;
  bool is_null_;
};

typedef Vector<Value> OutputValueVec;

}}} // namespace datastax::internal::core

EXTERNAL_TYPE(datastax::internal::core::Value, CassValue)

#endif

<MSG> Schema metadata refactor

<DFF> @@ -27,35 +27,40 @@ class Value {
 public:
   Value()
       : type_(CASS_VALUE_TYPE_UNKNOWN)
-      , def_(NULL)
+      , primary_type_(CASS_VALUE_TYPE_UNKNOWN)
+      , secondary_type_(CASS_VALUE_TYPE_UNKNOWN)
       , count_(0) {}
 
   Value(CassValueType type, char* data, size_t size)
       : type_(type)
-      , def_(NULL)
+      , primary_type_(CASS_VALUE_TYPE_UNKNOWN)
+      , secondary_type_(CASS_VALUE_TYPE_UNKNOWN)
       , count_(0)
       , buffer_(data, size) {}
 
-  Value(const ColumnDefinition* definition, int32_t count, char* data, size_t size)
-    : type_(static_cast<CassValueType>(definition->type))
-    , def_(definition)
+  Value(CassValueType type, CassValueType primary_type, CassValueType secondary_type,
+        int32_t count, char* data, size_t size)
+      : type_(type)
+      , primary_type_(primary_type)
+      , secondary_type_(secondary_type)
+      , count_(count)
+      , buffer_(data, size) {}
+
+  Value(const ColumnDefinition* def, int32_t count, char* data, size_t size)
+    : type_(static_cast<CassValueType>(def->type))
+    , primary_type_(static_cast<CassValueType>(def->collection_primary_type))
+    , secondary_type_(static_cast<CassValueType>(def->collection_secondary_type))
     , count_(count)
     , buffer_(data, size) {}
 
   CassValueType type() const { return type_; }
 
   CassValueType primary_type() const {
-    if (def_ == NULL) {
-      return CASS_VALUE_TYPE_UNKNOWN;
-    }
-    return static_cast<CassValueType>(def_->collection_primary_type);
+    return primary_type_;
   }
 
   CassValueType secondary_type() const {
-    if (def_ == NULL) {
-      return CASS_VALUE_TYPE_UNKNOWN;
-    }
-    return static_cast<CassValueType>(def_->collection_secondary_type);
+    return secondary_type_;
   }
 
   bool is_null() const {
@@ -75,7 +80,8 @@ public:
 
 private:
   CassValueType type_;
-  const ColumnDefinition* def_;
+  CassValueType primary_type_;
+  CassValueType secondary_type_;
   int32_t count_;
   BufferPiece buffer_;
 };

{'commit': 'diff --git a/examples/basic/basic.c b/examples/basic/basic.c\nindex fa4e47b9..b4862454 100644\n--- a/examples/basic/basic.c\n+++ b/examples/basic/basic.c\n@@ -36,7 +36,6 @@ void print_error(CassFuture* future) {\n   fprintf(stderr, "Error: %.*s\\n", (int)message.length, message.data);\n }\n \n-\n CassCluster* create_cluster() {\n   CassCluster* cluster = cass_cluster_new();\n   cass_cluster_set_contact_points(cluster, "127.0.0.1,127.0.0.2,127.0.0.3");\ndiff --git a/examples/schema_meta/schema_meta.c b/examples/schema_meta/schema_meta.c\nindex 94a1d113..02703572 100644\n--- a/examples/schema_meta/schema_meta.c\n+++ b/examples/schema_meta/schema_meta.c\n@@ -17,6 +17,63 @@\n #include <stdio.h>\n #include <cassandra.h>\n \n+void print_schema_meta(const CassSchemaMeta* meta, int indent);\n+\n+void print_keyspace(CassSession* session, const char* keyspace) {\n+  const CassSchema* schema = cass_session_get_schema(session);\n+  const CassSchemaMeta* keyspace_meta = cass_schema_get_keyspace(schema, keyspace);\n+\n+  if (keyspace_meta != NULL) {\n+    print_schema_meta(keyspace_meta, 0);\n+  } else {\n+    fprintf(stderr, "Unable to find \\"%s\\" keyspace in the schema metadata\\n", keyspace);\n+  }\n+\n+  cass_schema_free(schema);\n+}\n+\n+void print_table(CassSession* session, const char* keyspace, const char* table) {\n+  const CassSchema* schema = cass_session_get_schema(session);\n+  const CassSchemaMeta* keyspace_meta = cass_schema_get_keyspace(schema, keyspace);\n+\n+  if (keyspace_meta != NULL) {\n+    const CassSchemaMeta* table_meta = cass_schema_meta_get_entry(keyspace_meta, table);\n+    if (table_meta != NULL) {\n+      print_schema_meta(table_meta, 0);\n+    } else {\n+      fprintf(stderr, "Unable to find \\"%s\\" table in the schema metadata\\n", table);\n+    }\n+  } else {\n+    fprintf(stderr, "Unable to find \\"%s\\" keyspace in the schema metadata\\n", keyspace);\n+  }\n+\n+  cass_schema_free(schema);\n+}\n+\n+void print_error(CassFuture* future) {\n+  CassString message = cass_future_error_message(future);\n+  fprintf(stderr, "Error: %.*s\\n", (int)message.length, message.data);\n+}\n+\n+CassError execute_query(CassSession* session, const char* query) {\n+  CassError rc = CASS_OK;\n+  CassFuture* future = NULL;\n+  CassStatement* statement = cass_statement_new(cass_string_init(query), 0);\n+\n+  future = cass_session_execute(session, statement);\n+  cass_future_wait(future);\n+\n+  rc = cass_future_error_code(future);\n+  if(rc != CASS_OK) {\n+    print_error(future);\n+  }\n+\n+  cass_future_free(future);\n+  cass_statement_free(statement);\n+\n+  return rc;\n+}\n+\n int main() {\n   CassFuture* connect_future = NULL;\n   CassCluster* cluster = cass_cluster_new();\n@@ -28,77 +85,28 @@ int main() {\n     CassFuture* close_future = NULL;\n     CassSession* session = cass_future_get_session(connect_future);\n \n-    {\n-      CassSchemaMetadata* schema = cass_session_get_schema_meta(session);\n-      CassKeyspaceMeta ks_meta;\n-      CassColumnFamilyMeta cf_meta;\n-      CassColumnMeta col_meta;\n-      printf("Known entities:\\n============\\n");\n-      if (cass_meta_get_keyspace2(schema, "system_traces", &ks_meta) == CASS_OK) {\n-        printf("keyspace: %.*s\\n", (int)ks_meta.name.length, ks_meta.name.data);\n-        printf("  replication strategy: %.*s\\n", (int)ks_meta.replication_strategy.length, ks_meta.replication_strategy.data);\n-        printf("      strategy options: %.*s\\n", (int)ks_meta.strategy_options.length, ks_meta.strategy_options.data);\n-        printf("  durable writes: %s\\n", ks_meta.durable_writes?"true":"false");\n-      }\n+    execute_query(session,\n+                  "CREATE KEYSPACE examples WITH replication = { \\\n+                  \'class\': \'SimpleStrategy\', \'replication_factor\': \'3\' };");\n \n-      if (cass_meta_get_column_family2(schema, "system_traces", "sessions", &cf_meta) == CASS_OK) {\n-        printf("column family: %.*s\\n", (int)cf_meta.name.length, cf_meta.name.data);\n-        printf("  comment: %.*s\\n", (int)cf_meta.comment.length, cf_meta.comment.data);\n-      }\n+    print_keyspace(session, "examples");\n \n-      if (cass_meta_get_column2(schema, "system_traces", "events", "event_id", &col_meta) == CASS_OK) {\n-        printf("column: %.*s\\n", (int)col_meta.name.length, col_meta.name.data);\n-        printf("  validator: %.*s\\n", (int)col_meta.validator.length, col_meta.validator.data);\n-      }\n-      cass_meta_free(schema);\n-    }\n+    execute_query(session,\n+                  "CREATE TABLE examples.schema_meta (key text, \\\n+                  value bigint, \\\n+                  PRIMARY KEY (key));");\n \n-    {\n-      CassKeyspaceMeta ks_meta;\n-      CassColumnFamilyMeta cf_meta;\n-      CassColumnMeta col_meta;\n-      CassSchemaMetadata* schema_meta = cass_session_get_schema_meta(session);\n-      CassIterator* ks_itr = cass_iterator_keyspaces(schema_meta);\n-      CassIterator* cf_itr;\n-      CassIterator* col_itr;\n-      printf("\\nIterators:\\n============\\n");\n-      while (cass_iterator_next(ks_itr)) {\n-        cass_iterator_get_keyspace_meta(ks_itr, &ks_meta);\n-        printf("keyspace: %.*s\\n", (int)ks_meta.name.length, ks_meta.name.data);\n-        printf("  replication strategy: %.*s\\n", (int)ks_meta.replication_strategy.length, ks_meta.replication_strategy.data);\n-        printf("      strategy options: %.*s\\n", (int)ks_meta.strategy_options.length, ks_meta.strategy_options.data);\n-        printf("  durable writes: %s\\n", ks_meta.durable_writes?"true":"false");\n-        printf("  column families:\\n");\n-        cf_itr = cass_iterator_column_families_from_keyspace(ks_itr);\n-        while (cass_iterator_next(cf_itr)) {\n-          cass_iterator_get_column_family_meta(cf_itr, &cf_meta);\n-          printf("      column family: %.*s: \\"%.*s\\"\\n",\n-                 (int)cf_meta.name.length, cf_meta.name.data,\n-                 (int)cf_meta.comment.length, cf_meta.comment.data);\n-          col_itr = cass_iterator_columns_from_column_family(cf_itr);\n-          while (cass_iterator_next(col_itr)) {\n-            cass_iterator_get_column_meta(col_itr, &col_meta);\n-            printf("        column: %.*s (%.*s)\\n",\n-                   (int)col_meta.name.length, col_meta.name.data,\n-                   (int)col_meta.validator.length, col_meta.validator.data);\n-          }\n-          cass_iterator_free(col_itr);\n-        }\n-        cass_iterator_free(cf_itr);\n-      }\n-      cass_iterator_free(ks_itr);\n-      cass_meta_free(schema_meta);\n-    }\n+    print_table(session, "examples", "schema_meta");\n \n     /* Close the session */\n     close_future = cass_session_close(session);\n     cass_future_wait(close_future);\n     cass_future_free(close_future);\n   } else {\n-      /* Handle error */\n-      CassString message = cass_future_error_message(connect_future);\n-      fprintf(stderr, "Unable to connect: \'%.*s\'\\n", (int)message.length, \n-                                                          message.data);\n+    /* Handle error */\n+    CassString message = cass_future_error_message(connect_future);\n+    fprintf(stderr, "Unable to connect: \'%.*s\'\\n", (int)message.length,\n+            message.data);\n   }\n \n   cass_future_free(connect_future);\n@@ -106,3 +114,161 @@ int main() {\n \n   return 0;\n }\n+\n+void print_schema_value(const CassValue* value);\n+void print_schema_list(const CassValue* value);\n+void print_schema_map(const CassValue* value);\n+void print_schema_meta_field(const CassSchemaMetaField* field, int indent);\n+void print_schema_meta_fields(const CassSchemaMeta* meta, int indent);\n+void print_schema_meta_entries(const CassSchemaMeta* meta, int indent);\n+\n+void print_indent(int indent) {\n+  int i;\n+  for (i = 0; i < indent; ++i) {\n+    printf("\\t");\n+  }\n+}\n+\n+void print_schema_value(const CassValue* value) {\n+  cass_int32_t i;\n+  cass_bool_t b;\n+  cass_double_t d;\n+  CassString s;\n+  CassUuid u;\n+  char us[CASS_UUID_STRING_LENGTH];\n+\n+  CassValueType type = cass_value_type(value);\n+  switch (type) {\n+    case CASS_VALUE_TYPE_INT:\n+      cass_value_get_int32(value, &i);\n+      printf("%d", i);\n+      break;\n+\n+    case CASS_VALUE_TYPE_BOOLEAN:\n+      cass_value_get_bool(value, &b);\n+      printf("%s", b ? "true" : "false");\n+      break;\n+\n+    case CASS_VALUE_TYPE_DOUBLE:\n+      cass_value_get_double(value, &d);\n+      printf("%f", d);\n+      break;\n+\n+    case CASS_VALUE_TYPE_TEXT:\n+    case CASS_VALUE_TYPE_ASCII:\n+    case CASS_VALUE_TYPE_VARCHAR:\n+      cass_value_get_string(value, &s);\n+      printf("\\"%.*s\\"", (int)s.length, s.data);\n+      break;\n+\n+    case CASS_VALUE_TYPE_UUID:\n+      cass_value_get_uuid(value, u);\n+      cass_uuid_string(u, us);\n+      printf("%s", us);\n+      break;\n+\n+    case CASS_VALUE_TYPE_LIST:\n+      print_schema_list(value);\n+      break;\n+\n+    case CASS_VALUE_TYPE_MAP:\n+      print_schema_map(value);\n+      break;\n+\n+    default:\n+      if (cass_value_is_null(value)) {\n+        printf("null");\n+      } else {\n+        printf("<unhandled type>");\n+      }\n+      break;\n+  }\n+}\n+\n+void print_schema_list(const CassValue* value) {\n+  CassIterator* iterator = cass_iterator_from_collection(value);\n+  cass_bool_t is_first = cass_true;\n+\n+  printf("[ ");\n+  while (cass_iterator_next(iterator)) {\n+    if (!is_first) printf(", ");\n+    print_schema_value(cass_iterator_get_value(iterator));\n+    is_first = cass_false;\n+  }\n+  printf(" ]");\n+}\n+\n+void print_schema_map(const CassValue* value) {\n+  CassIterator* iterator = cass_iterator_from_map(value);\n+  cass_bool_t is_first = cass_true;\n+\n+  printf("{ ");\n+  while (cass_iterator_next(iterator)) {\n+    if (!is_first) printf(", ");\n+    print_schema_value(cass_iterator_get_map_key(iterator));\n+    printf(" : ");\n+    print_schema_value(cass_iterator_get_map_value(iterator));\n+    is_first = cass_false;\n+  }\n+  printf(" }");\n+}\n+\n+void print_schema_meta_field(const CassSchemaMetaField* field, int indent) {\n+  CassString name = cass_schema_meta_field_name(field);\n+  const CassValue* value = cass_schema_meta_field_value(field);\n+\n+  print_indent(indent);\n+  printf("%.*s: ", (int)name.length, name.data);\n+  print_schema_value(value);\n+  printf("\\n");\n+}\n+\n+void print_schema_meta_fields(const CassSchemaMeta* meta, int indent) {\n+  CassIterator* fields = cass_iterator_fields_from_schema_meta(meta);\n+\n+  while (cass_iterator_next(fields)) {\n+    print_schema_meta_field(cass_iterator_get_schema_meta_field(fields), indent);\n+  }\n+}\n+\n+void print_schema_meta_entries(const CassSchemaMeta* meta, int indent) {\n+  CassIterator* entries = cass_iterator_from_schema_meta(meta);\n+\n+  while (cass_iterator_next(entries)) {\n+    print_schema_meta(cass_iterator_get_schema_meta(entries), indent);\n+  }\n+}\n+\n+void print_schema_meta(const CassSchemaMeta* meta, int indent) {\n+  const CassSchemaMetaField* field = NULL;\n+  CassString name;\n+  print_indent(indent);\n+\n+  switch (cass_schema_meta_type(meta)) {\n+    case CASS_SCHEMA_META_TYPE_KEYSPACE:\n+      field = cass_schema_meta_get_field(meta, "keyspace_name");\n+      cass_value_get_string(cass_schema_meta_field_value(field), &name);\n+      printf("Keyspace \\"%.*s\\":\\n", (int)name.length, name.data);\n+      print_schema_meta_fields(meta, indent + 1);\n+      printf("\\n");\n+      print_schema_meta_entries(meta, indent + 1);\n+      break;\n+\n+    case CASS_SCHEMA_META_TYPE_TABLE:\n+      field = cass_schema_meta_get_field(meta, "columnfamily_name");\n+      cass_value_get_string(cass_schema_meta_field_value(field), &name);\n+      printf("Table \\"%.*s\\":\\n", (int)name.length, name.data);\n+      print_schema_meta_fields(meta, indent + 1);\n+      printf("\\n");\n+      print_schema_meta_entries(meta, indent + 1);\n+      break;\n+\n+    case CASS_SCHEMA_META_TYPE_COLUMN:\n+      field = cass_schema_meta_get_field(meta, "column_name");\n+      cass_value_get_string(cass_schema_meta_field_value(field), &name);\n+      printf("Column \\"%.*s\\":\\n", (int)name.length, name.data);\n+      print_schema_meta_fields(meta, indent + 1);\n+      printf("\\n");\n+      break;\n+  }\n+}\ndiff --git a/include/cassandra.h b/include/cassandra.h\nindex 2c0d82fd..a2a0f1eb 100644\n--- a/include/cassandra.h\n+++ b/include/cassandra.h\n@@ -139,7 +139,9 @@ typedef struct CassIterator_ CassIterator;\n typedef struct CassRow_ CassRow;\n typedef struct CassValue_ CassValue;\n typedef struct CassCollection_ CassCollection;\n-typedef struct CassSchemaMetadata_ CassSchemaMetadata;\n+typedef struct CassSchema_ CassSchema;\n+typedef struct CassSchemaMeta_ CassSchemaMeta;\n+typedef struct CassSchemaMetaField_ CassSchemaMetaField;\n \n typedef enum CassConsistency_ {\n   CASS_CONSISTENCY_ANY          = 0x0000,\n@@ -206,6 +208,21 @@ typedef enum CassColumnType_ {\n   CASS_COLUMN_TYPE_UNKNOWN\n } CassColumnType;\n \n+typedef enum CassIteratorType_ {\n+  CASS_ITERATOR_TYPE_RESULT,\n+  CASS_ITERATOR_TYPE_ROW,\n+  CASS_ITERATOR_TYPE_COLLECTION,\n+  CASS_ITERATOR_TYPE_MAP,\n+  CASS_ITERATOR_TYPE_SCHEMA_META,\n+  CASS_ITERATOR_TYPE_SCHEMA_META_FIELD\n+} CassIteratorType;\n+\n+typedef enum CassSchemaMetaType_ {\n+  CASS_SCHEMA_META_TYPE_KEYSPACE,\n+  CASS_SCHEMA_META_TYPE_TABLE,\n+  CASS_SCHEMA_META_TYPE_COLUMN\n+} CassSchemaMetaType;\n+\n #define CASS_LOG_LEVEL_MAP(XX) \\\n   XX(CASS_LOG_DISABLED, "") \\\n   XX(CASS_LOG_CRITICAL, "CRITICAL") \\\n@@ -786,191 +803,105 @@ CASS_EXPORT CassFuture*\n cass_session_execute_batch(CassSession* session,\n                            const CassBatch* batch);\n \n-/***********************************************************************************\n- *\n- * Schema metadata\n- *\n- ***********************************************************************************/\n-\n /**\n- * Get the current schema metadata model\n+ * Gets a copy of this session\'s schema metadata. The returned\n+ * copy of the schema metadata is not updated. This function\n+ * must be called again to retrieve any schema changes since the\n+ * previous call.\n  *\n  * @param[in] session\n- * @return A schema metadata model that must be freed\n+ * @return A schema instance that must be freed.\n  *\n- * @see cass_schema_meta_free()\n+ * @see cass_schema_free()\n  */\n-CASS_EXPORT CassSchemaMetadata*\n-cass_session_get_schema_meta(CassSession* session);\n+CASS_EXPORT const CassSchema*\n+cass_session_get_schema(CassSession* session);\n \n-/**\n- * Get metadata for a known keyspace\n+/***********************************************************************************\n  *\n- * @param[in] schema_meta\n- * @param[in] keyspace_name\n- * @param[out] output\n- * @return CASS_OK if keyspace is found, otherwise error\n- */\n-CASS_EXPORT CassError\n-cass_meta_get_keyspace(CassSchemaMetadata* schema_meta,\n-                       CassString keyspace_name,\n-                       CassKeyspaceMeta* output);\n-CASS_EXPORT CassError\n-cass_meta_get_keyspace2(CassSchemaMetadata* schema_meta,\n-                        const char* keyspace_name,\n-                        CassKeyspaceMeta* output);\n-\n-/**\n- * Get metadata for a known column family\n+ * Schema metadata\n  *\n- * @param[in] schema_meta\n- * @param[in] keyspace_name\n- * @param[in] column_family_name\n- * @param[out] output\n- * @return CASS_OK if column family is found, otherwise error\n- */\n-CASS_EXPORT CassError\n-cass_meta_get_column_family(CassSchemaMetadata* schema_meta,\n-                            CassString keyspace_name,\n-                            CassString column_family_name,\n-                            CassColumnFamilyMeta* output);\n-CASS_EXPORT CassError\n-cass_meta_get_column_family2(CassSchemaMetadata* schema_meta,\n-                             const char* keyspace_name,\n-                             const char* column_family_name,\n-                             CassColumnFamilyMeta* output);\n+ ***********************************************************************************/\n \n /**\n- * Get metadata for a known column\n+ * Gets a the metadata for the provided keyspace name.\n  *\n- * @param[in] schema_meta\n+ * @param[in] schema\n  * @param[in] keyspace_name\n- * @param[in] column_family_name\n- * @param[in] column_name\n- * @param[out] output\n- * @return CASS_OK if column is found, otherwise error\n- */\n-CASS_EXPORT CassError\n-cass_meta_get_column(CassSchemaMetadata* schema_meta,\n-                     CassString keyspace_name,\n-                     CassString column_family_name,\n-                     CassString column_name,\n-                     CassColumnMeta* output);\n-CASS_EXPORT CassError\n-cass_meta_get_column2(CassSchemaMetadata* schema_meta,\n-                      const char* keyspace_name,\n-                      const char* column_family_name,\n-                      const char* column_name,\n-                      CassColumnMeta* output);\n-\n-/**\n- * Frees a schema metadata object created by cass_session_get_schema_meta\n+ * @return The schema metadata for a keyspace. NULL if keyspace does not exist.\n  *\n- * @param[in] schema_meta\n+ * @see cass_schema_meta_get_entry()\n+ * @see cass_schema_meta_get_field()\n+ * @see cass_schema_meta_type()\n+ * @see cass_iterator_from_schema_meta()\n  */\n-CASS_EXPORT void\n-cass_meta_free(CassSchemaMetadata* meta);\n+CASS_EXPORT const CassSchemaMeta*\n+cass_schema_get_keyspace(const CassSchema* schema, const char* keyspace_name);\n \n /**\n- * Create an iterator over keyspaces in schema metadata\n- *\n- * @param[in] schema_meta\n- * @return A new iterator that must be freed.\n+ * Gets the type of the specified schema metadata.\n  *\n- * @see cass_iterator_free()\n+ * @param[in] meta\n+ * @return The type of the schema metadata\n  */\n-CASS_EXPORT CassIterator*\n-cass_iterator_keyspaces(CassSchemaMetadata* schema_meta);\n+CASS_EXPORT CassSchemaMetaType\n+cass_schema_meta_type(const CassSchemaMeta* meta);\n \n /**\n- * Get metadata for the iterator keyspace\n+ * Gets a metadata entry for the provided table/column name.\n  *\n- * @param[in] ks_itr\n- * @param[out] output\n- * @return CASS_OK\n- */\n-CASS_EXPORT CassError\n-cass_iterator_get_keyspace_meta(CassIterator* ks_itr,\n-                                CassKeyspaceMeta* output);\n-\n-/**\n- * Create an iterator over column families in the iterator keyspace\n+ * @param[in] meta\n+ * @param[in] name The name of a table or column\n+ * @return The schema metadata for a table/column. NULL if table/column does not exist.\n  *\n- * @param[in] ks_itr\n- * @return A new iterator that must be freed.\n- *\n- * @see cass_iterator_free()\n+ * @see cass_schema_meta_get_entry()\n+ * @see cass_schema_meta_get_field()\n+ * @see cass_schema_meta_type()\n+ * @see cass_iterator_from_schema_meta()\n+ * @see cass_iterator_fields_from_schema_meta()\n  */\n-CASS_EXPORT CassIterator*\n-cass_iterator_column_families_from_keyspace(CassIterator* ks_itr);\n+CASS_EXPORT const CassSchemaMeta*\n+cass_schema_meta_get_entry(const CassSchemaMeta* meta, const char* name);\n \n /**\n- * Create an iterator over column families in the specified keyspace\n+ * Gets a metadata field for the provided name.\n  *\n- * @param[in] schema_meta\n- * @param[in] keyspace_name\n- * @return A new iterator that must be freed. (NULL if keyspace does not exist)\n+ * @param[in] meta\n+ * @param[in] name The name of a field\n+ * @return A schema metadata field. NULL if the field does not exist.\n  *\n- * @see cass_iterator_free()\n+ * @see cass_schema_meta_field_name()\n+ * @see cass_schema_meta_field_value()\n  */\n-CASS_EXPORT CassIterator*\n-cass_iterator_column_families(CassSchemaMetadata* schema_meta,\n-                              CassString keyspace_name);\n-CASS_EXPORT CassIterator*\n-cass_iterator_column_families2(CassSchemaMetadata* schema_meta,\n-                               const char* keyspace_name);\n+CASS_EXPORT const CassSchemaMetaField*\n+cass_schema_meta_get_field(const CassSchemaMeta* meta, const char* name);\n \n /**\n- * Get metadata for the iterator column family\n+ * Gets the name for a schema metadata field\n  *\n- * @param[in] cf_itr\n- * @param[out] output\n- * @return CASS_OK\n+ * @param[in] field\n+ * @return The name of the metdata data field\n  */\n-CASS_EXPORT CassError\n-cass_iterator_get_column_family_meta(CassIterator* cf_itr,\n-                                     CassColumnFamilyMeta* output);\n+CASS_EXPORT CassString\n+cass_schema_meta_field_name(const CassSchemaMetaField* field);\n \n /**\n- * Create an iterator over columns in the specified keyspace/column family\n- *\n- * @param[in] schema_meta\n- * @param[in] keyspace_name\n- * @param[in] column_family_name\n- * @return A new iterator that must be freed. (NULL if column family does not exist)\n+ * Gets the value for a schema metadata field\n  *\n- * @see cass_iterator_free()\n+ * @param[in] field\n+ * @return The value of the metdata data field\n  */\n-CASS_EXPORT CassIterator*\n-cass_iterator_columns(CassSchemaMetadata* schema_meta,\n-                      CassString keyspace_name,\n-                      CassString column_family_name);\n-CASS_EXPORT CassIterator*\n-cass_iterator_column2(CassSchemaMetadata* schema_meta,\n-                      const char* keyspace_name,\n-                      const char* column_family_name);\n+CASS_EXPORT const CassValue*\n+cass_schema_meta_field_value(const CassSchemaMetaField* field);\n \n /**\n- * Create an iterator over columns in the iterator column family\n+ * Frees a schema instance.\n  *\n- * @param[in] cf_itr\n- * @return A new iterator that must be freed.\n- *\n- * @see cass_iterator_free()\n+ * @param[in] schema\n  */\n-CASS_EXPORT CassIterator*\n-cass_iterator_columns_from_column_family(CassIterator* cf_itr);\n+CASS_EXPORT void\n+cass_schema_free(const CassSchema* schema);\n \n-/**\n- * Get metadata for the iterator keyspace\n- *\n- * @param[in] col_itr\n- * @param[out] output\n- * @return CASS_OK\n- */\n-CASS_EXPORT CassError\n-cass_iterator_get_column_meta(CassIterator* col_itr,\n-                              CassColumnMeta* output);\n \n /***********************************************************************************\n  *\n@@ -1848,6 +1779,15 @@ cass_result_has_more_pages(const CassResult* result);\n  *\n  ***********************************************************************************/\n \n+/**\n+ * Gets the type of the specified iterator.\n+ *\n+ * @param[in] iterator\n+ * @return The type of the iterator.\n+ */\n+CASS_EXPORT CassIteratorType\n+cass_iterator_type(CassIterator* iterator);\n+\n /**\n  * Creates a new iterator for the specified result. This can be\n  * used to iterate over rows in the result.\n@@ -1898,6 +1838,45 @@ cass_iterator_from_collection(const CassValue* value);\n CASS_EXPORT CassIterator*\n cass_iterator_from_map(const CassValue* value);\n \n+/**\n+ * Creates a new iterator for the specified schema.\n+ * This can be used to iterate over keyspace entries.\n+ *\n+ * @param[in] schema\n+ * @return A new iterator that must be freed.\n+ *\n+ * @see cass_iterator_get_schema_meta()\n+ * @see cass_iterator_free()\n+ */\n+CASS_EXPORT CassIterator*\n+cass_iterator_from_schema(const CassSchema* schema);\n+\n+/**\n+ * Creates a new iterator for the specified schema metadata.\n+ * This can be used to iterate over table/column entries.\n+ *\n+ * @param[in] meta\n+ * @return A new iterator that must be freed.\n+ *\n+ * @see cass_iterator_get_schema_meta()\n+ * @see cass_iterator_free()\n+ */\n+CASS_EXPORT CassIterator*\n+cass_iterator_from_schema_meta(const CassSchemaMeta* meta);\n+\n+/**\n+ * Creates a new iterator for the specified schema metadata.\n+ * This can be used to iterate over schema metadata fields.\n+ *\n+ * @param[in] meta\n+ * @return A new iterator that must be freed.\n+ *\n+ * @see cass_iterator_get_schema_meta_field()\n+ * @see cass_iterator_free()\n+ */\n+CASS_EXPORT CassIterator*\n+cass_iterator_fields_from_schema_meta(const CassSchemaMeta* meta);\n+\n /**\n  * Frees an iterator instance.\n  *\n@@ -1988,6 +1967,34 @@ cass_iterator_get_map_key(CassIterator* iterator);\n CASS_EXPORT const CassValue*\n cass_iterator_get_map_value(CassIterator* iterator);\n \n+/**\n+ * Gets the schema metadata entry at the iterator\'s current\n+ * position.\n+ *\n+ * Calling cass_iterator_next() will invalidate the previous\n+ * value returned by this method.\n+ *\n+ * @param[in] iterator\n+ * @return A keyspace/table/column schema metadata entry\n+ */\n+CASS_EXPORT const CassSchemaMeta*\n+cass_iterator_get_schema_meta(CassIterator* iterator);\n+\n+/**\n+ * Gets the schema metadata field at the iterator\'s current\n+ * position.\n+ *\n+ * Calling cass_iterator_next() will invalidate the previous\n+ * value returned by this method.\n+ *\n+ * @param[in] iterator\n+ * @return A schema metadata field\n+ */\n+CASS_EXPORT const CassSchemaMetaField*\n+cass_iterator_get_schema_meta_field(CassIterator* iterator);\n+\n+\n+\n \n /***********************************************************************************\n  *\ndiff --git a/src/buffer.cpp b/src/buffer.cpp\nindex cb2b8aa3..1198b303 100644\n--- a/src/buffer.cpp\n+++ b/src/buffer.cpp\n@@ -28,7 +28,7 @@ Buffer::Buffer(const BufferCollection* collection)\n \n Buffer::~Buffer() {\n   if (size_ > FIXED_BUFFER_SIZE) {\n-    data_.ref.array->dec_ref();\n+    data_.ref.buffer->dec_ref();\n   } else if (size_ == IS_COLLECTION) {\n     data_.ref.collection->dec_ref();\n   }\n@@ -43,8 +43,8 @@ void Buffer::copy(const Buffer& buffer) {\n   BufferRef temp = data_.ref;\n \n   if (buffer.size_ > FIXED_BUFFER_SIZE) {\n-    buffer.data_.ref.array->inc_ref();\n-    data_.ref.array = buffer.data_.ref.array;\n+    buffer.data_.ref.buffer->inc_ref();\n+    data_.ref.buffer = buffer.data_.ref.buffer;\n   } else if (buffer.size_ == IS_COLLECTION) {\n     buffer.data_.ref.collection->inc_ref();\n     data_.ref.collection = buffer.data_.ref.collection;\n@@ -53,7 +53,7 @@ void Buffer::copy(const Buffer& buffer) {\n   }\n \n   if (size_ > FIXED_BUFFER_SIZE) {\n-    temp.array->dec_ref();\n+    temp.buffer->dec_ref();\n   } else if (size_ == IS_COLLECTION) {\n     temp.collection->dec_ref();\n   }\ndiff --git a/src/buffer.hpp b/src/buffer.hpp\nindex 16736e7a..cbfe0195 100644\n--- a/src/buffer.hpp\n+++ b/src/buffer.hpp\n@@ -26,22 +26,6 @@\n \n namespace cass {\n \n-class BufferArray : public RefCounted<BufferArray> {\n-public:\n-  BufferArray(size_t size)\n-    : data_(new char[size]) {}\n-\n-  virtual ~BufferArray() {\n-    delete[] data_;\n-  }\n-\n-  const char* data() const { return data_; }\n-  char* data() { return data_; }\n-\n-private:\n-  char* data_;\n-};\n-\n class BufferCollection;\n \n class Buffer {\n@@ -52,10 +36,10 @@ public:\n   Buffer(const char* data, size_t size)\n     : size_(size) {\n     if (size > static_cast<size_t>(FIXED_BUFFER_SIZE)) {\n-      BufferArray* array = new BufferArray(size);\n-      array->inc_ref();\n-      memcpy(array->data(), data, size);\n-      data_.ref.array = array;\n+      RefBuffer* buffer = RefBuffer::create(size);\n+      buffer->inc_ref();\n+      memcpy(buffer->data(), data, size);\n+      data_.ref.buffer = buffer;\n     } else {\n       memcpy(data_.fixed, data, size);\n     }\n@@ -65,9 +49,9 @@ public:\n   Buffer(size_t size)\n     : size_(size) {\n     if (size > static_cast<size_t>(FIXED_BUFFER_SIZE)) {\n-      BufferArray* array = new BufferArray(size);\n-      array->inc_ref();\n-      data_.ref.array = array;\n+      RefBuffer* buffer = RefBuffer::create(size);\n+      buffer->inc_ref();\n+      data_.ref.buffer = buffer;\n     }\n   }\n \n@@ -172,9 +156,14 @@ public:\n     return copy(offset, reinterpret_cast<const char*>(source), size);\n   }\n \n+  char* data() {\n+    assert(is_buffer());\n+    return size_ > FIXED_BUFFER_SIZE ? static_cast<RefBuffer*>(data_.ref.buffer)->data() : data_.fixed;\n+  }\n+\n   const char* data() const {\n     assert(is_buffer());\n-    return size_ > FIXED_BUFFER_SIZE ? static_cast<BufferArray*>(data_.ref.array)->data() : data_.fixed;\n+    return size_ > FIXED_BUFFER_SIZE ? static_cast<RefBuffer*>(data_.ref.buffer)->data() : data_.fixed;\n   }\n \n   int size() const { return size_; }\n@@ -196,7 +185,7 @@ private:\n   char* buffer() {\n     assert(is_buffer());\n     return size_ > FIXED_BUFFER_SIZE\n-        ? static_cast<BufferArray*>(data_.ref.array)->data()\n+        ? static_cast<RefBuffer*>(data_.ref.buffer)->data()\n         : data_.fixed;\n   }\n \n@@ -207,7 +196,7 @@ private:\n   void copy(const Buffer& buffer);\n \n   union BufferRef {\n-    BufferArray* array;\n+    RefBuffer* buffer;\n     const BufferCollection* collection;\n   };\n \ndiff --git a/src/buffer_collection.cpp b/src/buffer_collection.cpp\nindex 79fa9028..80ea032d 100644\n--- a/src/buffer_collection.cpp\n+++ b/src/buffer_collection.cpp\n@@ -99,30 +99,43 @@ namespace cass {\n int BufferCollection::encode(int version, BufferVec* bufs) const {\n   if (version != 1 && version != 2) return -1;\n \n-  int value_size = sizeof(uint16_t);\n+  int buf_size = sizeof(int32_t) + sizeof(uint16_t) + calculate_size(version);\n \n-  for (BufferVec::const_iterator it = bufs_.begin(),\n-      end = bufs_.end(); it != end; ++it) {\n-    value_size += sizeof(uint16_t);\n-    value_size += it->size();\n-  }\n+  Buffer buf(buf_size);\n \n-  int buf_size = sizeof(int32_t) + value_size;\n+  int pos = 0;\n+  pos = buf.encode_int32(pos, buf_size);\n+  pos = buf.encode_uint16(pos, is_map_ ? bufs_.size() / 2 : bufs_.size());\n \n-  Buffer buf(buf_size);\n+  encode(version, buf.data() + pos);\n \n-  size_t pos = buf.encode_int32(0, value_size);\n+  bufs->push_back(buf);\n \n-  pos = buf.encode_uint16(pos, is_map_ ? bufs_.size() / 2 : bufs_.size());\n+  return buf_size;\n+}\n+\n+int BufferCollection::calculate_size(int version) const {\n+  if (version != 1 && version != 2) return -1;\n+  int value_size = 0;\n   for (BufferVec::const_iterator it = bufs_.begin(),\n       end = bufs_.end(); it != end; ++it) {\n-    pos = buf.encode_uint16(pos, it->size());\n-    pos = buf.copy(pos, it->data(), it->size());\n+    value_size += sizeof(uint16_t);\n+    value_size += it->size();\n   }\n+  return value_size;\n+}\n \n-  bufs->push_back(buf);\n+void BufferCollection::encode(int version, char* buf) const {\n+  assert(version == 1 || version == 2);\n+  char* pos = buf;\n+  for (BufferVec::const_iterator it = bufs_.begin(),\n+      end = bufs_.end(); it != end; ++it) {\n+    encode_uint16(pos, it->size());\n+    pos += sizeof(uint16_t);\n \n-  return buf_size;\n+    memcpy(pos, it->data(), it->size());\n+    pos += it->size();\n+  }\n }\n \n }\ndiff --git a/src/buffer_collection.hpp b/src/buffer_collection.hpp\nindex 54ab80f6..51d101da 100644\n--- a/src/buffer_collection.hpp\n+++ b/src/buffer_collection.hpp\n@@ -72,8 +72,11 @@ public:\n   size_t item_count() const { return bufs_.size(); }\n \n   int encode(int version, BufferVec* bufs) const;\n+  int calculate_size(int version) const;\n+  void encode(int version, char* buf) const;\n \n private:\n+\n   BufferVec bufs_;\n   bool is_map_;\n };\ndiff --git a/src/collection_iterator.hpp b/src/collection_iterator.hpp\nindex e99627ec..4820b7b4 100644\n--- a/src/collection_iterator.hpp\n+++ b/src/collection_iterator.hpp\n@@ -27,7 +27,7 @@ namespace cass {\n class CollectionIterator : public Iterator {\n public:\n   CollectionIterator(const Value* collection)\n-      : Iterator(CASS_ITERATOR_COLLECTION)\n+      : Iterator(CASS_ITERATOR_TYPE_COLLECTION)\n       , collection_(collection)\n       , position_(collection->buffer().data())\n       , index_(-1)\ndiff --git a/src/common.cpp b/src/common.cpp\nindex 6aaa66e4..94c540d1 100644\n--- a/src/common.cpp\n+++ b/src/common.cpp\n@@ -19,8 +19,6 @@\n #include "buffer_piece.hpp"\n #include "constants.hpp"\n \n-#include <rapidjson/document.h>\n-\n #include <algorithm>\n #include <assert.h>\n \n@@ -92,38 +90,4 @@ std::string& trim(std::string& str) {\n   return str;\n }\n \n-void json_to_list(const BufferPiece& alias_json, std::list<std::string>* output) {\n-  char* buffer = new char[alias_json.size() + 1];\n-  memcpy(buffer, alias_json.data(), alias_json.size());\n-  buffer[alias_json.size()] = \'\\0\';\n-\n-  rapidjson::Document d;\n-  d.ParseInsitu(buffer);\n-  if (!d.HasParseError()) {\n-    for (rapidjson::Value::ConstValueIterator i = d.Begin(); i != d.End(); ++i) {\n-      output->push_back(i->GetString());\n-    }\n-  } else {\n-    //TODO: log to global logging\n-  }\n-  delete[] buffer;\n-}\n-\n-void json_to_map(const BufferPiece& json_buffer, std::map<std::string, std::string>* output) {\n-  char* buffer = new char[json_buffer.size() + 1];\n-  memcpy(buffer, json_buffer.data(), json_buffer.size());\n-  buffer[json_buffer.size()] = \'\\0\';\n-\n-  rapidjson::Document d;\n-  d.ParseInsitu(buffer);\n-  if (!d.HasParseError()) {\n-    for (rapidjson::Value::ConstMemberIterator i = d.MemberBegin(); i != d.MemberEnd(); ++i) {\n-      (*output)[i->name.GetString()] = i->value.GetString();\n-    }\n-  } else {\n-    //TODO: log to global logging\n-  }\n-  delete[] buffer;\n-}\n-\n } // namespace cass\ndiff --git a/src/common.hpp b/src/common.hpp\nindex bd35966a..f72753c2 100644\n--- a/src/common.hpp\n+++ b/src/common.hpp\n@@ -64,9 +64,6 @@ std::string opcode_to_string(int opcode);\n \n std::string& trim(std::string& str);\n \n-void json_to_list(const BufferPiece& alias_json, std::list<std::string>* output);\n-void json_to_map(const BufferPiece& json_buffer, std::map<std::string, std::string>* output);\n-\n } // namespace cass\n \n #endif\ndiff --git a/src/connection.cpp b/src/connection.cpp\nindex 8860b146..6e54be9b 100644\n--- a/src/connection.cpp\n+++ b/src/connection.cpp\n@@ -572,9 +572,9 @@ void Connection::PendingWriteBuffer::flush() {\n     uv_bufs_.clear();\n     uv_bufs_.reserve(buffers_.size());\n \n-    for (BufferVec::const_iterator it = buffers_.begin(),\n+    for (BufferVec::iterator it = buffers_.begin(),\n          end = buffers_.end(); it != end; ++it) {\n-      uv_bufs_.push_back(uv_buf_init(const_cast<char*>(it->data()), it->size()));\n+      uv_bufs_.push_back(uv_buf_init(it->data(), it->size()));\n     }\n \n     is_flushed_ = true;\ndiff --git a/src/control_connection.cpp b/src/control_connection.cpp\nindex 659b711b..390f8377 100644\n--- a/src/control_connection.cpp\n+++ b/src/control_connection.cpp\n@@ -172,6 +172,9 @@ void ControlConnection::on_connection_ready(Connection* connection) {\n   logger_->debug("ControlConnection: Connection ready on host %s",\n                  connection->address().to_string().c_str());\n \n+  // A protocol version is need to encode/decode maps properly\n+  session_->schema().set_protocol_version(protocol_version_);\n+\n   // The control connection has to refresh meta when there\'s a reconnect because\n   // events could have been missed while not connected.\n   query_meta_all();\n@@ -273,33 +276,10 @@ void ControlConnection::on_query_meta_all(const MultipleRequestHandler::Response\n \n   session_->purge_hosts(is_initial_connection);\n \n-  {\n-    ResultResponse* keyspaces_result =\n-        static_cast<ResultResponse*>(responses[2]);\n-    keyspaces_result->decode_first_row();\n-    ResultIterator rows(keyspaces_result);\n-    while (rows.next()) {\n-      session_->update_keyspace(rows.row());\n-    }\n-  }\n-  {\n-    ResultResponse* col_fam_result =\n-        static_cast<ResultResponse*>(responses[3]);\n-    col_fam_result->decode_first_row();\n-    ResultIterator rows(col_fam_result);\n-    while (rows.next()) {\n-      session_->update_column_family(rows.row());\n-    }\n-  }\n-  {\n-    ResultResponse* col_result =\n-        static_cast<ResultResponse*>(responses[4]);\n-    col_result->decode_first_row();\n-    ResultIterator rows(col_result);\n-    while (rows.next()) {\n-      session_->update_column(rows.row());\n-    }\n-  }\n+  session_->schema().clear();\n+  session_->schema().update_keyspaces(static_cast<ResultResponse*>(responses[2]));\n+  session_->schema().update_tables(static_cast<ResultResponse*>(responses[3]));\n+  session_->schema().update_columns(static_cast<ResultResponse*>(responses[4]));\n \n   if (is_initial_connection) {\n     state_ = CONTROL_STATE_READY;\n@@ -402,7 +382,6 @@ void ControlConnection::on_refresh_node_info_all(RefreshNodeData data, Response*\n   }\n }\n \n-\n void ControlConnection::update_node_info(SharedRefPtr<Host> host, const Row* row) {\n   const Value* v;\n \n@@ -462,8 +441,7 @@ void ControlConnection::on_refresh_keyspace(const std::string& keyspace_name, Re\n                    keyspace_name.c_str());\n     return;\n   }\n-  result->decode_first_row();\n-  session_->update_keyspace(&result->first_row());\n+  session_->schema().update_keyspaces(result);\n }\n \n void ControlConnection::refresh_table(const boost::string_ref& keyspace_name,\n@@ -490,23 +468,14 @@ void ControlConnection::refresh_table(const boost::string_ref& keyspace_name,\n void ControlConnection::on_refresh_table(const std::string& keyspace_name,\n                                          const std::string& table_name,\n                                          const MultipleRequestHandler::ResponseVec& responses) {\n-  ResultResponse* col_fam_result = static_cast<ResultResponse*>(responses[0]);\n-  if (col_fam_result->row_count() == 0) {\n+  ResultResponse* column_family_result = static_cast<ResultResponse*>(responses[0]);\n+  if (column_family_result->row_count() == 0) {\n     logger_->error("ControlConnection: No row found for column family %s.%s in system schema table.",\n                    keyspace_name.c_str(), table_name.c_str());\n     return;\n   }\n-  col_fam_result->decode_first_row();\n-\n-  ResultResponse* col_result = static_cast<ResultResponse*>(responses[1]);\n-  col_result->decode_first_row();\n-  std::vector<Row> rows;\n-  rows.reserve(col_result->row_count());\n-  ResultIterator itr(col_result);\n-  while (itr.next()) {\n-    rows.push_back(*itr.row());\n-  }\n-  session_->update_column_family(&col_fam_result->first_row(), rows);\n+  session_->schema().update_tables(column_family_result);\n+  session_->schema().update_columns(static_cast<ResultResponse*>(responses[1]));\n }\n \n bool ControlConnection::handle_query_invalid_response(Response* response) {\n@@ -604,10 +573,10 @@ void ControlConnection::on_connection_event(EventResponse* response) {\n \n         case EventResponse::DROPPED:\n           if (response->table().size() > 0) {\n-            session_->drop_column_family(response->keyspace().to_string(),\n-                                         response->table().to_string());\n+            session_->schema().drop_table(response->keyspace().to_string(),\n+                                          response->table().to_string());\n           } else {\n-            session_->drop_keyspace(response->keyspace().to_string());\n+            session_->schema().drop_keyspace(response->keyspace().to_string());\n           }\n           break;\n       }\ndiff --git a/src/iterator.cpp b/src/iterator.cpp\nindex 9f1e85da..636a240b 100644\n--- a/src/iterator.cpp\n+++ b/src/iterator.cpp\n@@ -24,6 +24,10 @@\n \n extern "C" {\n \n+CassIteratorType cass_iterator_type(CassIterator* iterator) {\n+  return iterator->type();\n+}\n+\n CassIterator* cass_iterator_from_result(const CassResult* result) {\n   return CassIterator::to(new cass::ResultIterator(result));\n }\n@@ -55,7 +59,7 @@ cass_bool_t cass_iterator_next(CassIterator* iterator) {\n }\n \n const CassRow* cass_iterator_get_row(CassIterator* iterator) {\n-  if (iterator->type() != cass::CASS_ITERATOR_TYPE_RESULT) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_RESULT) {\n     return NULL;\n   }\n   return CassRow::to(\n@@ -64,7 +68,7 @@ const CassRow* cass_iterator_get_row(CassIterator* iterator) {\n }\n \n const CassValue* cass_iterator_get_column(CassIterator* iterator) {\n-  if (iterator->type() != cass::CASS_ITERATOR_TYPE_ROW) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_ROW) {\n     return NULL;\n   }\n   return CassValue::to(\n@@ -73,7 +77,7 @@ const CassValue* cass_iterator_get_column(CassIterator* iterator) {\n }\n \n const CassValue* cass_iterator_get_value(CassIterator* iterator) {\n-  if (iterator->type() != cass::CASS_ITERATOR_COLLECTION) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_COLLECTION) {\n     return NULL;\n   }\n   return CassValue::to(\n@@ -82,7 +86,7 @@ const CassValue* cass_iterator_get_value(CassIterator* iterator) {\n }\n \n const CassValue* cass_iterator_get_map_key(CassIterator* iterator) {\n-  if (iterator->type() != cass::CASS_ITERATOR_MAP) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_MAP) {\n     return NULL;\n   }\n   return CassValue::to(\n@@ -91,7 +95,7 @@ const CassValue* cass_iterator_get_map_key(CassIterator* iterator) {\n }\n \n const CassValue* cass_iterator_get_map_value(CassIterator* iterator) {\n-  if (iterator->type() != cass::CASS_ITERATOR_MAP) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_MAP) {\n     return NULL;\n   }\n   return CassValue::to(\ndiff --git a/src/iterator.hpp b/src/iterator.hpp\nindex 4130a10a..98535d9e 100644\n--- a/src/iterator.hpp\n+++ b/src/iterator.hpp\n@@ -17,32 +17,23 @@\n #ifndef __CASS_ITERATOR_HPP_INCLUDED__\n #define __CASS_ITERATOR_HPP_INCLUDED__\n \n-namespace cass {\n+#include "cassandra.h"\n \n-enum IteratorType {\n-  CASS_ITERATOR_TYPE_RESULT,\n-  CASS_ITERATOR_TYPE_ROW,\n-  CASS_ITERATOR_COLLECTION,\n-  CASS_ITERATOR_MAP,\n-  CASS_ITERATOR_TYPE_KS_META,\n-  CASS_ITERATOR_TYPE_CF_META,\n-  CASS_ITERATOR_TYPE_COL_META,\n-  CASS_ITERATOR_TYPE_UNKNOWN\n-};\n+namespace cass {\n \n class Iterator {\n public:\n-  Iterator(IteratorType type)\n+  Iterator(CassIteratorType type)\n       : type_(type) {}\n \n   virtual ~Iterator() {}\n \n-  IteratorType type() const { return type_; }\n+  CassIteratorType type() const { return type_; }\n \n   virtual bool next() = 0;\n \n private:\n-  const IteratorType type_;\n+  const CassIteratorType type_;\n };\n \n } // namespace cass\ndiff --git a/src/map_iterator.hpp b/src/map_iterator.hpp\nindex 64366a19..76ef0597 100644\n--- a/src/map_iterator.hpp\n+++ b/src/map_iterator.hpp\n@@ -27,7 +27,7 @@ namespace cass {\n class MapIterator : public Iterator {\n public:\n   MapIterator(const Value* map)\n-      : Iterator(CASS_ITERATOR_MAP)\n+      : Iterator(CASS_ITERATOR_TYPE_MAP)\n       , map_(map)\n       , position_(map->buffer().data())\n       , index_(-1)\ndiff --git a/src/ref_counted.hpp b/src/ref_counted.hpp\nindex 69de9a77..e1b99770 100644\n--- a/src/ref_counted.hpp\n+++ b/src/ref_counted.hpp\n@@ -17,11 +17,13 @@\n #ifndef __CASS_REF_COUNTED_HPP_INCLUDED__\n #define __CASS_REF_COUNTED_HPP_INCLUDED__\n \n+#include "common.hpp"\n #include "macros.hpp"\n \n #include "third_party/boost/boost/atomic.hpp"\n \n #include <assert.h>\n+#include <new>\n \n namespace cass {\n \n@@ -55,6 +57,30 @@ private:\n   DISALLOW_COPY_AND_ASSIGN(RefCounted);\n };\n \n+class RefBuffer : public RefCounted<RefBuffer> {\n+public:\n+  static RefBuffer* create(size_t size) {\n+    return new (size) RefBuffer();\n+  }\n+\n+  char* data() {\n+    return copy_cast<RefBuffer*, char*>(this) + sizeof(RefBuffer);\n+  }\n+\n+  void operator delete(void* ptr) {\n+    ::operator delete(ptr);\n+  }\n+\n+private:\n+  RefBuffer() {}\n+\n+  void* operator new(size_t size, size_t extra) {\n+    return ::operator new(size + extra);\n+  }\n+\n+  DISALLOW_COPY_AND_ASSIGN(RefBuffer);\n+};\n+\n template<class T>\n class SharedRefPtr {\n public:\ndiff --git a/src/response.cpp b/src/response.cpp\nindex 7ded10af..0b638091 100644\n--- a/src/response.cpp\n+++ b/src/response.cpp\n@@ -97,8 +97,8 @@ int ResponseMessage::decode(int version, char* input, size_t size) {\n         return -1;\n       }\n \n-      response_body_->set_buffer(new char[length_]);\n-      body_buffer_pos_ = response_body_->buffer();\n+      response_body_->set_buffer(length_);\n+      body_buffer_pos_ = response_body_->data();\n     } else {\n       // We haven\'t received all the data for the header. We consume the\n       // entire buffer.\n@@ -119,9 +119,9 @@ int ResponseMessage::decode(int version, char* input, size_t size) {\n     memcpy(body_buffer_pos_, input_pos, needed);\n     body_buffer_pos_ += needed;\n     input_pos += needed;\n-    assert(body_buffer_pos_ == response_body_->buffer() + length_);\n+    assert(body_buffer_pos_ == response_body_->data() + length_);\n \n-    if (!response_body_->decode(version, response_body_->buffer(), length_)) {\n+    if (!response_body_->decode(version, response_body_->data(), length_)) {\n       is_body_error_ = true;\n       return -1;\n     }\ndiff --git a/src/response.hpp b/src/response.hpp\nindex 0d4326c7..8e59eaaa 100644\n--- a/src/response.hpp\n+++ b/src/response.hpp\n@@ -17,8 +17,10 @@\n #ifndef __CASS_RESPONSE_HPP_INCLUDED__\n #define __CASS_RESPONSE_HPP_INCLUDED__\n \n+#include "common.hpp"\n #include "constants.hpp"\n #include "macros.hpp"\n+#include "ref_counted.hpp"\n #include "scoped_ptr.hpp"\n \n #include "third_party/boost/boost/cstdint.hpp"\n@@ -34,14 +36,17 @@ public:\n \n   uint8_t opcode() const { return opcode_; }\n \n-  char* buffer() { return buffer_.get(); }\n-  void set_buffer(char* buffer) { buffer_.reset(buffer); }\n+  char* data() const { return buffer_->data(); }\n+  const SharedRefPtr<RefBuffer>& buffer() const { return buffer_; }\n+  void set_buffer(size_t size) {\n+    buffer_ = SharedRefPtr<RefBuffer>(RefBuffer::create(size));\n+  }\n \n   virtual bool decode(int version, char* buffer, size_t size) = 0;\n \n private:\n   uint8_t opcode_;\n-  ScopedPtr<char[]> buffer_;\n+  SharedRefPtr<RefBuffer> buffer_;\n \n private:\n   DISALLOW_COPY_AND_ASSIGN(Response);\ndiff --git a/src/schema_metadata.cpp b/src/schema_metadata.cpp\nindex f6f24f2f..bb48767f 100644\n--- a/src/schema_metadata.cpp\n+++ b/src/schema_metadata.cpp\n@@ -17,471 +17,377 @@\n #include "schema_metadata.hpp"\n \n #include "buffer.hpp"\n+#include "buffer_collection.hpp"\n #include "cass_type_parser.hpp"\n+#include "iterator.hpp"\n #include "map_iterator.hpp"\n+#include "result_iterator.hpp"\n #include "row.hpp"\n+#include "row_iterator.hpp"\n #include "types.hpp"\n #include "value.hpp"\n \n #include "third_party/boost/boost/algorithm/string.hpp"\n+#include "third_party/rapidjson/rapidjson/document.h"\n \n #include <cmath>\n \n extern "C" {\n \n-void keyspace_meta_out(const cass::KeyspaceMetadata& ksm,\n-                       CassKeyspaceMeta* output) {\n-  cass::cass_string_of_string(ksm.name_, &output->name);\n-  output->durable_writes = ksm.durable_writes_;\n-  cass::cass_string_of_string(ksm.strategy_class_, &output->replication_strategy);\n-  cass::cass_string_of_string(ksm.strategy_options_json_, &output->strategy_options);\n+void cass_schema_free(const CassSchema* schema) {\n+  delete schema->from();\n }\n \n-CassError cass_meta_get_keyspace(CassSchemaMetadata* meta,\n-                                 CassString keyspace_name,\n-                                 CassKeyspaceMeta* output) {\n-  const cass::KeyspaceModel* ks = meta->get_keyspace(std::string(keyspace_name.data, keyspace_name.length));\n-  if (ks != NULL) {\n-    keyspace_meta_out(ks->meta(), output);\n-    return CASS_OK;\n-  }\n-  return CASS_ERROR_NAME_DOES_NOT_EXIST;\n-}\n-\n-CassError cass_meta_get_keyspace2(CassSchemaMetadata* meta,\n-                                  const char* keyspace_name,\n-                                  CassKeyspaceMeta* output) {\n-  return cass_meta_get_keyspace(meta, cass_string_init(keyspace_name), output);\n+const CassSchemaMeta* cass_schema_get_keyspace(const CassSchema* schema, const char* keyspace_name) {\n+  return CassSchemaMeta::to(schema->get(keyspace_name));\n }\n \n-void column_family_meta_out(const cass::ColumnFamilyMetadata& cfm,\n-                            CassColumnFamilyMeta* output) {\n-  cass::cass_string_of_string(cfm.name_, &output->name);\n-  output->bloom_filter_fp_chance = cfm.bloom_filter_fp_chance_;\n-  cass::cass_string_of_string(cfm.caching_, &output->caching);\n-  memcpy(output->cf_id, cfm.cf_id_, sizeof(cfm.cf_id_));\n-  cass::cass_string_of_string(cfm.column_aliases_, &output->column_aliases);\n-  cass::cass_string_of_string(cfm.comment_, &output->comment);\n-  cass::cass_string_of_string(cfm.compaction_strategy_class_, &output->compaction_strategy_class);\n-  cass::cass_string_of_string(cfm.compaction_strategy_options_, &output->compaction_strategy_options);\n-  cass::cass_string_of_string(cfm.comparator_, &output->comparator);\n-  cass::cass_string_of_string(cfm.compression_parameters_, &output->compression_parameters);\n-  output->default_time_to_live = cfm.default_time_to_live_;\n-  cass::cass_string_of_string(cfm.default_validator_, &output->default_validator);\n-  // not decoded: dropped_columns (map<string, bigint>)\n-  // didn\'t see a lot of value in creating an iterator just to get this out\n-  // could see encoding json, but not sure what a client would need it for\n-  output->gc_grace_seconds = cfm.gc_grace_seconds_;\n-  output->index_interval = cfm.index_interval_;\n-  output->is_dense = cfm.is_dense_;\n-  cass::cass_string_of_string(cfm.key_aliases_, &output->key_aliases);\n-  cass::cass_string_of_string(cfm.key_validator_, &output->key_validator);\n-  output->local_read_repair_chance = cfm.local_read_repair_chance_;\n-  output->max_compaction_threshold = cfm.max_compaction_threshold_;\n-  output->max_index_interval = cfm.max_index_interval_;\n-  output->memtable_flush_period_in_ms = cfm.memtable_flush_period_in_ms_;\n-  output->min_compaction_threshold = cfm.min_compaction_threshold_;\n-  output->min_index_interval = cfm.min_index_interval_;\n-  output->read_repair_chance = cfm.read_repair_chance_;\n-  cass::cass_string_of_string(cfm.speculative_retry_, &output->speculative_retry);\n-  cass::cass_string_of_string(cfm.subcomparator_, &output->subcomparator);\n-  cass::cass_string_of_string(cfm.type_, &output->type);\n-  cass::cass_string_of_string(cfm.value_alias_, &output->value_alias);\n+CassSchemaMetaType cass_schema_meta_type(const CassSchemaMeta* meta) {\n+  return meta->type();\n }\n \n-CassError cass_meta_get_column_family(CassSchemaMetadata* schema_meta,\n-                                      CassString keyspace_name,\n-                                      CassString column_family_name,\n-                                      CassColumnFamilyMeta* output) {\n-  const cass::KeyspaceModel* ks = schema_meta->get_keyspace(std::string(keyspace_name.data, keyspace_name.length));\n-  if (ks != NULL) {\n-    const cass::ColumnFamilyModel* cf = ks->get_column_family(std::string(column_family_name.data, column_family_name.length));\n-    if (cf != NULL) {\n-      column_family_meta_out(cf->meta(), output);\n-      return CASS_OK;\n-    }\n-  }\n-  return CASS_ERROR_NAME_DOES_NOT_EXIST;\n+const CassSchemaMeta* cass_schema_meta_get_entry(const CassSchemaMeta* meta, const char* name) {\n+  return CassSchemaMeta::to(meta->get_entry(name));\n }\n \n-CassError cass_meta_get_column_family2(CassSchemaMetadata* schema_meta,\n-                                       const char* keyspace_name,\n-                                       const char* column_family_name,\n-                                       CassColumnFamilyMeta* output) {\n-  return cass_meta_get_column_family(schema_meta, cass_string_init(keyspace_name), cass_string_init(column_family_name), output);\n+const CassSchemaMetaField* cass_schema_meta_get_field(const CassSchemaMeta* meta, const char* name) {\n+  return CassSchemaMetaField::to(meta->get_field(name));\n }\n \n-void column_meta_out(const cass::ColumnMetadata& cm, CassColumnMeta* output) {\n-  cass::cass_string_of_string(cm.name_, &output->name);\n-  output->component_index = cm.component_index_;\n-  cass::cass_string_of_string(cm.index_name_, &output->index_name);\n-  cass::cass_string_of_string(cm.index_options_, &output->index_options);\n-  cass::cass_string_of_string(cm.index_type_, &output->index_type);\n-  output->kind = cm.kind_;\n-  output->type = cm.type_.type_;\n-  output->is_reversed = static_cast<cass_bool_t>(cm.type_.is_reversed_);\n-  cass::cass_string_of_string(cm.validator_, &output->validator);\n+CassString cass_schema_meta_field_name(const CassSchemaMetaField* field) {\n+  const std::string& name = field->name();\n+  return cass_string_init2(name.data(), name.size());\n }\n \n-CassError cass_meta_get_column(CassSchemaMetadata* schema_meta,\n-                               CassString keyspace_name,\n-                               CassString column_family_name,\n-                               CassString column_name,\n-                               CassColumnMeta* output) {\n-  const cass::KeyspaceModel* ks = schema_meta->get_keyspace(std::string(keyspace_name.data, keyspace_name.length));\n-  if (ks != NULL) {\n-    const cass::ColumnFamilyModel* cf = ks->get_column_family(std::string(column_family_name.data, column_family_name.length));\n-    if (cf != NULL) {\n-      const cass::ColumnModel* cm = cf->get_column(std::string(column_name.data, column_name.length));\n-      if (cm != NULL) {\n-        column_meta_out(cm->meta(), output);\n-        return CASS_OK;\n-      }\n-    }\n-  }\n-  return CASS_ERROR_NAME_DOES_NOT_EXIST;\n+const CassValue* cass_schema_meta_field_value(const CassSchemaMetaField* field) {\n+  return CassValue::to(field->value());\n }\n \n-CassError cass_meta_get_column2(CassSchemaMetadata* schema_meta,\n-                                const char* keyspace_name,\n-                                const char* column_family_name,\n-                                const char* column_name,\n-                                CassColumnMeta* output) {\n-  return cass_meta_get_column(schema_meta, cass_string_init(keyspace_name), cass_string_init(column_family_name), cass_string_init(column_name), output);\n+CassIterator* cass_iterator_from_schema(const CassSchema* schema) {\n+  return CassIterator::to(schema->iterator());\n }\n \n-CassIterator* cass_iterator_keyspaces(CassSchemaMetadata* schema_meta) {\n-  return CassIterator::to(new cass::KeyspaceIterator(schema_meta->keyspaces()));\n+CassIterator* cass_iterator_from_schema_meta(const CassSchemaMeta* meta) {\n+  return CassIterator::to(meta->iterator());\n }\n \n-CassError cass_iterator_get_keyspace_meta(CassIterator* ks_itr,\n-                                          CassKeyspaceMeta* output) {\n-  assert(ks_itr->type() == cass::CASS_ITERATOR_TYPE_KS_META);\n-  keyspace_meta_out(static_cast<cass::KeyspaceIterator*>(ks_itr->from())->meta(), output);\n-  return CASS_OK;\n+const CassSchemaMeta* cass_iterator_get_schema_meta(CassIterator* iterator) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_SCHEMA_META) {\n+    return NULL;\n+  }\n+  return CassSchemaMeta::to(\n+        static_cast<cass::SchemaMetadataIterator*>(\n+          iterator->from())->meta());\n }\n \n-CassIterator* cass_iterator_column_families_from_keyspace(CassIterator* ks_itr) {\n-  assert(ks_itr->type() == cass::CASS_ITERATOR_TYPE_KS_META);\n-  const cass::KeyspaceModel& ksm = static_cast<cass::KeyspaceIterator*>(ks_itr->from())->model();\n-  return CassIterator::to(new cass::ColumnFamilyIterator(ksm.column_families()));\n+CassIterator* cass_iterator_fields_from_schema_meta(const CassSchemaMeta* meta) {\n+  return CassIterator::to(meta->iterator_fields());\n }\n \n-CassIterator* cass_iterator_column_families(CassSchemaMetadata* schema_meta,\n-                                            CassString keyspace_name) {\n-  const cass::KeyspaceModel* ksm = schema_meta->get_keyspace(std::string(keyspace_name.data, keyspace_name.length));\n-  if (ksm != NULL) {\n-    return CassIterator::to(new cass::ColumnFamilyIterator(ksm->column_families()));\n+const CassSchemaMetaField* cass_iterator_get_schema_meta_field(CassIterator* iterator) {\n+  if (iterator->type() != CASS_ITERATOR_TYPE_SCHEMA_META_FIELD) {\n+    return NULL;\n   }\n-  return NULL;\n+  return CassSchemaMetaField::to(\n+        static_cast<cass::SchemaMetadataFieldIterator*>(\n+          iterator->from())->field());\n }\n \n-CassIterator* cass_iterator_column_families2(CassSchemaMetadata* schema_meta,\n-                                             const char* keyspace_name) {\n-  return cass_iterator_column_families(schema_meta, cass_string_init(keyspace_name));\n-}\n+} // extern "C"\n \n-CassError cass_iterator_get_column_family_meta(CassIterator* cf_itr,\n-                                               CassColumnFamilyMeta* output) {\n-  assert(cf_itr->type() == cass::CASS_ITERATOR_TYPE_CF_META);\n-  column_family_meta_out(static_cast<cass::ColumnFamilyIterator*>(cf_itr->from())->meta(), output);\n-  return CASS_OK;\n-}\n+namespace cass {\n \n-CassIterator* cass_iterator_columns(CassSchemaMetadata* schema_meta,\n-                                    CassString keyspace_name,\n-                                    CassString column_family_name) {\n-  const cass::KeyspaceModel* ksm = schema_meta->get_keyspace(std::string(keyspace_name.data, keyspace_name.length));\n-  if (ksm != NULL) {\n-    const cass::ColumnFamilyModel* cfm = ksm->get_column_family(std::string(column_family_name.data, column_family_name.length));\n-    if (cfm != NULL) {\n-      return CassIterator::to(new cass::ColumnIterator(cfm->columns()));\n-    }\n+static bool get_value_by_name(const Row* row, const char* column_name, std::string* output) {\n+  const Value* value = row->get_by_name(column_name);\n+  if (value == NULL || value->is_null() || value->buffer().size() == 0) {\n+    return false;\n   }\n-  return NULL;\n-}\n-\n-CassIterator* cass_iterator_column2(CassSchemaMetadata* schema_meta,\n-                                    const char* keyspace_name,\n-                                    const char* column_family_name) {\n-  return cass_iterator_columns(schema_meta, cass_string_init(keyspace_name), cass_string_init(column_family_name));\n+  output->assign(value->buffer().data(), value->buffer().size());\n+  return true;\n }\n \n-CassIterator* cass_iterator_columns_from_column_family(CassIterator *cf_itr) {\n-  assert(cf_itr->type() == cass::CASS_ITERATOR_TYPE_CF_META);\n-  const cass::ColumnFamilyModel& cfm = static_cast<cass::ColumnFamilyIterator*>(cf_itr->from())->model();\n-  return CassIterator::to(new cass::ColumnIterator(cfm.columns()));\n+template <class T>\n+const T* find_by_name(const std::map<std::string, T>& map, const std::string& name) {\n+  typename std::map<std::string, T>::const_iterator it = map.find(name);\n+  if (it == map.end()) return NULL;\n+  return &it->second;\n }\n \n-CassError cass_iterator_get_column_meta(CassIterator *col_itr,\n-                                        CassColumnMeta *output) {\n-  assert(col_itr->type() == cass::CASS_ITERATOR_TYPE_COL_META);\n-  column_meta_out(static_cast<cass::ColumnIterator*>(col_itr->from())->meta(), output);\n-  return CASS_OK;\n+const SchemaMetadata* Schema::get(const std::string& name) const {\n+  return find_by_name<KeyspaceMetadata>(*keyspaces_, name);\n }\n \n-void cass_meta_free(CassSchemaMetadata *meta) {\n-  delete meta->from();\n-}\n-\n-} // extern "C"\n+void Schema::update_keyspaces(ResultResponse* result) {\n+  SharedRefPtr<RefBuffer> buffer = result->buffer();\n \n-namespace cass {\n+  result->decode_first_row();\n+  ResultIterator rows(result);\n \n-void get_optional_string(const Value* v, std::string* output, const char* deflt = NULL) {\n-  if (v != NULL && !v->is_null()) {\n-    output->assign(v->buffer().data(), v->buffer().size());\n-  } else {//TODO: remove?\n-    if (deflt != NULL) {\n-      *output = deflt;\n+  while (rows.next()) {\n+    const Row* row = rows.row();\n+    std::string keyspace_name;\n+    if (!get_value_by_name(row, "keyspace_name", &keyspace_name)) {\n+      // TODO: Add global logging\n+      continue;\n     }\n+    get_or_create(keyspace_name)->update(protocol_version_, buffer, row);\n   }\n }\n \n-std::string string_from_column(const Row* row, const boost::string_ref& name) {\n-  std::string value;\n-  get_optional_string(row->get_by_name(name), &value);\n-  return value;\n-}\n+void Schema::update_tables(ResultResponse* result) {\n+  SharedRefPtr<RefBuffer> buffer = result->buffer();\n \n-ColumnMetadata::ColumnTypeMapper::ColumnTypeMapper() {\n-  name_type_map_["PARITION_KEY"] = CASS_COLUMN_TYPE_PARITION_KEY;\n-  name_type_map_["CLUSTERING_KEY"] = CASS_COLUMN_TYPE_CLUSTERING_KEY;\n-  name_type_map_["REGULAR"] = CASS_COLUMN_TYPE_REGULAR;\n-  name_type_map_["COMPACT_VALUE"] = CASS_COLUMN_TYPE_COMPACT_VALUE;\n-  name_type_map_["STATIC"] = CASS_COLUMN_TYPE_STATIC;\n-}\n+  result->decode_first_row();\n+  ResultIterator rows(result);\n \n-CassColumnType ColumnMetadata::ColumnTypeMapper::operator [](const std::string& col_type) const {\n-  NameTypeMap::const_iterator itr = name_type_map_.find(boost::to_upper_copy(col_type));\n-  if (itr != name_type_map_.end()) {\n-    return itr->second;\n-  } else {\n-    return CASS_COLUMN_TYPE_UNKNOWN;\n-  }\n-}\n+  std::string keyspace_name;\n+  std::string columnfamily_name;\n+  KeyspaceMetadata* keyspace_metadata = NULL;\n \n-const ColumnMetadata::ColumnTypeMapper ColumnMetadata::type_map_;\n+  while (rows.next()) {\n+    std::string temp_keyspace_name;\n+    const Row* row = rows.row();\n \n-ColumnMetadata::ColumnMetadata()\n-    : component_index_(-1)\n-    , kind_(CASS_COLUMN_TYPE_UNKNOWN) {}\n-\n-ColumnMetadata ColumnMetadata::from_schema_row(const Row* schema_row) {\n-  ColumnMetadata cm;\n+    if (!get_value_by_name(row, "keyspace_name", &temp_keyspace_name) ||\n+        !get_value_by_name(row, "columnfamily_name", &columnfamily_name)) {\n+      // TODO: Add global logging\n+      continue;\n+    }\n \n-  get_optional_string(schema_row->get_by_name("column_name"), &cm.name_);\n+    if (keyspace_name != temp_keyspace_name) {\n+      keyspace_name = temp_keyspace_name;\n+      keyspace_metadata = get_or_create(keyspace_name);\n+    }\n \n-  std::string kind;\n-  get_optional_string(schema_row->get_by_name("type"), &kind);\n-  cm.kind_ = type_map_[kind];\n+    keyspace_metadata->get_or_create(columnfamily_name)->update(protocol_version_, buffer, row);\n+  }\n+}\n \n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("component_index")), &cm.component_index_);\n+void Schema::update_columns(ResultResponse* result) {\n+  SharedRefPtr<RefBuffer> buffer = result->buffer();\n \n-  get_optional_string(schema_row->get_by_name("validator"), &cm.validator_);\n-  cm.type_ = CassTypeParser::parse(cm.validator_);\n+  result->decode_first_row();\n+  ResultIterator rows(result);\n \n-  get_optional_string(schema_row->get_by_name("index_name"), &cm.index_name_);\n-  get_optional_string(schema_row->get_by_name("index_options"), &cm.index_options_);\n-  get_optional_string(schema_row->get_by_name("index_type"), &cm.index_type_);\n+  std::string keyspace_name;\n+  std::string columnfamily_name;\n+  std::string column_name;\n+  TableMetadata* table_metadata = NULL;\n \n-  return cm;\n-}\n+  while (rows.next()) {\n+    std::string temp_keyspace_name;\n+    std::string temp_columnfamily_name;\n+    const Row* row = rows.row();\n \n-std::string ColumnMetadata::keyspace_name_from_row(const Row* schema_row) {\n-  return string_from_column(schema_row, "keyspace_name");\n-}\n-\n-std::string ColumnMetadata::column_family_name_from_row(const Row* schema_row) {\n-  return string_from_column(schema_row, "columnfamily_name");\n-}\n-\n-std::string ColumnMetadata::name_from_row(const Row* schema_row) {\n-  return string_from_column(schema_row, "column_name");\n-}\n+    if (!get_value_by_name(row, "keyspace_name", &temp_keyspace_name) ||\n+        !get_value_by_name(row, "columnfamily_name", &temp_columnfamily_name) ||\n+        !get_value_by_name(row, "column_name", &column_name)) {\n+      // TODO: Add global logging\n+      continue;\n+    }\n \n-ColumnFamilyMetadata::ColumnFamilyMetadata()\n-  : bloom_filter_fp_chance_(NAN)\n-  , default_time_to_live_(-1)\n-  , gc_grace_seconds_(-1)\n-  , index_interval_(-1)\n-  , is_dense_(cass_false)\n-  , local_read_repair_chance_(NAN)\n-  , max_compaction_threshold_(-1)\n-  , max_index_interval_(-1)\n-  , memtable_flush_period_in_ms_(-1)\n-  , min_compaction_threshold_(-1)\n-  , min_index_interval_(-1)\n-  , read_repair_chance_(NAN) {\n-  memset(&cf_id_, 0, sizeof(cf_id_));\n-}\n+    if (keyspace_name != temp_keyspace_name ||\n+        columnfamily_name != temp_columnfamily_name) {\n+      keyspace_name = temp_keyspace_name;\n+      columnfamily_name = temp_columnfamily_name;\n+      table_metadata = get_or_create(keyspace_name)->get_or_create(columnfamily_name);\n+    }\n \n-ColumnFamilyMetadata ColumnFamilyMetadata::from_schema_row(const Row* schema_row) {\n-  ColumnFamilyMetadata cfm;\n-  get_optional_string(schema_row->get_by_name("columnfamily_name"), &cfm.name_);\n-  cass_value_get_double(CassValue::to(schema_row->get_by_name("bloom_filter_fp_chance")), &cfm.bloom_filter_fp_chance_);\n-  get_optional_string(schema_row->get_by_name("caching"), &cfm.caching_);\n-  cass_value_get_uuid(CassValue::to(schema_row->get_by_name("cf_id")), cfm.cf_id_);\n-  get_optional_string(schema_row->get_by_name("column_aliases"), &cfm.column_aliases_);\n-  get_optional_string(schema_row->get_by_name("comment"), &cfm.comment_);\n-  get_optional_string(schema_row->get_by_name("compaction_strategy_class"), &cfm.compaction_strategy_class_);\n-  get_optional_string(schema_row->get_by_name("compaction_strategy_options"), &cfm.compaction_strategy_options_);\n-  get_optional_string(schema_row->get_by_name("comparator"), &cfm.comparator_);\n-  get_optional_string(schema_row->get_by_name("compression_parameters"), &cfm.compression_parameters_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("default_time_to_live")), &cfm.default_time_to_live_);\n-  get_optional_string(schema_row->get_by_name("default_validator"), &cfm.default_validator_);\n-\n-  MapIterator itr(schema_row->get_by_name("dropped_columns"));\n-  while(itr.next()) {\n-    const Value* key = itr.key();\n-    cass_int64_t& ts = cfm.dropped_columns_[std::string(key->buffer().data(), key->buffer().size())];\n-    cass_value_get_int64(CassValue::to(itr.value()), &ts);\n+    table_metadata->get_or_create(column_name)->update(protocol_version_, buffer, row);\n   }\n+}\n \n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("gc_grace_seconds")), &cfm.gc_grace_seconds_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("index_interval")), &cfm.index_interval_);\n-  cass_value_get_bool(CassValue::to(schema_row->get_by_name("is_dense")), &cfm.is_dense_);\n-  get_optional_string(schema_row->get_by_name("key_aliases"), &cfm.key_aliases_);\n-  get_optional_string(schema_row->get_by_name("key_validator"), &cfm.key_validator_);\n-  cass_value_get_double(CassValue::to(schema_row->get_by_name("local_read_repair_chance")), &cfm.local_read_repair_chance_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("max_compaction_threshold")), &cfm.max_compaction_threshold_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("max_index_interval")), &cfm.max_index_interval_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("memtable_flush_period_in_ms")), &cfm.memtable_flush_period_in_ms_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("min_compaction_threshold")), &cfm.min_compaction_threshold_);\n-  cass_value_get_int32(CassValue::to(schema_row->get_by_name("min_index_interval")), &cfm.min_index_interval_);\n-  cass_value_get_double(CassValue::to(schema_row->get_by_name("read_repair_chance")), &cfm.read_repair_chance_);\n-  get_optional_string(schema_row->get_by_name("speculative_retry"), &cfm.speculative_retry_);\n-  get_optional_string(schema_row->get_by_name("subcomparator"), &cfm.subcomparator_);\n-  get_optional_string(schema_row->get_by_name("type"), &cfm.type_);\n-  get_optional_string(schema_row->get_by_name("value_alias"), &cfm.value_alias_);\n-  return cfm;\n+void Schema::drop_keyspace(const std::string& keyspace_name) {\n+  keyspaces_->erase(keyspace_name);\n }\n \n-std::string ColumnFamilyMetadata::keyspace_name_from_row(const Row* schema_row) {\n-  return string_from_column(schema_row, "keyspace_name");\n+void Schema::drop_table(const std::string& keyspace_name, const std::string& table_name) {\n+  KeyspaceMetadata::Map::iterator it = keyspaces_->find(keyspace_name);\n+  if (it == keyspaces_->end()) return;\n+  it->second.drop_table(table_name);\n }\n \n-std::string ColumnFamilyMetadata::name_from_row(const Row* schema_row) {\n-  return string_from_column(schema_row, "columnfamily_name");\n+void Schema::clear() {\n+  keyspaces_->clear();\n }\n \n-void ColumnFamilyModel::update_column(const Row* schema_row) {\n-  columns_[ColumnMetadata::name_from_row(schema_row)]\n-      .set_meta(ColumnMetadata::from_schema_row(schema_row));\n+const SchemaMetadataField* SchemaMetadata::get_field(const std::string& name) const {\n+  return find_by_name<SchemaMetadataField>(fields_, name);\n }\n \n-void ColumnFamilyModel::update_columns(const std::vector<Row> col_rows) {\n-  std::set<std::string> updated;\n-  for (std::vector<Row>::const_iterator i = col_rows.begin(); i != col_rows.end(); ++i) {\n-    std::string col_name = ColumnMetadata::name_from_row(&*i);\n-    updated.insert(col_name);\n-    columns_[col_name].set_meta(ColumnMetadata::from_schema_row(&*i));\n-  }\n-  ColumnModelMap::iterator i = columns_.begin();\n-  while(i != columns_.end()) {\n-    if (updated.find(i->first) == updated.end()) {\n-      columns_.erase(i++);\n-    } else {\n-      ++i;\n-    }\n+void SchemaMetadata::add_field(const SharedRefPtr<RefBuffer>& buffer, const Row* row, const std::string& name) {\n+  const Value* value = row->get_by_name(name);\n+  if (value == NULL || value->buffer().size() <= 0) {\n+    fields_[name] = SchemaMetadataField(name);\n+    return;\n   }\n+  fields_[name] = SchemaMetadataField(name, *value, buffer);\n }\n \n-const ColumnModel* ColumnFamilyModel::get_column(const std::string& col_name) const {\n-  const ColumnModel* cm = NULL;\n-  ColumnModelMap::const_iterator i = columns_.find(col_name);\n-  if (i != columns_.end()) {\n-    cm = &i->second;\n+void SchemaMetadata::add_json_list_field(int version, const Row* row, const std::string& name) {\n+  const Value* value = row->get_by_name(name);\n+  if (value == NULL || value->buffer().size() <= 0) {\n+    fields_[name] = SchemaMetadataField(name);\n+    return;\n   }\n-  return cm;\n-}\n \n-KeyspaceMetadata::KeyspaceMetadata()\n-  : durable_writes_(cass_false) {}\n+  int32_t buffer_size = value->buffer().size();\n+  ScopedPtr<char[]> buf(new char[buffer_size + 1]);\n+  memcpy(buf.get(), value->buffer().data(), buffer_size);\n+  buf[buffer_size] = \'\\0\';\n \n+  rapidjson::Document d;\n+  d.ParseInsitu(buf.get());\n \n-KeyspaceMetadata KeyspaceMetadata::from_schema_row(const Row* schema_row) {\n-  KeyspaceMetadata ksm;\n-  get_optional_string(schema_row->get_by_name("keyspace_name"), &ksm.name_);\n-  cass_value_get_bool(CassValue::to(schema_row->get_by_name("durable_writes")), &ksm.durable_writes_);\n-  get_optional_string(schema_row->get_by_name("strategy_class"), &ksm.strategy_class_);\n+  if (d.HasParseError()) {\n+    //TODO: log to global logging\n+    return;\n+  }\n \n-  const Value* v = schema_row->get_by_name("strategy_options");\n-  if (v != NULL && !v->is_null()) {\n-    json_to_map(v->buffer(), &ksm.strategy_options_);\n-    ksm.strategy_options_json_.assign(v->buffer().data(), v->buffer().size());\n+  if (!d.IsArray()) {\n+    fields_[name] = SchemaMetadataField(name);\n+    return;\n   }\n \n-  return ksm;\n-}\n+  BufferCollection collection(false, d.Size());\n+  for (rapidjson::Value::ConstValueIterator i = d.Begin(); i != d.End(); ++i) {\n+    collection.append(i->GetString(), i->GetStringLength());\n+  }\n \n-std::string KeyspaceMetadata::name_from_row(const Row* schema_row) {\n-  return string_from_column(schema_row, "keyspace_name");\n-}\n+  int encoded_size = collection.calculate_size(version);\n \n-void KeyspaceModel::update_column_family(const Row* schema_row) {\n-  cfs_[ColumnFamilyMetadata::name_from_row(schema_row)]\n-      .set_meta(ColumnFamilyMetadata::from_schema_row(schema_row));\n-}\n+  if (encoded_size <= 0) {\n+    //TODO: log to global logging\n+    return;\n+  }\n \n-void KeyspaceModel::update_column_family(const Row* schema_row, const std::vector<Row> col_rows) {\n-  ColumnFamilyModel& cfm = cfs_[ColumnMetadata::column_family_name_from_row(schema_row)];\n-  cfm.set_meta(ColumnFamilyMetadata::from_schema_row(schema_row));\n-  cfm.update_columns(col_rows);\n-}\n+  SharedRefPtr<RefBuffer> encoded(RefBuffer::create(encoded_size));\n+\n+  collection.encode(version, encoded->data());\n \n-void KeyspaceModel::update_column(const Row* schema_row) {\n-  cfs_[ColumnMetadata::column_family_name_from_row(schema_row)]\n-      .update_column(schema_row);\n+  Value map(CASS_VALUE_TYPE_LIST,\n+            CASS_VALUE_TYPE_TEXT,\n+            CASS_VALUE_TYPE_UNKNOWN,\n+            d.Size(),\n+            encoded->data(),\n+            encoded_size);\n+  fields_[name] = SchemaMetadataField(name, map, encoded);\n }\n \n-const ColumnFamilyModel* KeyspaceModel::get_column_family(const std::string& cf_name) const {\n-  const ColumnFamilyModel* cfm = NULL;\n-  ColumnFamilyModelMap::const_iterator i = cfs_.find(cf_name);\n-  if (i != cfs_.end()) {\n-    cfm = &i->second;\n+void SchemaMetadata::add_json_map_field(int version, const Row* row, const std::string& name) {\n+  const Value* value = row->get_by_name(name);\n+  if (value == NULL || value->buffer().size() <= 0) {\n+    fields_[name] = SchemaMetadataField(name);\n+    return;\n   }\n-  return cfm;\n-}\n \n-void SchemaModel::update_keyspace(const Row* schema_row) {\n-  keyspaces_[KeyspaceMetadata::name_from_row(schema_row)]\n-      .set_meta(KeyspaceMetadata::from_schema_row(schema_row));\n-}\n+  int32_t buffer_size = value->buffer().size();\n+  ScopedPtr<char[]> buf(new char[buffer_size + 1]);\n+  memcpy(buf.get(), value->buffer().data(), buffer_size);\n+  buf[buffer_size] = \'\\0\';\n \n-void SchemaModel::update_column_family(const Row* schema_row) {\n-  keyspaces_[ColumnFamilyMetadata::keyspace_name_from_row(schema_row)]\n-      .update_column_family(schema_row);\n-}\n+  rapidjson::Document d;\n+  d.ParseInsitu(buf.get());\n \n-void SchemaModel::update_column_family(const Row* schema_row, const std::vector<Row> col_rows) {\n-  KeyspaceModelMap::iterator i = keyspaces_.find(ColumnMetadata::keyspace_name_from_row(schema_row));\n-  if (i != keyspaces_.end()) {\n-    i->second.update_column_family(schema_row, col_rows);\n+  if (d.HasParseError()) {\n+    //TODO: log to global logging\n+    return;\n   }\n-}\n \n-void SchemaModel::update_column(const Row *schema_row) {\n-  keyspaces_[ColumnFamilyMetadata::keyspace_name_from_row(schema_row)]\n-      .update_column(schema_row);\n-}\n+  if (!d.IsObject()) {\n+    fields_[name] = SchemaMetadataField(name);\n+    return;\n+  }\n \n-void SchemaModel::drop_column_family(const std::string& ks_name, const std::string& cf_name) {\n-  KeyspaceModelMap::iterator i = keyspaces_.find(ks_name);\n-  if (i != keyspaces_.end()) {\n-     i->second.drop_column_family(cf_name);\n+  BufferCollection collection(true, 2 * d.MemberCount());\n+  for (rapidjson::Value::ConstMemberIterator i = d.MemberBegin(); i != d.MemberEnd(); ++i) {\n+    collection.append(i->name.GetString(), i->name.GetStringLength());\n+    collection.append(i->value.GetString(), i->value.GetStringLength());\n   }\n-}\n \n-const KeyspaceModel* SchemaModel::get_keyspace(const std::string& ks_name) const {\n-  const KeyspaceModel* ksm = NULL;\n-  KeyspaceModelMap::const_iterator i = keyspaces_.find(ks_name);\n-  if (i != keyspaces_.end()) {\n-    ksm = &i->second;\n+  int encoded_size = collection.calculate_size(version);\n+\n+  if (encoded_size <= 0) {\n+    //TODO: log to global logging\n+    return;\n   }\n-  return ksm;\n+\n+  SharedRefPtr<RefBuffer> encoded(RefBuffer::create(encoded_size));\n+\n+  collection.encode(version, encoded->data());\n+\n+  Value map(CASS_VALUE_TYPE_MAP,\n+            CASS_VALUE_TYPE_TEXT,\n+            CASS_VALUE_TYPE_TEXT,\n+            d.MemberCount(),\n+            encoded->data(),\n+            encoded_size);\n+  fields_[name] = SchemaMetadataField(name, map, encoded);\n+}\n+\n+const SchemaMetadata* KeyspaceMetadata::get_entry(const std::string& name) const {\n+  return find_by_name<TableMetadata>(tables_, name);\n+}\n+\n+void KeyspaceMetadata::update(int version, const SharedRefPtr<RefBuffer>& buffer, const Row* row) {\n+  add_field(buffer, row, "keyspace_name");\n+  add_field(buffer, row, "durable_writes");\n+  add_field(buffer, row, "strategy_class");\n+  add_json_map_field(version, row, "strategy_options");\n+}\n+\n+void KeyspaceMetadata::drop_table(const std::string& table_name) {\n+  tables_.erase(table_name);\n+}\n+\n+const SchemaMetadata* TableMetadata::get_entry(const std::string& name) const {\n+  return find_by_name<ColumnMetadata>(columns_, name);\n+}\n+\n+void TableMetadata::update(int version, const SharedRefPtr<RefBuffer>& buffer, const Row* row) {\n+  add_field(buffer, row, "keyspace_name");\n+  add_field(buffer, row, "columnfamily_name");\n+  add_field(buffer, row, "bloom_filter_fp_chance");\n+  add_json_map_field(version, row, "caching");\n+  add_field(buffer, row, "cf_id");\n+  add_json_list_field(version, row, "column_aliases");\n+  add_field(buffer, row, "comment");\n+  add_field(buffer, row, "compaction_strategy_class");\n+  add_json_map_field(version, row, "compaction_strategy_options");\n+  add_field(buffer, row, "comparator");\n+  add_json_map_field(version, row, "compression_parameters");\n+  add_field(buffer, row, "default_time_to_live");\n+  add_field(buffer, row, "default_validator");\n+  add_field(buffer, row, "dropped_columns");\n+  add_field(buffer, row, "gc_grace_seconds");\n+  add_field(buffer, row, "index_interval");\n+  add_field(buffer, row, "is_dense");\n+  add_json_list_field(version, row, "key_aliases");\n+  add_field(buffer, row, "key_validator");\n+  add_field(buffer, row, "local_read_repair_chance");\n+  add_field(buffer, row, "max_compaction_threshold");\n+  add_field(buffer, row, "max_index_interval");\n+  add_field(buffer, row, "memtable_flush_period_in_ms");\n+  add_field(buffer, row, "min_compaction_threshold");\n+  add_field(buffer, row, "min_index_interval");\n+  add_field(buffer, row, "read_repair_chance");\n+  add_field(buffer, row, "speculative_retry");\n+  add_field(buffer, row, "subcomparator");\n+  add_field(buffer, row, "type");\n+  add_field(buffer, row, "value_alias");\n+}\n+\n+void ColumnMetadata::update(int version, const SharedRefPtr<RefBuffer>& buffer, const Row* row) {\n+  add_field(buffer, row, "keyspace_name");\n+  add_field(buffer, row, "columnfamily_name");\n+  add_field(buffer, row, "column_name");\n+  add_field(buffer, row, "type");\n+  add_field(buffer, row, "component_index");\n+  add_field(buffer, row, "validator");\n+  add_field(buffer, row, "index_name");\n+  add_json_map_field(version, row, "index_options");\n+  add_field(buffer, row, "index_type");\n }\n \n } // namespace cass\n \n-\ndiff --git a/src/schema_metadata.hpp b/src/schema_metadata.hpp\nindex d3e7b6a2..adb16843 100644\n--- a/src/schema_metadata.hpp\n+++ b/src/schema_metadata.hpp\n@@ -18,6 +18,7 @@\n #define __CASS_SCHEMA_METADATA_HPP_INCLUDED__\n \n #include "cass_type_parser.hpp"\n+#include "copy_on_write_ptr.hpp"\n #include "iterator.hpp"\n #include "scoped_ptr.hpp"\n \n@@ -26,201 +27,210 @@\n \n namespace cass {\n \n-class BufferPiece;\n class Row;\n+class ResultResponse;\n \n-template<class C, cass::IteratorType I>\n-class ModelMapIterator : public Iterator {\n+template<class T>\n+class SchemaMapIteratorImpl {\n public:\n-  ModelMapIterator(const C& model_map)\n-      : Iterator(I)\n-      , first_next_(true)\n-      , itr_(model_map.begin())\n-      , end_(model_map.end()) {}\n-\n-  virtual bool next() {\n-    if (itr_ == end_) {\n+  typedef std::map<std::string, T> Map;\n+\n+  SchemaMapIteratorImpl(const Map& map)\n+    : next_(map.begin())\n+    , end_(map.end()) {}\n+\n+  bool next() {\n+    if (next_ == end_) {\n       return false;\n     }\n-    if (!first_next_) {\n-      ++itr_;\n-    }\n-    first_next_ = false;\n-    return itr_ != end_;\n+    current_ = next_++;\n+    return true;\n+  }\n+\n+  const T* item() const {\n+    return &current_->second;\n   }\n \n-  const typename C::mapped_type::meta_type& meta() {\n-    assert(itr_ != end_);\n-    return itr_->second.meta();\n+private:\n+  typename Map::const_iterator next_;\n+  typename Map::const_iterator current_;\n+  typename Map::const_iterator end_;\n+};\n+\n+class SchemaMetadataField {\n+public:\n+  typedef std::map<std::string, SchemaMetadataField> Map;\n+\n+  SchemaMetadataField() {}\n+\n+  SchemaMetadataField(const std::string& name)\n+    : name_(name) {}\n+\n+  SchemaMetadataField(const std::string& name,\n+                      const Value& value,\n+                      const SharedRefPtr<RefBuffer>& buffer)\n+    : name_(name)\n+    , value_(value)\n+    , buffer_(buffer) {}\n+\n+  const std::string& name() const {\n+    return name_;\n   }\n \n-  const typename C::mapped_type& model() {\n-    assert(itr_ != end_);\n-    return itr_->second;\n+  const Value* value() const {\n+    return &value_;\n   }\n \n private:\n-  bool first_next_;\n-  typename C::const_iterator itr_;\n-  const typename C::const_iterator end_;\n+  std::string name_;\n+  Value value_;\n+  SharedRefPtr<RefBuffer> buffer_;\n };\n \n-class ColumnMetadata {\n+class SchemaMetadataFieldIterator : public Iterator {\n public:\n-  ColumnMetadata();\n-\n-  static ColumnMetadata from_schema_row(const Row* schema_row);\n-  static std::string keyspace_name_from_row(const Row* schema_row);\n-  static std::string column_family_name_from_row(const Row* schema_row);\n-  static std::string name_from_row(const Row* schema_row);\n-\n-  class ColumnTypeMapper {\n-  public:\n-    ColumnTypeMapper();\n-    CassColumnType operator[](const std::string& col_type) const;\n-  private:\n-    typedef std::map<std::string, CassColumnType> NameTypeMap;\n-    NameTypeMap name_type_map_;\n-  };\n+  typedef SchemaMapIteratorImpl<SchemaMetadataField> Map;\n \n-  std::string name_;\n-  int component_index_;\n-  std::string index_name_;\n-  std::string index_options_;\n-  std::string index_type_;\n-  CassColumnType kind_;\n-  TypeDescriptor type_;\n-  std::string validator_;\n+  SchemaMetadataFieldIterator(const Map& map)\n+    : Iterator(CASS_ITERATOR_TYPE_SCHEMA_META_FIELD)\n+    , impl_(map) {}\n \n-  const static ColumnTypeMapper type_map_;\n+  virtual bool next() { return impl_.next(); }\n+  const SchemaMetadataField* field() const { return impl_.item(); }\n \n private:\n-  void options_from_json(const BufferPiece& options_json);\n+  SchemaMapIteratorImpl<SchemaMetadataField> impl_;\n };\n \n-class ColumnModel {\n+class SchemaMetadata {\n public:\n-  typedef ColumnMetadata meta_type;\n+  SchemaMetadata(CassSchemaMetaType type)\n+    : type_(type) {}\n \n-  void set_meta(const meta_type& cfm) { cf_meta_ = cfm; }\n-  const meta_type& meta() const { return cf_meta_; }\n+  CassSchemaMetaType type() const { return type_; }\n+\n+  virtual const SchemaMetadata* get_entry(const std::string& name) const = 0;\n+  virtual Iterator* iterator() const = 0;\n+\n+  const SchemaMetadataField* get_field(const std::string& name) const;\n+  Iterator* iterator_fields() const { return new SchemaMetadataFieldIterator(fields_); }\n+\n+protected:\n+  void add_field(const SharedRefPtr<RefBuffer>& buffer, const Row* row, const std::string& name);\n+  void add_json_list_field(int version, const Row* row, const std::string& name);\n+  void add_json_map_field(int version, const Row* row, const std::string& name);\n+\n+  SchemaMetadataField::Map fields_;\n \n private:\n-  meta_type cf_meta_;\n+  const CassSchemaMetaType type_;\n };\n \n-typedef std::map<std::string, ColumnModel> ColumnModelMap;\n-typedef ModelMapIterator<ColumnModelMap, CASS_ITERATOR_TYPE_COL_META> ColumnIterator;\n+class SchemaMetadataIterator : public Iterator {\n+public:\n+  SchemaMetadataIterator()\n+    : Iterator(CASS_ITERATOR_TYPE_SCHEMA_META) {}\n+  virtual const SchemaMetadata* meta() const = 0;\n+};\n \n-class ColumnFamilyMetadata {\n+template<class T>\n+class SchemaMetadataIteratorImpl : public SchemaMetadataIterator {\n public:\n-  ColumnFamilyMetadata();\n+  typedef typename SchemaMapIteratorImpl<T>::Map Map;\n \n-  static ColumnFamilyMetadata from_schema_row(const Row* schema_row);\n-  static std::string keyspace_name_from_row(const Row* schema_row);\n-  static std::string name_from_row(const Row* schema_row);\n+  SchemaMetadataIteratorImpl(const Map& map)\n+    : impl_(map) {}\n \n-  std::string name_;\n-  double bloom_filter_fp_chance_;\n-  std::string caching_;\n-  CassUuid cf_id_;\n-  std::string column_aliases_;\n-  std::string comment_;\n-  std::string compaction_strategy_class_;\n-  std::string compaction_strategy_options_;\n-  std::string comparator_;\n-  std::string compression_parameters_;\n-  int default_time_to_live_;\n-  std::string default_validator_;\n-  std::map<std::string, cass_int64_t> dropped_columns_;\n-  int gc_grace_seconds_;\n-  int index_interval_;\n-  cass_bool_t is_dense_;\n-  std::string key_aliases_;\n-  std::string key_validator_;\n-  double local_read_repair_chance_;\n-  int max_compaction_threshold_;\n-  int max_index_interval_;\n-  int memtable_flush_period_in_ms_;\n-  int min_compaction_threshold_;\n-  int min_index_interval_;\n-  double read_repair_chance_;\n-  std::string speculative_retry_;\n-  std::string subcomparator_;\n-  std::string type_;\n-  std::string value_alias_;\n+  virtual bool next() { return impl_.next(); }\n+  virtual const SchemaMetadata* meta() const { return impl_.item(); }\n+\n+private:\n+  SchemaMapIteratorImpl<T> impl_;\n };\n \n-class ColumnFamilyModel {\n+class ColumnMetadata : public SchemaMetadata {\n public:\n-  typedef ColumnFamilyMetadata meta_type;\n+  typedef std::map<std::string, ColumnMetadata> Map;\n \n-  void set_meta(const meta_type& cfm) { cf_meta_ = cfm; }\n-  const meta_type& meta() const { return cf_meta_; }\n+  ColumnMetadata()\n+    : SchemaMetadata(CASS_SCHEMA_META_TYPE_COLUMN) {}\n \n-  void update_column_family(const Row* schema_row);\n-  void update_column(const Row* schema_row);\n-  void update_columns(const std::vector<Row> col_rows);\n-  const ColumnModel* get_column(const std::string& col_name) const;\n-  const ColumnModelMap& columns() const { return columns_; }\n+  virtual const SchemaMetadata* get_entry(const std::string& name) const {\n+    return NULL;\n+  }\n+  virtual Iterator* iterator() const { return NULL; }\n \n-private:\n-  meta_type cf_meta_;\n-  ColumnModelMap columns_;\n+  void update(int version, const SharedRefPtr<RefBuffer>& buffer, const Row* row);\n };\n \n-typedef std::map<std::string, ColumnFamilyModel> ColumnFamilyModelMap;\n-typedef ModelMapIterator<ColumnFamilyModelMap, CASS_ITERATOR_TYPE_CF_META> ColumnFamilyIterator;\n-\n-class KeyspaceMetadata {\n+class TableMetadata : public SchemaMetadata {\n public:\n-  KeyspaceMetadata();\n+  typedef std::map<std::string, TableMetadata> Map;\n+  typedef SchemaMetadataIteratorImpl<ColumnMetadata> ColumnIterator;\n \n-  static KeyspaceMetadata from_schema_row(const Row* schema_row);\n-  static std::string name_from_row(const Row* schema_row);\n+  TableMetadata()\n+    : SchemaMetadata(CASS_SCHEMA_META_TYPE_TABLE) {}\n \n-  std::string name_;\n-  cass_bool_t durable_writes_;\n-  std::string strategy_class_;\n-  std::map<std::string,std::string> strategy_options_;\n-  std::string strategy_options_json_;\n+  virtual const SchemaMetadata* get_entry(const std::string& name) const;\n+  virtual Iterator* iterator() const { return new ColumnIterator(columns_); }\n+\n+  ColumnMetadata* get_or_create(const std::string& name) { return &columns_[name]; }\n+  void update(int version, const SharedRefPtr<RefBuffer>& buffer, const Row* row);\n+\n+private:\n+  ColumnMetadata::Map columns_;\n };\n \n-class KeyspaceModel {\n+class KeyspaceMetadata : public SchemaMetadata {\n public:\n-  typedef KeyspaceMetadata meta_type;\n+  typedef std::map<std::string, KeyspaceMetadata> Map;\n+  typedef SchemaMetadataIteratorImpl<TableMetadata> TableIterator;\n+\n+  KeyspaceMetadata()\n+    : SchemaMetadata(CASS_SCHEMA_META_TYPE_KEYSPACE) {}\n \n-  void set_meta(const meta_type& ksm) { ks_meta_ = ksm; }\n-  const meta_type& meta() const { return ks_meta_; }\n+  virtual const SchemaMetadata* get_entry(const std::string& name) const;\n+  virtual Iterator* iterator() const { return new TableIterator(tables_); }\n \n-  void update_column_family(const Row* schema_row);\n-  void update_column_family(const Row* schema_row, const std::vector<Row> col_rows);\n-  void update_column(const Row* schema_row);\n-  void drop_column_family(const std::string& cf_name) { cfs_.erase(cf_name); }\n-  const ColumnFamilyModel* get_column_family(const std::string& cf_name) const;\n-  const ColumnFamilyModelMap& column_families() const { return cfs_; }\n+  TableMetadata* get_or_create(const std::string& name) { return &tables_[name]; }\n+  void update(int version, const SharedRefPtr<RefBuffer>& buffer, const Row* row);\n+  void drop_table(const std::string& table_name);\n \n private:\n-  meta_type ks_meta_;\n-  ColumnFamilyModelMap cfs_;\n+  TableMetadata::Map tables_;\n };\n \n-typedef std::map<std::string, KeyspaceModel> KeyspaceModelMap;\n-typedef ModelMapIterator<KeyspaceModelMap, CASS_ITERATOR_TYPE_KS_META> KeyspaceIterator;\n-\n-class SchemaModel {\n+class Schema {\n public:\n-  void update_keyspace(const Row* schema_row);\n-  void update_column_family(const Row* schema_row);\n-  void update_column_family(const Row* schema_row, const std::vector<Row> col_rows);\n-  void update_column(const Row* schema_row);\n-  void drop_keyspace(const std::string& ks_name) { keyspaces_.erase(ks_name); }\n-  void drop_column_family(const std::string& ks_name, const std::string& cf_name);\n-  const KeyspaceModel* get_keyspace(const std::string& ks_name) const;\n-  const KeyspaceModelMap& keyspaces() const { return keyspaces_; }\n+  typedef SchemaMetadataIteratorImpl<KeyspaceMetadata> KeyspaceIterator;\n+\n+  Schema()\n+    : keyspaces_(new KeyspaceMetadata::Map)\n+    , protocol_version_(0) {}\n+\n+  void set_protocol_version(int version) {\n+    protocol_version_ = version;\n+  }\n+\n+  const SchemaMetadata* get(const std::string& name) const;\n+  Iterator* iterator() const { return new KeyspaceIterator(*keyspaces_); }\n+\n+  KeyspaceMetadata* get_or_create(const std::string& name) { return &(*keyspaces_)[name]; }\n+  void update_keyspaces(ResultResponse* result);\n+  void update_tables(ResultResponse* result);\n+  void update_columns(ResultResponse* result);\n+  void drop_keyspace(const std::string& keyspace_name);\n+  void drop_table(const std::string& keyspace_name, const std::string& table_name);\n+  void clear();\n \n private:\n-  KeyspaceModelMap keyspaces_;\n+  // Really coarse grain copy-on-write. This could be made\n+  // more fine grain, but it might not be worth the work.\n+  CopyOnWritePtr<KeyspaceMetadata::Map> keyspaces_;\n+\n+  // Only used internally on a single thread, there\'s\n+  // no need for copy-on-write.\n+  int protocol_version_;\n };\n \n } // namespace cass\ndiff --git a/src/session.cpp b/src/session.cpp\nindex 466446d2..ec38e2c7 100644\n--- a/src/session.cpp\n+++ b/src/session.cpp\n@@ -49,8 +49,8 @@ CassFuture* cass_session_execute_batch(CassSession* session, const CassBatch* ba\n   return CassFuture::to(session->execute(batch->from()));\n }\n \n-CassSchemaMetadata* cass_session_get_schema_meta(CassSession* session) {\n-  return CassSchemaMetadata::to(session->get_schema_meta());\n+const CassSchema* cass_session_get_schema(CassSession* session) {\n+  return CassSchema::to(session->copy_schema());\n }\n \n } // extern "C"\ndiff --git a/src/session.hpp b/src/session.hpp\nindex 2cd53657..64dbdeb8 100644\n--- a/src/session.hpp\n+++ b/src/session.hpp\n@@ -99,9 +99,8 @@ public:\n   Future* prepare(const char* statement, size_t length);\n   Future* execute(const Request* statement);\n \n-  SchemaModel* get_schema_meta() {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    return new SchemaModel(schema_meta_);\n+  const Schema* copy_schema() const {\n+    return new Schema(schema_);\n   }\n \n private:\n@@ -123,6 +122,10 @@ private:\n private:\n   friend class ControlConnection;\n \n+  Schema& schema() {\n+    return schema_;\n+  }\n+\n   void on_control_connection_ready();\n   void on_control_connection_error(CassError code, const std::string& message);\n \n@@ -131,38 +134,6 @@ private:\n   void on_up(SharedRefPtr<Host> host);\n   void on_down(SharedRefPtr<Host> host, bool is_critical_failure);\n \n-  void update_keyspace(const Row* schema_row) {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    schema_meta_.update_keyspace(schema_row);\n-  }\n-\n-  void update_column_family(const Row* schema_row) {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    schema_meta_.update_column_family(schema_row);\n-  }\n-\n-  void update_column_family(const Row* schema_row,\n-                            const std::vector<Row>& column_rows) {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    schema_meta_.update_column_family(schema_row, column_rows);\n-  }\n-\n-  void update_column(const Row* schema_row) {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    schema_meta_.update_column(schema_row);\n-  }\n-\n-  void drop_keyspace(const std::string& keyspace_name) {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    schema_meta_.drop_keyspace(keyspace_name);\n-  }\n-\n-  void drop_column_family(const std::string& keyspace_name,\n-                          const std::string& column_family_name) {\n-    ScopedMutex l(&schema_meta_mutex_);\n-    schema_meta_.drop_column_family(keyspace_name, column_family_name);\n-  }\n-\n private:\n   typedef std::vector<SharedRefPtr<IOWorker> > IOWorkerVec;\n \n@@ -180,7 +151,7 @@ private:\n   int pending_pool_count_;\n   int pending_workers_count_;\n   int current_io_worker_;\n-  SchemaModel schema_meta_;\n+  Schema schema_;\n   uv_mutex_t schema_meta_mutex_;\n };\n \ndiff --git a/src/statement.hpp b/src/statement.hpp\nindex d0c25802..9ea31597 100644\n--- a/src/statement.hpp\n+++ b/src/statement.hpp\n@@ -163,7 +163,7 @@ public:\n     CASS_VALUE_CHECK_INDEX(index);\n     Buffer buf(4 + custom.output_size);\n     size_t pos = buf.encode_int32(0, custom.output_size);\n-    *(custom.output) = reinterpret_cast<uint8_t*>(const_cast<char*>(buf.data() + pos));\n+    *(custom.output) = reinterpret_cast<uint8_t*>(buf.data() + pos);\n     values_[index] = buf;\n     return CASS_OK;\n   }\ndiff --git a/src/types.hpp b/src/types.hpp\nindex 77e91327..1e525956 100644\n--- a/src/types.hpp\n+++ b/src/types.hpp\n@@ -19,6 +19,7 @@\n \n #include "cassandra.h"\n #include "cluster.hpp"\n+#include "schema_metadata.hpp"\n #include "session.hpp"\n #include "statement.hpp"\n #include "future.hpp"\n@@ -58,7 +59,9 @@ EXTERNAL_TYPE(cass::BufferCollection, CassCollection);\n EXTERNAL_TYPE(cass::Iterator, CassIterator);\n EXTERNAL_TYPE(cass::Row, CassRow);\n EXTERNAL_TYPE(cass::Value, CassValue);\n-EXTERNAL_TYPE(cass::SchemaModel, CassSchemaMetadata);\n+EXTERNAL_TYPE(cass::Schema, CassSchema);\n+EXTERNAL_TYPE(cass::SchemaMetadata, CassSchemaMeta);\n+EXTERNAL_TYPE(cass::SchemaMetadataField, CassSchemaMetaField);\n \n }\n \ndiff --git a/src/value.hpp b/src/value.hpp\nindex a609e413..ade776e9 100644\n--- a/src/value.hpp\n+++ b/src/value.hpp\n@@ -27,35 +27,40 @@ class Value {\n public:\n   Value()\n       : type_(CASS_VALUE_TYPE_UNKNOWN)\n-      , def_(NULL)\n+      , primary_type_(CASS_VALUE_TYPE_UNKNOWN)\n+      , secondary_type_(CASS_VALUE_TYPE_UNKNOWN)\n       , count_(0) {}\n \n   Value(CassValueType type, char* data, size_t size)\n       : type_(type)\n-      , def_(NULL)\n+      , primary_type_(CASS_VALUE_TYPE_UNKNOWN)\n+      , secondary_type_(CASS_VALUE_TYPE_UNKNOWN)\n       , count_(0)\n       , buffer_(data, size) {}\n \n-  Value(const ColumnDefinition* definition, int32_t count, char* data, size_t size)\n-    : type_(static_cast<CassValueType>(definition->type))\n-    , def_(definition)\n+  Value(CassValueType type, CassValueType primary_type, CassValueType secondary_type,\n+        int32_t count, char* data, size_t size)\n+      : type_(type)\n+      , primary_type_(primary_type)\n+      , secondary_type_(secondary_type)\n+      , count_(count)\n+      , buffer_(data, size) {}\n+\n+  Value(const ColumnDefinition* def, int32_t count, char* data, size_t size)\n+    : type_(static_cast<CassValueType>(def->type))\n+    , primary_type_(static_cast<CassValueType>(def->collection_primary_type))\n+    , secondary_type_(static_cast<CassValueType>(def->collection_secondary_type))\n     , count_(count)\n     , buffer_(data, size) {}\n \n   CassValueType type() const { return type_; }\n \n   CassValueType primary_type() const {\n-    if (def_ == NULL) {\n-      return CASS_VALUE_TYPE_UNKNOWN;\n-    }\n-    return static_cast<CassValueType>(def_->collection_primary_type);\n+    return primary_type_;\n   }\n \n   CassValueType secondary_type() const {\n-    if (def_ == NULL) {\n-      return CASS_VALUE_TYPE_UNKNOWN;\n-    }\n-    return static_cast<CassValueType>(def_->collection_secondary_type);\n+    return secondary_type_;\n   }\n \n   bool is_null() const {\n@@ -75,7 +80,8 @@ public:\n \n private:\n   CassValueType type_;\n-  const ColumnDefinition* def_;\n+  CassValueType primary_type_;\n+  CassValueType secondary_type_;\n   int32_t count_;\n   BufferPiece buffer_;\n };\n', 'commit_subject': 'Schema metadata refactor', 'repo_name': 'datastax/cpp-driver', 'committer': {'name': 'mpenick', 'email': 'b82b175c3e1c5f829d1b3019fdc6cf43b2042f4c@datastax.com', 'time_sec': '1414710138', 'tz_offset': '-420', 'date': {'seconds': '1414710138'}}, 'commit_tree': '636f3714a9e13bf66bcf69c298ba4c676319bbda', 'commit_message': 'Schema metadata refactor\n', 'language_name': 'Ruby', 'license': 'apache-2.0', 'hunks': '@@ -27,35 +27,40 @@ class Value {\n public:\n   Value()\n       : type_(CASS_VALUE_TYPE_UNKNOWN)\n-      , def_(NULL)\n+      , primary_type_(CASS_VALUE_TYPE_UNKNOWN)\n+      , secondary_type_(CASS_VALUE_TYPE_UNKNOWN)\n       , count_(0) {}\n \n   Value(CassValueType type, char* data, size_t size)\n       : type_(type)\n-      , def_(NULL)\n+      , primary_type_(CASS_VALUE_TYPE_UNKNOWN)\n+      , secondary_type_(CASS_VALUE_TYPE_UNKNOWN)\n       , count_(0)\n       , buffer_(data, size) {}\n \n-  Value(const ColumnDefinition* definition, int32_t count, char* data, size_t size)\n-    : type_(static_cast<CassValueType>(definition->type))\n-    , def_(definition)\n+  Value(CassValueType type, CassValueType primary_type, CassValueType secondary_type,\n+        int32_t count, char* data, size_t size)\n+      : type_(type)\n+      , primary_type_(primary_type)\n+      , secondary_type_(secondary_type)\n+      , count_(count)\n+      , buffer_(data, size) {}\n+\n+  Value(const ColumnDefinition* def, int32_t count, char* data, size_t size)\n+    : type_(static_cast<CassValueType>(def->type))\n+    , primary_type_(static_cast<CassValueType>(def->collection_primary_type))\n+    , secondary_type_(static_cast<CassValueType>(def->collection_secondary_type))\n     , count_(count)\n     , buffer_(data, size) {}\n \n   CassValueType type() const { return type_; }\n \n   CassValueType primary_type() const {\n-    if (def_ == NULL) {\n-      return CASS_VALUE_TYPE_UNKNOWN;\n-    }\n-    return static_cast<CassValueType>(def_->collection_primary_type);\n+    return primary_type_;\n   }\n \n   CassValueType secondary_type() const {\n-    if (def_ == NULL) {\n-      return CASS_VALUE_TYPE_UNKNOWN;\n-    }\n-    return static_cast<CassValueType>(def_->collection_secondary_type);\n+    return secondary_type_;\n   }\n \n   bool is_null() const {\n@@ -75,7 +80,8 @@ public:\n \n private:\n   CassValueType type_;\n-  const ColumnDefinition* def_;\n+  CassValueType primary_type_;\n+  CassValueType secondary_type_;\n   int32_t count_;\n   BufferPiece buffer_;\n };\n', 'addition_count': 20, 'deletion_count': 14, 'src_file': 'a/src/value.hpp', 'tgt_file': 'b/src/value.hpp', 'file_extension': '.hpp', 'before_file': '/*\n  Copyright (c) DataStax, Inc.\n\n  Licensed under the Apache License, Version 2.0 (the "License");\n  you may not use this file except in compliance with the License.\n  You may obtain a copy of the License at\n\n  http://www.apache.org/licenses/LICENSE-2.0\n\n  Unless required by applicable law or agreed to in writing, software\n  distributed under the License is distributed on an "AS IS" BASIS,\n  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  See the License for the specific language governing permissions and\n  limitations under the License.\n*/\n\n#ifndef DATASTAX_INTERNAL_VALUE_HPP\n#define DATASTAX_INTERNAL_VALUE_HPP\n\n#include "cassandra.h"\n#include "decoder.hpp"\n#include "external.hpp"\n#include "result_metadata.hpp"\n#include "string_ref.hpp"\n\nnamespace datastax { namespace internal { namespace core {\npublic:\n  Value()\n      : type_(CASS_VALUE_TYPE_UNKNOWN)\n      , def_(NULL)\n      , count_(0) {}\n\n  Value(CassValueType type, char* data, size_t size)\n      : type_(type)\n      , def_(NULL)\n      , count_(0)\n      , buffer_(data, size) {}\n\n  Value(const ColumnDefinition* definition, int32_t count, char* data, size_t size)\n    : type_(static_cast<CassValueType>(definition->type))\n    , def_(definition)\n    , count_(count)\n    , buffer_(data, size) {}\n\n  CassValueType type() const { return type_; }\n\n  CassValueType primary_type() const {\n    if (def_ == NULL) {\n      return CASS_VALUE_TYPE_UNKNOWN;\n    }\n    return static_cast<CassValueType>(def_->collection_primary_type);\n  }\n\n  CassValueType secondary_type() const {\n    if (def_ == NULL) {\n      return CASS_VALUE_TYPE_UNKNOWN;\n    }\n    return static_cast<CassValueType>(def_->collection_secondary_type);\n  }\n\n  bool is_null() const {\n    if (!primary) {\n      return CASS_VALUE_TYPE_UNKNOWN;\n    }\n    return primary->value_type();\n  }\n\n  const DataType::ConstPtr& primary_data_type() const {\n    if (!data_type_ || !data_type_->is_collection()) {\n      return DataType::NIL;\n    }\n    const CollectionType::ConstPtr& collection_type(data_type_);\n    if (collection_type->types().size() < 1) {\n      return DataType::NIL;\n\nprivate:\n  CassValueType type_;\n  const ColumnDefinition* def_;\n  int32_t count_;\n  BufferPiece buffer_;\n};\n    }\n    return secondary->value_type();\n  }\n\n  const DataType::ConstPtr& secondary_data_type() const {\n    if (!data_type_ || !data_type_->is_map()) {\n      return DataType::NIL;\n    }\n    const CollectionType::ConstPtr& collection_type(data_type_);\n    if (collection_type->types().size() < 2) {\n      return DataType::NIL;\n    }\n    return collection_type->types()[1];\n  }\n\n  bool is_null() const { return is_null_; }\n\n  bool is_collection() const {\n    if (!data_type_) return false;\n    return data_type_->is_collection();\n  }\n\n  bool is_map() const {\n    if (!data_type_) return false;\n    return data_type_->is_map();\n  }\n\n  bool is_tuple() const {\n    if (!data_type_) return false;\n    return data_type_->is_tuple();\n  }\n\n  bool is_user_type() const {\n    if (!data_type_) return false;\n    return data_type_->is_user_type();\n  }\n\n  int32_t count() const { return count_; }\n\n  StringRef to_string_ref() const {\n    if (is_null()) return StringRef();\n    return decoder_.as_string_ref();\n  }\n\n  String to_string() const { return to_string_ref().to_string(); }\n\n  bool as_bool() const;\n  int32_t as_int32() const;\n  CassUuid as_uuid() const;\n  StringVec as_stringlist() const;\n\nprivate:\n  friend class Decoder;\n  bool update(const Decoder& decoder);\n\nprivate:\n  DataType::ConstPtr data_type_;\n  int32_t count_;\n  Decoder decoder_;\n  bool is_null_;\n};\n\ntypedef Vector<Value> OutputValueVec;\n\n}}} // namespace datastax::internal::core\n\nEXTERNAL_TYPE(datastax::internal::core::Value, CassValue)\n\n#endif\n', 'message': 'Schema metadata refactor\n', 'author_name': 'mpenick', 'lang': 'hpp'}