Repository: cassandra-rs/cassandra-rs (language: rust)

Issue:
List data cannot be correctly displayed in the terminal
I tried using simple.rs to generate information and apply it. 
But when I generate a new field and specify the data type as list, the `println!` on the terminal is `[<error>].`
How do I display the correct list information on the terminal?


Discussion / hints:
Hi @pili2026 - the `simple.rs` example is passing in our Travis tests, so I don't believe there's a bug.

Can you share the code you are running, e.g. in a Gist or on https://play.rust-lang.org/ ?
@kw217 ,Thank you for your answer.The code I am using is here.
https://gist.github.com/pili2026/0d98e72833fd90ad0f7533205f21d1cf
This is my table content.
https://imgur.com/a/d65ltzJ

and my execution result is here.
https://imgur.com/a/7pjvYkK

When the execution is complete, I want to print out the fields for "addresses" and "phone_numbers".But the result is `{"home" => <udt>, }` and `[<error>]`.So maybe it's my code problem? or something is it wrong?
The `<error>` string indicates that the driver encountered an error while iterating through the contents of the set or list. Instead of just printing the entire row, try extracting the `phone_numbers` column and iterating over the values in it, and report the actual error that you get when inspecting Paul and Jeremy. This will tell you a lot more about what the actual problem is.

Also - what is the table schema - in particular, what is the type of the `phone_numbers` column?
The phone_numbers type is list.
https://imgur.com/a/Ay51Aes

If I want to parse the `list` and the type of `frozen` (`phone_numbers` and `addresses` field), use `List` and `SetIterator`? How is the List used?

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 68ea0f3..6984a4f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,15 @@ This file's format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/). The
 version number is tracked in the file `VERSION`.
 
+## [0.13.2] - ??
+- Avoid possible segfaults, by returning `None` where possible, otherwise
+  panicking. In particular, a collection field set to NULL now returns `None`
+  rather than faulting.
+- Make `SchemaMeta::get_keyspace_by_name` work (fix string handling bug).
+- Allow using the `SetIterator` for lists and tuples. Previously these
+  could not be enumerated at all!
+- For convenience, support `bind()` for `List`s.
+
 ## [0.13.1] - 2019-01-08
 - Fix `stmt!()` not working if `Statement` was not imported.
 
diff --git a/Cargo.toml b/Cargo.toml
index 6ac752b..835b73e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,7 +8,7 @@ keywords = [ "Cassandra", "binding", "CQL", "client", "database" ]
 categories = [ "api-bindings", "database", "external-ffi-bindings", "asynchronous" ]
 license = "Apache-2.0"
 name = "cassandra-cpp"
-version = "0.13.1"
+version = "0.13.2"
 authors = ["Tupshin Harper <tupshin@tupshin.com>", "Keith Wansbrough <Keith.Wansbrough@metaswitch.com>"]
 build = "build.rs"
 
diff --git a/examples/collections.rs b/examples/collections.rs
new file mode 100644
index 0000000..06d5524
--- /dev/null
+++ b/examples/collections.rs
@@ -0,0 +1,75 @@
+//! Simple example demonstrating the use of set/map/list values in both
+//! bindings and results.
+#[macro_use(stmt)]
+extern crate cassandra_cpp;
+extern crate futures;
+
+use cassandra_cpp::*;
+use futures::Future;
+use std::collections::hash_map::HashMap;
+
+fn do_work(session: &Session) -> Result<()> {
+    let create_keyspace = stmt!("CREATE KEYSPACE IF NOT EXISTS testks WITH REPLICATION = { 'class': 'SimpleStrategy', 'replication_factor': 1 };");
+    let create_table = stmt!("CREATE TABLE IF NOT EXISTS testks.user (first_name text PRIMARY KEY, addresses map<text, text>, email set<text>, last_name text, phone_numbers list<text>, title int);");
+    let mut insert_data = stmt!("INSERT INTO testks.user (first_name, addresses, email, last_name, phone_numbers, title) VALUES (?, ?, ?, ?, ?, ?);");
+    let query = stmt!("SELECT * FROM testks.user;");
+
+    session.execute(&create_keyspace).wait()?;
+
+    session.execute(&create_table).wait()?;
+
+    insert_data.bind(0, "Paul")?;
+    insert_data.bind_null(1)?;
+    let mut addresses = List::new(0);
+    addresses.append_string("george@example.com")?;
+    addresses.append_string("paul@example.com")?;
+    insert_data.bind(2, addresses)?;
+    insert_data.bind(3, "George")?;
+    let mut phones = List::new(0);
+    phones.append_string("123-456")?;
+    phones.append_string("789-012")?;
+    insert_data.bind(4, phones)?; // TODO: bind should really accept Vec<T>, and map should accept HashMap<T, U>. Requires generic CassCollection::append.
+    insert_data.bind(5, 13)?;
+    session.execute(&insert_data).wait()?;
+
+    let result = session.execute(&query).wait()?;
+
+    println!("Overall result: {}", result);
+    for row in result.iter() {
+        println!("Row: {}", row);
+
+        let first_name: String = row.get_by_name("first_name")?;
+        let addresses: HashMap<String, String> = {
+            let maybe_iter: Result<MapIterator> = row.get_by_name("addresses");
+            match maybe_iter {
+                Err(_) => HashMap::new(),
+                Ok(addresses_iter) => {
+                    addresses_iter
+                        .map(|(k, v)| Ok((k.get_string()?, v.get_string()?)))
+                        .collect::<Result<_>>()?
+                }
+            }
+        };
+        let emails_iter: SetIterator = row.get_by_name("email")?;
+        let emails: Vec<String> = emails_iter.map(|v| Ok(v.get_string()?)).collect::<Result<_>>()?;
+        let last_name: String = row.get_by_name("last_name")?;
+        let phone_numbers_iter: SetIterator = row.get_by_name("phone_numbers")?;
+        let phone_numbers: Vec<String> = phone_numbers_iter.map(|v| Ok(v.get_string()?)).collect::<Result<_>>()?;
+        let title: i32 = row.get_by_name("title")?;
+        println!(
+            " == {} {:?} {:?} {} {:?} {}",
+            first_name, addresses, emails, last_name, phone_numbers, title
+        );
+    }
+    Ok(())
+}
+
+fn main() {
+    let contact_points = "127.0.0.1";
+    let mut cluster = Cluster::default();
+    cluster.set_contact_points(contact_points).unwrap();
+    cluster.set_load_balance_round_robin();
+
+    let session = cluster.connect().unwrap();
+    do_work(&session).unwrap();
+}
diff --git a/src/cassandra/batch.rs b/src/cassandra/batch.rs
index 25d0a79..e5ede3a 100644
--- a/src/cassandra/batch.rs
+++ b/src/cassandra/batch.rs
@@ -34,7 +34,7 @@ unsafe impl Send for Batch {}
 
 impl Protected<*mut _Batch> for Batch {
     fn inner(&self) -> *mut _Batch { self.0 }
-    fn build(inner: *mut _Batch) -> Self { Batch(inner) }
+    fn build(inner: *mut _Batch) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Batch(inner) }
 }
 
 /// Custom payloads not fully supported yet
@@ -43,7 +43,7 @@ pub struct CustomPayload(*mut _CassCustomPayload);
 
 impl Protected<*mut _CassCustomPayload> for CustomPayload {
     fn inner(&self) -> *mut _CassCustomPayload { self.0 }
-    fn build(inner: *mut _CassCustomPayload) -> Self { CustomPayload(inner) }
+    fn build(inner: *mut _CassCustomPayload) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; CustomPayload(inner) }
 }
 
 impl Default for CustomPayload {
diff --git a/src/cassandra/cluster.rs b/src/cassandra/cluster.rs
index c90871f..9cc24b9 100644
--- a/src/cassandra/cluster.rs
+++ b/src/cassandra/cluster.rs
@@ -92,7 +92,7 @@ impl Drop for Cluster {
 
 impl Protected<*mut _Cluster> for Cluster {
     fn inner(&self) -> *mut _Cluster { self.0 }
-    fn build(inner: *mut _Cluster) -> Self { Cluster(inner) }
+    fn build(inner: *mut _Cluster) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Cluster(inner) }
 }
 
 impl Default for Cluster {
diff --git a/src/cassandra/collection.rs b/src/cassandra/collection.rs
index 8402ee8..6da7092 100644
--- a/src/cassandra/collection.rs
+++ b/src/cassandra/collection.rs
@@ -121,17 +121,17 @@ unsafe impl Send for List {}
 
 impl Protected<*mut _CassCollection> for List {
     fn inner(&self) -> *mut _CassCollection { self.0 }
-    fn build(inner: *mut _CassCollection) -> Self { List(inner) }
+    fn build(inner: *mut _CassCollection) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; List(inner) }
 }
 
 impl Protected<*mut _CassCollection> for Map {
     fn inner(&self) -> *mut _CassCollection { self.0 }
-    fn build(inner: *mut _CassCollection) -> Self { Map(inner) }
+    fn build(inner: *mut _CassCollection) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Map(inner) }
 }
 
 impl Protected<*mut _CassCollection> for Set {
     fn inner(&self) -> *mut _CassCollection { self.0 }
-    fn build(inner: *mut _CassCollection) -> Self { Set(inner) }
+    fn build(inner: *mut _CassCollection) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Set(inner) }
 }
 
 
@@ -143,14 +143,14 @@ impl CassCollection for List {
     type Value = _CassCollection;
 
     /// create a new list
-    fn new(item_count: usize) -> Self { unsafe { List(cass_collection_new(CASS_COLLECTION_TYPE_LIST, item_count)) } }
+    fn new(item_count: usize) -> Self { unsafe { List::build(cass_collection_new(CASS_COLLECTION_TYPE_LIST, item_count)) } }
 
     fn new_from_data_type(value: DataType, item_count: usize) -> Self {
         unsafe { List(cass_collection_new_from_data_type(value.inner(), item_count)) }
     }
 
     /// Gets the data type of a collection.
-    fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_collection_data_type(self.inner())) } }
+    fn data_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_collection_data_type(self.inner())) } }
 
 
     /// Appends a "tinyint" to the collection.
@@ -276,7 +276,7 @@ impl CassCollection for Set {
         unsafe { Set(cass_collection_new_from_data_type(value.inner(), item_count)) }
     }
     /// Gets the data type of a collection.
-    fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_collection_data_type(self.inner())) } }
+    fn data_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_collection_data_type(self.inner())) } }
 
 
     /// Appends a "tinyint" to the collection.
@@ -399,7 +399,7 @@ impl CassCollection for Map {
     }
 
     /// Gets the data type of a collection.
-    fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_collection_data_type(self.inner())) } }
+    fn data_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_collection_data_type(self.inner())) } }
 
 
     /// Appends a "tinyint" to the collection.
diff --git a/src/cassandra/data_type.rs b/src/cassandra/data_type.rs
index 729d86a..e546259 100644
--- a/src/cassandra/data_type.rs
+++ b/src/cassandra/data_type.rs
@@ -33,7 +33,7 @@ use std::ffi::CString;
 #[derive(Debug)]
 pub struct DataType(*mut _CassDataType);
 #[derive(Debug)]
-pub struct ConstDataType(pub *const _CassDataType);
+pub struct ConstDataType(*const _CassDataType);
 
 // The underlying C types have no thread-local state, but do not support access
 // from multiple threads: https://datastax.github.io/cpp-driver/topics/#thread-safety
@@ -42,7 +42,12 @@ unsafe impl Send for ConstDataType {}
 
 impl Protected<*mut _CassDataType> for DataType {
     fn inner(&self) -> *mut _CassDataType { self.0 }
-    fn build(inner: *mut _CassDataType) -> Self { DataType(inner) }
+    fn build(inner: *mut _CassDataType) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; DataType(inner) }
+}
+
+impl Protected<*const _CassDataType> for ConstDataType {
+    fn inner(&self) -> *const _CassDataType { self.0 }
+    fn build(inner: *const _CassDataType) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; ConstDataType(inner) }
 }
 
 impl Drop for DataType {
@@ -57,9 +62,9 @@ impl DataType {
     pub fn new(value_type: ValueType) -> Self { unsafe { DataType(cass_data_type_new(value_type.inner())) } }
 
     /// Creates a new data type from an existing data type.
+    // TODO: can return NULL
     pub fn new_user_type(&self) -> UserType { unsafe { UserType::build(cass_user_type_new_from_data_type(self.0)) } }
 
-
     /// Creates a new data type from an existing data type.
     pub fn new_from_existing(&self) -> Self { unsafe { DataType(cass_data_type_new_from_existing(self.0)) } }
 
@@ -165,7 +170,8 @@ impl DataType {
     ///
     /// <b>Note:</b> Only valid for UDT, tuple and collection data types.
     pub fn sub_data_type(&self, index: usize) -> ConstDataType {
-        unsafe { ConstDataType(cass_data_type_sub_data_type(self.0, index)) }
+        // TODO: can return NULL
+        unsafe { ConstDataType::build(cass_data_type_sub_data_type(self.0, index)) }
     }
 
     /// Gets the sub-data type of a UDT (user defined type) at the specified index.
@@ -175,7 +181,8 @@ impl DataType {
         where S: Into<String> {
         unsafe {
             let name_cstr = CString::new(name.into()).expect("must be utf8");
-            ConstDataType(cass_data_type_sub_data_type_by_name(data_type.0,
+            // TODO: can return NULL
+            ConstDataType::build(cass_data_type_sub_data_type_by_name(data_type.0,
                                                                name_cstr
                                                                    .as_ptr()))
         }
@@ -281,7 +288,8 @@ impl DataType {
     //    {
     //        unsafe {
     //            let name = CString::new(name.into()).unwrap();
-    //            ConstDataType(cass_data_type_sub_data_type_by_name_n(data_type.0,
+    //            // TODO: can return NULL
+    //            ConstDataType::build(cass_data_type_sub_data_type_by_name_n(data_type.0,
     //                                                                 name.as_ptr(),
     //                                                                 name.as_bytes().len() as u64))
     //        }
diff --git a/src/cassandra/iterator.rs b/src/cassandra/iterator.rs
index 503755d..fbae590 100644
--- a/src/cassandra/iterator.rs
+++ b/src/cassandra/iterator.rs
@@ -74,7 +74,7 @@ impl Iterator for UserTypeIterator {
         unsafe {
             match cass_iterator_next(self.0) {
                 cass_false => None,
-                cass_true => Some(ConstDataType(cass_iterator_get_user_type(self.0))),
+                cass_true => Some(ConstDataType::build(cass_iterator_get_user_type(self.0))),
             }
         }
     }
@@ -219,47 +219,47 @@ impl Iterator for FieldIterator {
 
 impl Protected<*mut _CassIterator> for UserTypeIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { UserTypeIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; UserTypeIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for AggregateIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { AggregateIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; AggregateIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for FunctionIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { FunctionIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; FunctionIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for KeyspaceIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { KeyspaceIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; KeyspaceIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for FieldIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { FieldIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; FieldIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for ColumnIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { ColumnIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; ColumnIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for TableIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { TableIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; TableIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for MapIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { MapIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; MapIterator(inner) }
 }
 
 impl Protected<*mut _CassIterator> for SetIterator {
     fn inner(&self) -> *mut _CassIterator { self.0 }
-    fn build(inner: *mut _CassIterator) -> Self { SetIterator(inner) }
+    fn build(inner: *mut _CassIterator) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; SetIterator(inner) }
 }
 
 
diff --git a/src/cassandra/policy/retry.rs b/src/cassandra/policy/retry.rs
index 1e8990c..8d0e78e 100644
--- a/src/cassandra/policy/retry.rs
+++ b/src/cassandra/policy/retry.rs
@@ -16,12 +16,12 @@ unsafe impl Send for RetryPolicy {}
 
 impl Protected<*mut _RetryPolicy> for RetryPolicy {
     fn inner(&self) -> *mut _RetryPolicy { self.0 }
-    fn build(inner: *mut _RetryPolicy) -> Self { RetryPolicy(inner) }
+    fn build(inner: *mut _RetryPolicy) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; RetryPolicy(inner) }
 }
 
 impl RetryPolicy {
     /// The default retry policy
-    pub fn default_new() -> Self { unsafe { RetryPolicy(cass_retry_policy_default_new()) } }
+    pub fn default_new() -> Self { unsafe { RetryPolicy::build(cass_retry_policy_default_new()) } }
 
     /// An auto-CL-downgrading consistency level
     pub fn downgrading_consistency_new() -> Self {
@@ -33,7 +33,8 @@ impl RetryPolicy {
 
     /// The a logging retry policy
     pub fn logging_new(child_retry_policy: RetryPolicy) -> Self {
-        unsafe { RetryPolicy(cass_retry_policy_logging_new(child_retry_policy.0)) }
+        // TODO: can return NULL
+        unsafe { RetryPolicy::build(cass_retry_policy_logging_new(child_retry_policy.0)) }
     }
 }
 
diff --git a/src/cassandra/prepared.rs b/src/cassandra/prepared.rs
index 35b93a4..e585b71 100644
--- a/src/cassandra/prepared.rs
+++ b/src/cassandra/prepared.rs
@@ -33,7 +33,7 @@ impl Drop for PreparedStatement {
 
 impl Protected<*const _PreparedStatement> for PreparedStatement {
     fn inner(&self) -> *const _PreparedStatement { self.0 }
-    fn build(inner: *const _PreparedStatement) -> Self { PreparedStatement(inner) }
+    fn build(inner: *const _PreparedStatement) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; PreparedStatement(inner) }
 }
 
 impl PreparedStatement {
@@ -59,7 +59,7 @@ impl PreparedStatement {
     /// Returns a reference to the data type of the parameter. Do not free
     /// this reference as it is bound to the lifetime of the prepared.
     pub fn parameter_data_type(&self, index: usize) -> ConstDataType {
-        unsafe { ConstDataType(cass_prepared_parameter_data_type(self.0, index)) }
+        unsafe { ConstDataType::build(cass_prepared_parameter_data_type(self.0, index)) }
     }
 
     /// Gets the data type of a parameter for the specified name.
@@ -69,7 +69,7 @@ impl PreparedStatement {
     pub fn parameter_data_type_by_name(&self, name: &str) -> ConstDataType {
         unsafe {
             let name_cstr = CString::new(name).expect("must be utf8");
-            ConstDataType(cass_prepared_parameter_data_type_by_name(self.0,
+            ConstDataType::build(cass_prepared_parameter_data_type_by_name(self.0,
                                                                     name_cstr.as_ptr()))
         }
     }
diff --git a/src/cassandra/result.rs b/src/cassandra/result.rs
index bce5063..1af891f 100644
--- a/src/cassandra/result.rs
+++ b/src/cassandra/result.rs
@@ -45,7 +45,7 @@ unsafe impl Send for CassResult {}
 
 impl Protected<*const _CassResult> for CassResult {
     fn inner(&self) -> *const _CassResult { self.0 }
-    fn build(inner: *const _CassResult) -> Self { CassResult(inner) }
+    fn build(inner: *const _CassResult) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; CassResult(inner) }
 }
 
 impl Debug for CassResult {
@@ -102,7 +102,8 @@ impl CassResult {
 
     /// Gets the column datatype at index for the specified result.
     pub fn column_data_type(&self, index: usize) -> ConstDataType {
-        unsafe { ConstDataType(cass_result_column_data_type(self.0, index)) }
+        // TODO: can return NULL
+        unsafe { ConstDataType::build(cass_result_column_data_type(self.0, index)) }
     }
 
     /// Gets the first row of the result.
diff --git a/src/cassandra/row.rs b/src/cassandra/row.rs
index 36dccf9..10ec159 100644
--- a/src/cassandra/row.rs
+++ b/src/cassandra/row.rs
@@ -29,7 +29,7 @@ unsafe impl Send for Row {}
 
 impl Protected<*const _Row> for Row {
     fn inner(&self) -> *const _Row { self.0 }
-    fn build(inner: *const _Row) -> Self { Row(inner) }
+    fn build(inner: *const _Row) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Row(inner) }
 }
 
 impl Debug for Row {
diff --git a/src/cassandra/schema/aggregate_meta.rs b/src/cassandra/schema/aggregate_meta.rs
index 123c4d6..c959259 100644
--- a/src/cassandra/schema/aggregate_meta.rs
+++ b/src/cassandra/schema/aggregate_meta.rs
@@ -28,7 +28,7 @@ pub struct AggregateMeta(*const _CassAggregateMeta);
 
 impl Protected<*const _CassAggregateMeta> for AggregateMeta {
     fn inner(&self) -> *const _CassAggregateMeta { self.0 }
-    fn build(inner: *const _CassAggregateMeta) -> Self { AggregateMeta(inner) }
+    fn build(inner: *const _CassAggregateMeta) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; AggregateMeta(inner) }
 }
 
 impl AggregateMeta {
@@ -63,14 +63,15 @@ impl AggregateMeta {
 
     /// Gets the aggregate's argument type for the provided index.
     pub fn argument_type(&self, index: usize) -> ConstDataType {
-        unsafe { ConstDataType(cass_aggregate_meta_argument_type(self.0, index)) }
+        // TODO: can return NULL
+        unsafe { ConstDataType::build(cass_aggregate_meta_argument_type(self.0, index)) }
     }
 
     /// Gets the aggregate's argument return type.
-    pub fn return_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_aggregate_meta_return_type(self.0)) } }
+    pub fn return_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_aggregate_meta_return_type(self.0)) } }
 
     /// Gets the aggregate's argument state type.
-    pub fn state_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_aggregate_meta_state_type(self.0)) } }
+    pub fn state_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_aggregate_meta_state_type(self.0)) } }
 
     /// Gets the function metadata for the aggregate's state function.
     pub fn state_func(&self) -> FunctionMeta { unsafe { FunctionMeta::build(cass_aggregate_meta_state_func(self.0)) } }
diff --git a/src/cassandra/schema/column_meta.rs b/src/cassandra/schema/column_meta.rs
index 1c8e66c..7be9874 100644
--- a/src/cassandra/schema/column_meta.rs
+++ b/src/cassandra/schema/column_meta.rs
@@ -22,7 +22,7 @@ use std::str;
 
 impl Protected<*const _CassColumnMeta> for ColumnMeta {
     fn inner(&self) -> *const _CassColumnMeta { self.0 }
-    fn build(inner: *const _CassColumnMeta) -> Self { ColumnMeta(inner) }
+    fn build(inner: *const _CassColumnMeta) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; ColumnMeta(inner) }
 }
 
 
@@ -48,7 +48,7 @@ impl ColumnMeta {
     pub fn get_type(&self) -> _CassColumnType { unsafe { cass_column_meta_type(self.0) } }
 
     /// Gets the data type of the column.
-    pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_column_meta_data_type(self.0)) } }
+    pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_column_meta_data_type(self.0)) } }
 
     /// Gets a metadata field for the provided name. Metadata fields allow direct
     /// access to the column data found in the underlying "columns" metadata table.
diff --git a/src/cassandra/schema/function_meta.rs b/src/cassandra/schema/function_meta.rs
index c651199..4cf7e7f 100644
--- a/src/cassandra/schema/function_meta.rs
+++ b/src/cassandra/schema/function_meta.rs
@@ -28,7 +28,7 @@ pub struct FunctionMeta(*const _CassFunctionMeta);
 
 impl Protected<*const _CassFunctionMeta> for FunctionMeta {
     fn inner(&self) -> *const _CassFunctionMeta { self.0 }
-    fn build(inner: *const _CassFunctionMeta) -> Self { FunctionMeta(inner) }
+    fn build(inner: *const _CassFunctionMeta) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; FunctionMeta(inner) }
 }
 
 impl FunctionMeta {
@@ -114,18 +114,20 @@ impl FunctionMeta {
     pub fn argument_type_by_name(&self, name: &str) -> ConstDataType {
         unsafe {
             let name_cstr = CString::new(name).expect("must be utf8");
-            ConstDataType(cass_function_meta_argument_type_by_name(self.0, name_cstr.as_ptr()))
+            // TODO: can return NULL
+            ConstDataType::build(cass_function_meta_argument_type_by_name(self.0, name_cstr.as_ptr()))
         }
     }
 
     /// Gets the return type of the function.
-    pub fn return_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_function_meta_return_type(self.0)) } }
+    pub fn return_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_function_meta_return_type(self.0)) } }
 
     /// Gets a metadata field for the provided name. Metadata fields allow direct
     /// access to the column data found in the underlying "functions" metadata table.
     pub fn field_by_name(&self, name: &str) -> Value {
         unsafe {
             let name_cstr = CString::new(name).expect("must be utf8");
+            // TODO: can return NULL
             Value::build(cass_function_meta_field_by_name(self.0, name_cstr.as_ptr()))
         }
     }
diff --git a/src/cassandra/schema/keyspace_meta.rs b/src/cassandra/schema/keyspace_meta.rs
index 33bbc8d..de4066a 100644
--- a/src/cassandra/schema/keyspace_meta.rs
+++ b/src/cassandra/schema/keyspace_meta.rs
@@ -34,7 +34,7 @@ pub struct KeyspaceMeta(*const _CassKeyspaceMeta);
 
 impl Protected<*const _CassKeyspaceMeta> for KeyspaceMeta {
     fn inner(&self) -> *const _CassKeyspaceMeta { self.0 }
-    fn build(inner: *const _CassKeyspaceMeta) -> Self { KeyspaceMeta(inner) }
+    fn build(inner: *const _CassKeyspaceMeta) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; KeyspaceMeta(inner) }
 }
 
 #[derive(Debug)]
@@ -72,7 +72,7 @@ impl KeyspaceMeta {
             if value.is_null() {
                 None
             } else {
-                Some(ConstDataType(value))
+                Some(ConstDataType::build(value))
             }
         }
     }
diff --git a/src/cassandra/schema/schema_meta.rs b/src/cassandra/schema/schema_meta.rs
index 8861ee5..c0e0215 100644
--- a/src/cassandra/schema/schema_meta.rs
+++ b/src/cassandra/schema/schema_meta.rs
@@ -7,6 +7,7 @@ use cassandra_sys::cass_iterator_keyspaces_from_schema_meta;
 use cassandra_sys::cass_schema_meta_free;
 use cassandra_sys::cass_schema_meta_keyspace_by_name;
 use cassandra_sys::cass_schema_meta_snapshot_version;
+use std::ffi::CString;
 
 /// A snapshot of the schema's metadata
 #[derive(Debug)]
@@ -22,7 +23,7 @@ impl Drop for SchemaMeta {
 
 impl Protected<*const _CassSchemaMeta> for SchemaMeta {
     fn inner(&self) -> *const _CassSchemaMeta { self.0 }
-    fn build(inner: *const _CassSchemaMeta) -> Self { SchemaMeta(inner) }
+    fn build(inner: *const _CassSchemaMeta) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; SchemaMeta(inner) }
 }
 
 impl SchemaMeta {
@@ -31,7 +32,11 @@ impl SchemaMeta {
 
     /// Gets the keyspace metadata for the provided keyspace name.
     pub fn get_keyspace_by_name(&self, keyspace: &str) -> KeyspaceMeta {
-        unsafe { KeyspaceMeta::build(cass_schema_meta_keyspace_by_name(self.0, keyspace.as_ptr() as *const i8)) }
+        // TODO: can return NULL
+        unsafe {
+            let keyspace_cstr = CString::new(keyspace).expect("Unable to convert string to bytes");
+            KeyspaceMeta::build(cass_schema_meta_keyspace_by_name(self.0, keyspace_cstr.as_ptr()))
+        }
     }
 
     /// Returns an iterator over the keyspaces in this schema
diff --git a/src/cassandra/schema/table_meta.rs b/src/cassandra/schema/table_meta.rs
index 6b657ef..740ed06 100644
--- a/src/cassandra/schema/table_meta.rs
+++ b/src/cassandra/schema/table_meta.rs
@@ -27,7 +27,7 @@ pub struct TableMeta(*const _CassTableMeta);
 
 impl Protected<*const _CassTableMeta> for TableMeta {
     fn inner(&self) -> *const _CassTableMeta { self.0 }
-    fn build(inner: *const _CassTableMeta) -> Self { TableMeta(inner) }
+    fn build(inner: *const _CassTableMeta) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; TableMeta(inner) }
 }
 
 impl TableMeta {
@@ -43,6 +43,7 @@ impl TableMeta {
 
     /// Gets the column metadata for the provided column name.
     pub fn column_by_name(&self, name: &str) -> ColumnMeta {
+        // TODO: can return NULL
         unsafe { ColumnMeta::build(cass_table_meta_column_by_name(self.0, name.as_ptr() as *const i8)) }
     }
 
@@ -64,6 +65,7 @@ impl TableMeta {
 
     /// Gets the column metadata for the provided index.
     pub fn column(&self, index: usize) -> ColumnMeta {
+        // TODO: can return NULL
         unsafe { ColumnMeta::build(cass_table_meta_column(self.0, index)) }
     }
 
diff --git a/src/cassandra/session.rs b/src/cassandra/session.rs
index b0d0458..bc7ff9c 100644
--- a/src/cassandra/session.rs
+++ b/src/cassandra/session.rs
@@ -45,7 +45,7 @@ unsafe impl Sync for Session {}
 
 impl Protected<*mut _Session> for Session {
     fn inner(&self) -> *mut _Session { self.0 }
-    fn build(inner: *mut _Session) -> Self { Session(inner) }
+    fn build(inner: *mut _Session) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Session(inner) }
 }
 
 impl Drop for Session {
diff --git a/src/cassandra/ssl.rs b/src/cassandra/ssl.rs
index 032d84a..ea044b7 100644
--- a/src/cassandra/ssl.rs
+++ b/src/cassandra/ssl.rs
@@ -48,7 +48,7 @@ unsafe impl Send for Ssl {}
 
 impl Protected<*mut _Ssl> for Ssl {
     fn inner(&self) -> *mut _Ssl { self.0 }
-    fn build(inner: *mut _Ssl) -> Self { Ssl(inner) }
+    fn build(inner: *mut _Ssl) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Ssl(inner) }
 }
 
 
diff --git a/src/cassandra/statement.rs b/src/cassandra/statement.rs
index 439e945..8e76ea1 100644
--- a/src/cassandra/statement.rs
+++ b/src/cassandra/statement.rs
@@ -82,7 +82,7 @@ unsafe impl Send for Statement {}
 
 impl Protected<*mut _Statement> for Statement {
     fn inner(&self) -> *mut _Statement { self.0 }
-    fn build(inner: *mut _Statement) -> Self { Statement(inner) }
+    fn build(inner: *mut _Statement) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Statement(inner) }
 }
 
 #[macro_export]
@@ -169,6 +169,12 @@ impl BindRustType<Set> for Statement {
     fn bind_by_name(&mut self, col: &str, value: Set) -> Result<&mut Self> { self.bind_set_by_name(col, value) }
 }
 
+impl BindRustType<List> for Statement {
+    fn bind(&mut self, index: usize, value: List) -> Result<&mut Self> { self.bind_list(index, value) }
+
+    fn bind_by_name(&mut self, col: &str, value: List) -> Result<&mut Self> { self.bind_list_by_name(col, value) }
+}
+
 impl BindRustType<Uuid> for Statement {
     fn bind(&mut self, index: usize, value: Uuid) -> Result<&mut Self> { self.bind_uuid(index, value) }
 
diff --git a/src/cassandra/time.rs b/src/cassandra/time.rs
index 2c99a3c..476c1be 100644
--- a/src/cassandra/time.rs
+++ b/src/cassandra/time.rs
@@ -18,7 +18,7 @@ unsafe impl Sync for TimestampGen {}
 
 impl Protected<*mut _TimestampGen> for TimestampGen {
     fn inner(&self) -> *mut _TimestampGen { self.0 }
-    fn build(inner: *mut _TimestampGen) -> Self { TimestampGen(inner) }
+    fn build(inner: *mut _TimestampGen) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; TimestampGen(inner) }
 }
 
 
diff --git a/src/cassandra/tuple.rs b/src/cassandra/tuple.rs
index f20dde4..a690117 100644
--- a/src/cassandra/tuple.rs
+++ b/src/cassandra/tuple.rs
@@ -45,7 +45,7 @@ unsafe impl Send for Tuple {}
 
 impl Protected<*mut _Tuple> for Tuple {
     fn inner(&self) -> *mut _Tuple { self.0 }
-    fn build(inner: *mut _Tuple) -> Self { Tuple(inner) }
+    fn build(inner: *mut _Tuple) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Tuple(inner) }
 }
 
 impl Tuple {
@@ -58,7 +58,7 @@ impl Tuple {
     }
 
     /// Gets the data type of a tuple.
-    pub fn data_type(&mut self) -> ConstDataType { unsafe { ConstDataType(cass_tuple_data_type(self.0)) } }
+    pub fn data_type(&mut self) -> ConstDataType { unsafe { ConstDataType::build(cass_tuple_data_type(self.0)) } }
 
     /// Sets an null in a tuple at the specified index.
     pub fn set_null(&mut self, index: usize) -> Result<&mut Self> {
diff --git a/src/cassandra/user_type.rs b/src/cassandra/user_type.rs
index ad9d57d..0d84767 100644
--- a/src/cassandra/user_type.rs
+++ b/src/cassandra/user_type.rs
@@ -61,7 +61,7 @@ unsafe impl Send for UserType {}
 
 impl Protected<*mut _UserType> for UserType {
     fn inner(&self) -> *mut _UserType { self.0 }
-    fn build(inner: *mut _UserType) -> Self { UserType(inner) }
+    fn build(inner: *mut _UserType) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; UserType(inner) }
 }
 
 
@@ -77,7 +77,7 @@ impl Drop for UserType {
 
 impl UserType {
     /// Gets the data type of a user defined type.
-    pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_user_type_data_type(self.0)) } }
+    pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_user_type_data_type(self.0)) } }
 
     /// Sets a null in a user defined type at the specified index.
     pub fn set_null(&mut self, index: usize) -> Result<&mut Self> {
diff --git a/src/cassandra/value.rs b/src/cassandra/value.rs
index 35c9844..800df6e 100644
--- a/src/cassandra/value.rs
+++ b/src/cassandra/value.rs
@@ -10,6 +10,7 @@ use cassandra::uuid::Uuid;
 use cassandra::error::*;
 
 use cassandra_sys::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
+use cassandra_sys::CASS_ERROR_LIB_NULL_VALUE;
 use cassandra_sys::CASS_VALUE_TYPE_ASCII;
 use cassandra_sys::CASS_VALUE_TYPE_BIGINT;
 use cassandra_sys::CASS_VALUE_TYPE_BLOB;
@@ -152,7 +153,7 @@ unsafe impl Sync for Value {}
 
 impl Protected<*const _CassValue> for Value {
     fn inner(&self) -> *const _CassValue { self.0 }
-    fn build(inner: *const _CassValue) -> Self { Value(inner) }
+    fn build(inner: *const _CassValue) -> Self { if inner.is_null() { panic!("Unexpected null pointer") }; Value(inner) }
 }
 
 /// Write a set iterator to a formatter.
@@ -292,7 +293,7 @@ impl Value {
     pub fn get_type(&self) -> ValueType { unsafe { ValueType::build(cass_value_type(self.0)) } }
 
     /// Get the data type of this Cassandra value
-    pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_value_data_type(self.0)) } }
+    pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType::build(cass_value_data_type(self.0)) } }
 
     /// Returns true if a specified value is null.
     pub fn is_null(&self) -> bool { unsafe { cass_value_is_null(self.0) == cass_true } }
@@ -321,7 +322,15 @@ impl Value {
     pub fn get_set(&self) -> Result<SetIterator> {
         unsafe {
             match self.get_type() {
-                ValueType::SET => Ok(SetIterator::build(cass_iterator_from_collection(self.0))),
+                ValueType::SET | ValueType::LIST | ValueType::TUPLE => {
+                    let iter = cass_iterator_from_collection(self.0);
+                    if iter.is_null() {
+                        // No iterator, probably because this set is_null. Complain.
+                        Err(CASS_ERROR_LIB_NULL_VALUE.to_error())
+                    } else {
+                        Ok(SetIterator::build(iter))
+                    }
+                }
                 _ => Err(CASS_ERROR_LIB_INVALID_VALUE_TYPE.to_error()),
             }
         }
@@ -331,7 +340,15 @@ impl Value {
     pub fn get_map(&self) -> Result<MapIterator> {
         unsafe {
             match self.get_type() {
-                ValueType::MAP => Ok(MapIterator::build(cass_iterator_from_map(self.0))),
+                ValueType::MAP => {
+                    let iter = cass_iterator_from_map(self.0);
+                    if iter.is_null() {
+                        // No iterator, probably because this map is_null. Complain.
+                        Err(CASS_ERROR_LIB_NULL_VALUE.to_error())
+                    } else {
+                        Ok(MapIterator::build(iter))
+                    }
+                },
                 _ => Err(CASS_ERROR_LIB_INVALID_VALUE_TYPE.to_error()),
             }
         }
@@ -341,7 +358,15 @@ impl Value {
     pub fn get_user_type(&self) -> Result<UserTypeIterator> {
         unsafe {
             match self.get_type() {
-                ValueType::UDT => Ok(UserTypeIterator::build(cass_iterator_fields_from_user_type(self.0))),
+                ValueType::UDT => {
+                    let iter = cass_iterator_fields_from_user_type(self.0);
+                    if iter.is_null() {
+                        // No iterator, probably because this user_type field is null. Complain.
+                        Err(CASS_ERROR_LIB_NULL_VALUE.to_error())
+                    } else {
+                        Ok(UserTypeIterator::build(iter))
+                    }
+                },
                 _ => Err(CASS_ERROR_LIB_INVALID_VALUE_TYPE.to_error()),
             }
         }


Test patch:
diff --git a/tests/collections.rs b/tests/collections.rs
index 498c8fd..ef98638 100644
--- a/tests/collections.rs
+++ b/tests/collections.rs
@@ -20,6 +20,12 @@ fn insert_into_collections(session: &Session, key: &str, items: &Vec<String>) ->
     session.execute(&statement).wait()
 }
 
+fn insert_null_into_collections(session: &Session, key: &str) -> Result<CassResult> {
+    let mut statement = stmt!("INSERT INTO examples.collections (key) VALUES (?);");
+    statement.bind(0, key)?;
+    session.execute(&statement).wait()
+}
+
 fn select_from_collections(session: &Session, key: &str) -> Result<Vec<String>> {
     let mut statement = stmt!("SELECT items FROM examples.collections WHERE key = ?");
     statement.bind(0, key)?;
@@ -54,4 +60,7 @@ fn test_collections() {
     let set0: HashSet<_> = items.iter().collect();
     let set1: HashSet<_> = result.iter().collect();
     assert_eq!(set0, set1, "expected {:?} but got {:?}", &items, &result);
+
+    insert_null_into_collections(&session, "empty").unwrap();
+    select_from_collections(&session, "empty").expect_err("Should fail cleanly");
 }