├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── clippy.toml ├── rustfmt.toml └── src ├── cassandra ├── batch.rs ├── cluster.rs ├── collection.rs ├── column.rs ├── compression.rs ├── consistency.rs ├── custom_payload.rs ├── data_type.rs ├── error.rs ├── field.rs ├── future.rs ├── helpers.rs ├── inet.rs ├── iterator.rs ├── log.rs ├── metrics.rs ├── mod.rs ├── policy │ ├── mod.rs │ └── retry.rs ├── prepared.rs ├── result.rs ├── row.rs ├── schema │ ├── aggregate_meta.rs │ ├── column_meta.rs │ ├── function_meta.rs │ ├── keyspace_meta.rs │ ├── mod.rs │ ├── schema_meta.rs │ └── table_meta.rs ├── session.rs ├── ssl.rs ├── statement.rs ├── time.rs ├── tuple.rs ├── user_type.rs ├── util.rs ├── uuid.rs ├── value.rs └── write_type.rs ├── examples ├── async.rs ├── basic.rs ├── batch.rs ├── bind_by_name.rs ├── callbacks.rs ├── collections.rs ├── logging.rs ├── maps.rs ├── paging.rs ├── perf.rs ├── prepared.rs ├── schema_meta.rs ├── simple.rs ├── ssl.rs ├── udt.rs └── uuids.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.o 3 | *.so 4 | *.rlib 5 | *.dll 6 | 7 | # Executables 8 | *.exe 9 | Cargo.lock 10 | 11 | # Generated by Cargo 12 | /target/ 13 | .project 14 | /.settings/ 15 | .travis.yml 16 | 17 | #rustfmt backup files 18 | *.bk 19 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cpp-driver"] 2 | path = cpp-driver 3 | url = https://github.com/datastax/cpp-driver 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | language: rust 4 | rust: 5 | - stable 6 | cache: 7 | directories: 8 | - $HOME/.cargo 9 | 10 | addons: 11 | apt: 12 | packages: 13 | - libcurl4-openssl-dev 14 | - libelf-dev 15 | - libdw-dev 16 | 17 | before_install: 18 | 19 | - wget http://downloads.datastax.com/cpp-driver/ubuntu/14.04/cassandra/v2.5.0/cassandra-cpp-driver-dbg_2.5.0-1_amd64.deb 20 | - wget http://downloads.datastax.com/cpp-driver/ubuntu/14.04/cassandra/v2.5.0/cassandra-cpp-driver-dev_2.5.0-1_amd64.deb 21 | - wget http://downloads.datastax.com/cpp-driver/ubuntu/14.04/cassandra/v2.5.0/cassandra-cpp-driver_2.5.0-1_amd64.deb 22 | - wget http://downloads.datastax.com/cpp-driver/ubuntu/14.04/dependencies/libuv/v1.8.0/libuv-dbg_1.8.0-1_amd64.deb 23 | - wget http://downloads.datastax.com/cpp-driver/ubuntu/14.04/dependencies/libuv/v1.8.0/libuv-dev_1.8.0-1_amd64.deb 24 | - wget http://downloads.datastax.com/cpp-driver/ubuntu/14.04/dependencies/libuv/v1.8.0/libuv_1.8.0-1_amd64.deb 25 | - sudo dpkg -i libuv-dbg_1.8.0-1_amd64.deb libuv-dev_1.8.0-1_amd64.deb libuv_1.8.0-1_amd64.deb cassandra-cpp-driver_2.5.0-1_amd64.deb cassandra-cpp-driver-dbg_2.5.0-1_amd64.deb cassandra-cpp-driver-dev_2.5.0-1_amd64.deb 26 | 27 | before_script: 28 | - | 29 | pip install 'travis-cargo<0.2' --user && 30 | export PATH=$HOME/.local/bin:/usr/local/bin:$PATH 31 | script: 32 | - | 33 | cargo build && 34 | cargo test 35 | after_success: 36 | - travis-cargo coveralls --no-sudo 37 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | 3 | description = "A usable Cassandra CQL driver (this replaces the previous cql-ffi package).\nWraps the DataStax c++ native driver and uses cql-bindgen via rust-bindgen.\nWorks with nightly" 4 | keywords = ["cassandra"] 5 | license = "Apache-2.0" 6 | homepage = "https://github.com/tupshin/cassandra-rust" 7 | repository = "https://github.com/tupshin/cassandra-rust" 8 | name = "cassandra" 9 | version = "0.8.2-pre" 10 | authors = ["Tupshin Harper "] 11 | build = "build.rs" 12 | 13 | [lib] 14 | name = "cassandra" 15 | 16 | [dependencies] 17 | clippy = {version = "0.0", optional = true} 18 | libc = "0.2" 19 | num = "0.1" 20 | log = "0.3" 21 | cassandra-sys = "0.8" 22 | decimal = "0.2" 23 | chrono = "0.2" 24 | ip = "1.0" 25 | time = "0.1" 26 | clap = "1" 27 | uuid = "0.1" 28 | error-chain="0.7" 29 | 30 | [build-dependencies] 31 | rusty-cheddar = "0.3" 32 | 33 | [[bin]] 34 | name="async" 35 | path="src/examples/async.rs" 36 | 37 | [[bin]] 38 | name="basic" 39 | path="src/examples/basic.rs" 40 | 41 | [[bin]] 42 | name="batch" 43 | path="src/examples/batch.rs" 44 | 45 | [[bin]] 46 | name="bind_by_name" 47 | path="src/examples/bind_by_name.rs" 48 | 49 | [[bin]] 50 | name="collections" 51 | path="src/examples/collections.rs" 52 | 53 | # [[bin]] 54 | # name="logging" 55 | # path="src/examples/logging.rs" 56 | 57 | [[bin]] 58 | name="maps" 59 | path="src/examples/maps.rs" 60 | 61 | [[bin]] 62 | name="paging" 63 | path="src/examples/paging.rs" 64 | 65 | [[bin]] 66 | name="prepared" 67 | path="src/examples/prepared.rs" 68 | 69 | [[bin]] 70 | name="schema_meta" 71 | path="src/examples/schema_meta.rs" 72 | 73 | [[bin]] 74 | name="simple" 75 | path="src/examples/simple.rs" 76 | 77 | # [[bin]] 78 | # name="udt" 79 | # path="src/examples/udt.rs" 80 | 81 | [[bin]] 82 | name="uuids" 83 | path="src/examples/uuids.rs" 84 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/tupshin/cassandra-rs.svg?branch=master)](https://travis-ci.org/tupshin/cassandra-rs) 2 | [![Current Version](http://meritbadge.herokuapp.com/cassandra)](https://crates.io/crates/cassandra) 3 | [![License: MPL-2.0](https://img.shields.io/crates/l/cassandra.svg)](#License) 4 | 5 | # cassandra-rs 6 | 7 | This is a maintained rust project that 8 | exposes the cpp driver at https://github.com/datastax/cpp-driver/ 9 | in a somewhat-sane crate. 10 | 11 | For the wrapper to work, you must first have installed the datastax-cpp driver. 12 | 13 | Follow the steps on the cpp driver [docs](https://github.com/datastax/cpp-driver/blob/15215e170810433511c48c304b9e9ca51ff32b2f/topics/building/README.md) to do so. 14 | 15 | Make sure that the driver (specifically `libcassandra_static.a` and `libcassandra.so`) are in your `/usr/local/lib64/` directory 16 | 17 | You can use it from cargo with 18 | 19 | ```toml 20 | [dependencies.cassandra] 21 | git = "https://github.com/tupshin/cassandra-rs" 22 | ``` 23 | 24 | Or just 25 | 26 | ```toml 27 | [dependencies] 28 | cassandra="*" 29 | ``` 30 | 31 | Here's a straightforward example found in simple.rs: 32 | 33 | 34 | ```rust 35 | #[macro_use(stmt)] 36 | extern crate cassandra; 37 | use cassandra::*; 38 | use std::str::FromStr; 39 | 40 | 41 | fn main() { 42 | let query = stmt!("SELECT keyspace_name FROM system_schema.keyspaces;"); 43 | let col_name = "keyspace_name"; 44 | 45 | let contact_points = ContactPoints::from_str("127.0.0.1").unwrap(); 46 | 47 | let mut cluster = Cluster::default(); 48 | cluster.set_contact_points(contact_points).unwrap(); 49 | cluster.set_load_balance_round_robin(); 50 | 51 | match cluster.connect() { 52 | Ok(ref mut session) => { 53 | let result = session.execute(&query).wait().unwrap(); 54 | println!("{}", result); 55 | for row in result.iter() { 56 | let col: String = row.get_col_by_name(col_name).unwrap(); 57 | println!("ks name = {}", col); 58 | } 59 | } 60 | err => println!("{:?}", err), 61 | } 62 | } 63 | ``` 64 | 65 | There's additional examples included with the project in src/examples. 66 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | extern crate cheddar; 2 | 3 | fn main() { 4 | if let Some(datastax_dir) = option_env!("CASSANDRA_SYS_LIB_PATH") { 5 | for p in datastax_dir.split(";") { 6 | println!("cargo:rustc-link-search={}", p); 7 | } 8 | } 9 | println!("cargo:rustc-flags=-l dylib=crypto"); 10 | println!("cargo:rustc-flags=-l dylib=ssl"); 11 | println!("cargo:rustc-flags=-l dylib=stdc++"); 12 | println!("cargo:rustc-flags=-l dylib=uv"); 13 | println!("cargo:rustc-link-search={}", "/usr/lib/x86_64-linux-gnu"); 14 | println!("cargo:rustc-link-search={}", "/usr/local/lib/x86_64-linux-gnu"); 15 | println!("cargo:rustc-link-search={}", "/usr/local/lib64"); 16 | println!("cargo:rustc-link-search={}", "/usr/local/lib"); 17 | println!("cargo:rustc-link-search={}", "/usr/lib64/"); 18 | println!("cargo:rustc-link-search={}", "/usr/lib/"); 19 | println!("cargo:rustc-link-lib=static=cassandra_static"); 20 | } 21 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | # cast_possible_truncation = warn 2 | # mem_forget = warn 3 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 120 2 | ideal_width = 100 3 | leeway = 5 4 | tab_spaces = 4 5 | newline_style = "Unix" 6 | fn_brace_style = "PreferSameLine" 7 | fn_return_indent = "WithArgs" 8 | fn_args_paren_newline = true 9 | fn_args_density = "Compressed" 10 | fn_args_layout = "Visual" 11 | fn_arg_indent = "Tabbed" 12 | where_density = "Tall" 13 | where_indent = "Tabbed" 14 | where_layout = "Horizontal" 15 | where_pred_indent = "Visual" 16 | generics_indent = "Visual" 17 | struct_trailing_comma = "Vertical" 18 | struct_lit_trailing_comma = "Vertical" 19 | struct_lit_style = "Block" 20 | enum_trailing_comma = true 21 | report_todo = "Always" 22 | report_fixme = "Never" 23 | expr_indent_style = "Tabbed" 24 | closure_indent_style = "Visual" 25 | single_line_if_else = true 26 | format_strings = true 27 | density = "Compressed" 28 | rewrite_if_else = true 29 | fn_empty_single_line = true 30 | use_try_shorthand = true 31 | fn_single_line = true 32 | reorder_imports = true 33 | reorder_imported_names = true 34 | -------------------------------------------------------------------------------- /src/cassandra/batch.rs: -------------------------------------------------------------------------------- 1 | use cassandra::consistency::Consistency; 2 | use cassandra::policy::retry::RetryPolicy; 3 | use cassandra::statement::Statement; 4 | use cassandra::util::Protected; 5 | 6 | use cassandra_sys::CASS_OK; 7 | pub use cassandra_sys::CassBatch as _Batch; 8 | pub use cassandra_sys::CassBatchType as BatchType; 9 | use cassandra_sys::CassConsistency; 10 | use cassandra_sys::CassCustomPayload as _CassCustomPayload; 11 | use cassandra_sys::CassError; 12 | use cassandra_sys::cass_batch_add_statement; 13 | use cassandra_sys::cass_batch_free; 14 | use cassandra_sys::cass_batch_new; 15 | use cassandra_sys::cass_batch_set_consistency; 16 | use cassandra_sys::cass_batch_set_custom_payload; 17 | use cassandra_sys::cass_batch_set_retry_policy; 18 | use cassandra_sys::cass_batch_set_serial_consistency; 19 | use cassandra_sys::cass_batch_set_timestamp; 20 | use cassandra_sys::cass_custom_payload_free; 21 | use cassandra_sys::cass_custom_payload_new; 22 | use cassandra_sys::cass_custom_payload_set; 23 | use std::ffi::CString; 24 | use std::ffi::NulError; 25 | 26 | 27 | /// A group of statements that are executed as a single batch. 28 | /// Note: Batches are not supported by the binary protocol version 1. 29 | #[derive(Debug)] 30 | pub struct Batch(*mut _Batch); 31 | 32 | impl Protected<*mut _Batch> for Batch { 33 | fn inner(&self) -> *mut _Batch { self.0 } 34 | fn build(inner: *mut _Batch) -> Self { Batch(inner) } 35 | } 36 | 37 | /// Custom payloads not fully supported yet 38 | #[derive(Debug)] 39 | pub struct CustomPayload(*mut _CassCustomPayload); 40 | 41 | impl Protected<*mut _CassCustomPayload> for CustomPayload { 42 | fn inner(&self) -> *mut _CassCustomPayload { self.0 } 43 | fn build(inner: *mut _CassCustomPayload) -> Self { CustomPayload(inner) } 44 | } 45 | 46 | impl Default for CustomPayload { 47 | /// creates a new custom payload 48 | fn default() -> Self { unsafe { CustomPayload(cass_custom_payload_new()) } } 49 | } 50 | impl CustomPayload { 51 | /// Sets an item to the custom payload. 52 | pub fn set(&self, name: String, value: &[u8]) -> Result<(), NulError> { 53 | unsafe { 54 | Ok(cass_custom_payload_set(self.0, 55 | CString::new(name)?.as_ptr(), 56 | value.as_ptr(), 57 | value.len())) 58 | } 59 | } 60 | } 61 | 62 | impl Drop for CustomPayload { 63 | fn drop(&mut self) { unsafe { cass_custom_payload_free(self.0) } } 64 | } 65 | 66 | // ///Type of Cassandra Batch operation to perform 67 | // pub enum BatchType { 68 | // ///Logged batches have Atomicity guarantees 69 | // LOGGED, 70 | // ///Unlogged batches do not provide any atomicity guarantees 71 | // UNLOGGED, 72 | // ///Counter batches can only be used when writing counter types 73 | // COUNTER, 74 | // } 75 | 76 | impl Drop for Batch { 77 | /// Frees a batch instance. Batches can be immediately freed after being 78 | /// executed. 79 | fn drop(&mut self) { unsafe { cass_batch_free(self.0) } } 80 | } 81 | 82 | impl Batch { 83 | /// Creates a new batch statement with batch type. 84 | pub fn new(batch_type: BatchType) -> Batch { unsafe { Batch(cass_batch_new(batch_type)) } } 85 | 86 | /// Sets the batch's consistency level 87 | pub fn set_consistency(&mut self, consistency: CassConsistency) -> Result<&Self, CassError> { 88 | unsafe { 89 | match cass_batch_set_consistency(self.0, consistency) { 90 | CASS_OK => Ok(self), 91 | err => Err(err), 92 | } 93 | } 94 | } 95 | 96 | /// Sets the batch's serial consistency level. 97 | /// 98 | /// Default: Not set 99 | pub fn set_serial_consistency(&mut self, consistency: Consistency) -> Result<&Self, CassError> { 100 | unsafe { 101 | match cass_batch_set_serial_consistency(self.0, consistency.inner()) { 102 | CASS_OK => Ok(self), 103 | err => Err(err), 104 | } 105 | } 106 | } 107 | 108 | /// Sets the batch's timestamp. 109 | pub fn set_timestamp(&mut self, timestamp: i64) -> Result<&Self, CassError> { 110 | unsafe { 111 | match cass_batch_set_timestamp(self.0, timestamp) { 112 | CASS_OK => Ok(self), 113 | err => Err(err), 114 | } 115 | } 116 | } 117 | 118 | /// Sets the batch's retry policy. 119 | pub fn set_retry_policy(&mut self, retry_policy: RetryPolicy) -> Result<&Self, CassError> { 120 | unsafe { 121 | match cass_batch_set_retry_policy(self.0, retry_policy.inner()) { 122 | CASS_OK => Ok(self), 123 | err => Err(err), 124 | } 125 | } 126 | } 127 | 128 | /// Sets the batch's custom payload. 129 | pub fn set_custom_payload(&mut self, custom_payload: CustomPayload) -> Result<&Self, CassError> { 130 | unsafe { 131 | match cass_batch_set_custom_payload(self.0, custom_payload.0) { 132 | CASS_OK => Ok(self), 133 | err => Err(err), 134 | } 135 | } 136 | } 137 | 138 | /// Adds a statement to a batch. 139 | pub fn add_statement(&mut self, statement: &Statement) -> Result<&Self, CassError> { 140 | unsafe { 141 | match cass_batch_add_statement(self.0, statement.inner()) { 142 | CASS_OK => Ok(self), 143 | err => Err(err), 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/cassandra/compression.rs: -------------------------------------------------------------------------------- 1 | pub type CassCompression { 2 | NONE = 0, 3 | SNAPPY = 1, 4 | LZ4 = 2 5 | } 6 | -------------------------------------------------------------------------------- /src/cassandra/consistency.rs: -------------------------------------------------------------------------------- 1 | use cassandra::util::Protected; 2 | use cassandra_sys::CassConsistency as _CassConsistency; 3 | 4 | use cassandra_sys::cass_consistency_string; 5 | 6 | use std::ffi::CStr; 7 | 8 | 9 | 10 | /// A Cassandra consistency level 11 | #[derive(Debug)] 12 | pub struct Consistency(_CassConsistency); 13 | 14 | impl ToString for Consistency { 15 | fn to_string(&self) -> String { 16 | unsafe { 17 | let my_string = cass_consistency_string(self.0); 18 | CStr::from_ptr(my_string).to_string_lossy().into_owned() 19 | } 20 | } 21 | } 22 | 23 | impl Protected<_CassConsistency> for Consistency { 24 | fn inner(&self) -> _CassConsistency { self.0 } 25 | fn build(inner: _CassConsistency) -> Self { Consistency(inner) } 26 | } 27 | -------------------------------------------------------------------------------- /src/cassandra/custom_payload.rs: -------------------------------------------------------------------------------- 1 | // use cassandra_sys::cass_custom_payload_free; 2 | // use cassandra_sys::cass_custom_payload_new; 3 | // use cassandra_sys::cass_custom_payload_set; 4 | 5 | // use cassandra_sys::CassCustomPayload as _CassCustomPayload; 6 | // 7 | // pub struct CustomPayload(_CasCustomPayload); 8 | -------------------------------------------------------------------------------- /src/cassandra/data_type.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use cassandra::error::CassError; 4 | 5 | use cassandra::user_type::UserType; 6 | use cassandra::util::Protected; 7 | use cassandra::value::ValueType; 8 | 9 | use cassandra_sys::CassDataType as _CassDataType; 10 | use cassandra_sys::cass_data_sub_type_count; 11 | use cassandra_sys::cass_data_type_add_sub_type; 12 | use cassandra_sys::cass_data_type_add_sub_type_by_name; 13 | use cassandra_sys::cass_data_type_add_sub_value_type; 14 | use cassandra_sys::cass_data_type_add_sub_value_type_by_name; 15 | use cassandra_sys::cass_data_type_class_name; 16 | use cassandra_sys::cass_data_type_free; 17 | use cassandra_sys::cass_data_type_keyspace; 18 | use cassandra_sys::cass_data_type_new; 19 | use cassandra_sys::cass_data_type_new_from_existing; 20 | use cassandra_sys::cass_data_type_new_tuple; 21 | use cassandra_sys::cass_data_type_new_udt; 22 | use cassandra_sys::cass_data_type_set_class_name; 23 | use cassandra_sys::cass_data_type_set_keyspace; 24 | use cassandra_sys::cass_data_type_set_type_name; 25 | use cassandra_sys::cass_data_type_sub_data_type; 26 | use cassandra_sys::cass_data_type_sub_data_type_by_name; 27 | use cassandra_sys::cass_data_type_sub_type_name; 28 | use cassandra_sys::cass_data_type_type; 29 | use cassandra_sys::cass_data_type_type_name; 30 | use cassandra_sys::cass_user_type_new_from_data_type; 31 | use errors::*; 32 | 33 | use std::ffi::CString; 34 | 35 | 36 | /// Any cassandra datatype 37 | #[derive(Debug)] 38 | pub struct DataType(*mut _CassDataType); 39 | #[derive(Debug)] 40 | pub struct ConstDataType(pub *const _CassDataType); 41 | 42 | impl Protected<*mut _CassDataType> for DataType { 43 | fn inner(&self) -> *mut _CassDataType { self.0 } 44 | fn build(inner: *mut _CassDataType) -> Self { DataType(inner) } 45 | } 46 | 47 | impl Drop for DataType { 48 | /// Frees a data type instance. 49 | fn drop(&mut self) { unsafe { cass_data_type_free(self.0) } } 50 | } 51 | 52 | 53 | 54 | impl DataType { 55 | /// Creates a new data type with value type. 56 | pub fn new(value_type: ValueType) -> Self { unsafe { DataType(cass_data_type_new(value_type.inner())) } } 57 | 58 | /// Creates a new data type from an existing data type. 59 | pub fn new_user_type(&self) -> UserType { unsafe { UserType::build(cass_user_type_new_from_data_type(self.0)) } } 60 | 61 | 62 | /// Creates a new data type from an existing data type. 63 | pub fn new_from_existing(&self) -> Self { unsafe { DataType(cass_data_type_new_from_existing(self.0)) } } 64 | 65 | /// Creates a new tuple data type. 66 | pub fn new_tuple(item_count: usize) -> Self { unsafe { DataType(cass_data_type_new_tuple(item_count)) } } 67 | 68 | /// Creates a new UDT (user defined type) data type. 69 | pub fn new_udt(field_count: usize) -> DataType { unsafe { DataType(cass_data_type_new_udt(field_count)) } } 70 | 71 | /// Gets the value type of the specified data type. 72 | pub fn get_type(data_type: DataType) -> ValueType { unsafe { ValueType::build(cass_data_type_type(data_type.0)) } } 73 | 74 | /// Gets the type name of a UDT data type. 75 | pub fn type_name(data_type: DataType, type_name: S) -> Result<()> 76 | where S: Into { 77 | unsafe { 78 | let type_name2 = CString::new(type_name.into()).expect("must be valid utf8"); 79 | let err = cass_data_type_type_name(data_type.0, 80 | &mut type_name2.as_ptr(), 81 | &mut (type_name2.as_bytes().len())); 82 | err.to_result(()).chain_err(|| "") 83 | } 84 | } 85 | 86 | /// Sets the type name of a UDT data type. 87 | /// 88 | /// Note: Only valid for UDT data types. 89 | pub fn set_type_name(data_type: DataType, type_name: S) -> Result<()> 90 | where S: Into { 91 | unsafe { 92 | cass_data_type_set_type_name(data_type.0, 93 | CString::new(type_name.into()) 94 | .expect("must be utf8") 95 | .as_ptr()) 96 | .to_result(()) 97 | .chain_err(|| "") 98 | } 99 | } 100 | 101 | /// Gets the type name of a UDT data type. 102 | /// 103 | /// Note: Only valid for UDT data types. 104 | pub fn keyspace(data_type: DataType, keyspace: S) -> Result<()> 105 | where S: Into { 106 | unsafe { 107 | let keyspace2 = CString::new(keyspace.into()).expect("must be utf8"); 108 | cass_data_type_keyspace(data_type.0, 109 | &mut (keyspace2.as_ptr()), 110 | &mut (keyspace2.as_bytes().len())) 111 | .to_result(()) 112 | .chain_err(|| "") 113 | } 114 | } 115 | 116 | /// Sets the keyspace of a UDT data type. 117 | /// 118 | /// Note: Only valid for UDT data types. 119 | pub fn set_keyspace(data_type: DataType, keyspace: S) -> Result<()> 120 | where S: Into { 121 | unsafe { 122 | cass_data_type_set_keyspace(data_type.0, 123 | CString::new(keyspace.into()).expect("must be utf8").as_ptr()) 124 | .to_result(()) 125 | .chain_err(|| "") 126 | } 127 | } 128 | 129 | /// Gets the class name of a custom data type. 130 | /// 131 | /// Note: Only valid for custom data types. 132 | pub fn class_name(data_type: DataType, class_name: S) -> Result<()> 133 | where S: Into { 134 | unsafe { 135 | let class_name2 = CString::new(class_name.into()).expect("must be valid utf8"); 136 | cass_data_type_class_name(data_type.0, 137 | &mut class_name2.as_ptr(), 138 | &mut (class_name2.as_bytes().len())) 139 | .to_result(()) 140 | .chain_err(|| "") 141 | } 142 | } 143 | 144 | /// Sets the class name of a custom data type. 145 | /// 146 | /// Note: Only valid for custom data types. 147 | pub fn set_class_name(&self, class_name: S) -> Result<()> 148 | where S: Into { 149 | unsafe { 150 | cass_data_type_set_class_name(self.0, 151 | CString::new(class_name.into()) 152 | .expect("must be valid utf8") 153 | .as_ptr()) 154 | .to_result(()) 155 | .chain_err(|| "") 156 | } 157 | } 158 | 159 | /// Gets the sub-data type count of a UDT (user defined type), tuple 160 | /// or collection. 161 | /// 162 | /// Note: Only valid for UDT, tuple and collection data types. 163 | pub fn sub_type_count(&self) -> usize { unsafe { cass_data_sub_type_count(self.0) } } 164 | 165 | /// Gets the sub-data type of a UDT (user defined type), tuple or collection at 166 | /// the specified index. 167 | /// 168 | /// Note: Only valid for UDT, tuple and collection data types. 169 | pub fn sub_data_type(&self, index: usize) -> ConstDataType { 170 | unsafe { ConstDataType(cass_data_type_sub_data_type(self.0, index)) } 171 | } 172 | 173 | /// Gets the sub-data type of a UDT (user defined type) at the specified index. 174 | /// 175 | /// Note: Only valid for UDT data types. 176 | pub fn sub_data_type_by_name(data_type: DataType, name: S) -> ConstDataType 177 | where S: Into { 178 | unsafe { 179 | ConstDataType(cass_data_type_sub_data_type_by_name(data_type.0, 180 | CString::new(name.into()) 181 | .expect("must be utf8") 182 | .as_ptr())) 183 | } 184 | } 185 | 186 | /// Gets the sub-type name of a UDT (user defined type) at the specified index. 187 | /// 188 | /// Note: Only valid for UDT data types. 189 | pub fn sub_type_name(data_type: DataType, index: usize, name: S) -> Result<()> 190 | where S: Into { 191 | unsafe { 192 | let name2 = CString::new(name.into()).expect("must be utf8"); 193 | cass_data_type_sub_type_name(data_type.0, 194 | index, 195 | &mut name2.as_ptr(), 196 | &mut (name2.as_bytes().len())) 197 | .to_result(()) 198 | .chain_err(|| "") 199 | 200 | } 201 | } 202 | 203 | /// Adds a sub-data type to a tuple or collection. 204 | /// 205 | /// Note: Only valid for tuple and collection data types. 206 | pub fn add_sub_type(&self, sub_data_type: DataType) -> Result<()> { 207 | unsafe { 208 | cass_data_type_add_sub_type(self.0, sub_data_type.0) 209 | .to_result(()) 210 | .chain_err(|| "") 211 | } 212 | } 213 | 214 | /// Gets the sub-data type of a UDT (user defined type) at the specified index. 215 | /// 216 | /// Note: Only valid for UDT data types. 217 | pub fn add_sub_type_by_name(&mut self, name: S, sub_data_type: DataType) -> Result<()> 218 | where S: Into { 219 | unsafe { 220 | cass_data_type_add_sub_type_by_name(self.0, 221 | CString::new(name.into()) 222 | .expect("must be utf8") 223 | .as_ptr(), 224 | sub_data_type.0) 225 | .to_result(()) 226 | .chain_err(|| "") 227 | } 228 | } 229 | 230 | /// Adds a sub-data type to a tuple or collection using a value type. 231 | /// 232 | /// Note: Only valid for tuple and collection data types. 233 | pub fn add_sub_value_type(&self, sub_value_type: ValueType) -> Result<()> 234 | where S: Into { 235 | unsafe { 236 | cass_data_type_add_sub_value_type(self.0, sub_value_type.inner()) 237 | .to_result(()) 238 | .chain_err(|| "") 239 | } 240 | } 241 | 242 | /// Adds a sub-data type to a tuple or collection using a value type. 243 | /// 244 | /// Note: Only valid for tuple and collection data types. 245 | pub fn add_sub_value_type_by_name(&self, name: &str, typ: ValueType) -> Result<()> 246 | where S: Into { 247 | unsafe { 248 | cass_data_type_add_sub_value_type_by_name(self.0, 249 | CString::new(name) 250 | .expect("must be utf8") 251 | .as_ptr(), 252 | typ.inner()) 253 | .to_result(()) 254 | .chain_err(|| "") 255 | } 256 | 257 | } 258 | 259 | // pub fn set_type_name_n(data_type: DataType, type_name: S) -> Result<(), CassError> 260 | // where S: Into 261 | // { 262 | // unsafe { 263 | // let type_name = CString::new(type_name.into()).unwrap(); 264 | // CassError::build(cass_data_type_set_type_name_n(data_type.0, 265 | // type_name.as_ptr(), 266 | // type_name.as_bytes().len() as u64)) 267 | // .wrap(()) 268 | // } 269 | // } 270 | 271 | // pub fn set_class_name_n(data_type: DataType, class_name: S) -> Result<(), CassError> 272 | // where S: Into 273 | // { 274 | // unsafe { 275 | // let class_name = CString::new(class_name.into()).unwrap(); 276 | // CassError::build(cass_data_type_set_class_name_n(data_type.0, 277 | // class_name.as_ptr(), 278 | // class_name.as_bytes().len() as u64)) 279 | // .wrap(()) 280 | // } 281 | // } 282 | 283 | 284 | // pub fn sub_data_type_by_name_n(data_type: DataType, name: S) -> ConstDataType 285 | // where S: Into 286 | // { 287 | // unsafe { 288 | // let name = CString::new(name.into()).unwrap(); 289 | // ConstDataType(cass_data_type_sub_data_type_by_name_n(data_type.0, 290 | // name.as_ptr(), 291 | // name.as_bytes().len() as u64)) 292 | // } 293 | // } 294 | } 295 | -------------------------------------------------------------------------------- /src/cassandra/error.rs: -------------------------------------------------------------------------------- 1 | #![macro_use] 2 | // use cassandra_sys; 3 | 4 | use cassandra::consistency::Consistency; 5 | use cassandra::util::Protected; 6 | use cassandra::write_type::WriteType; 7 | 8 | use cassandra_sys::CASS_OK; 9 | use cassandra_sys::CassError as _CassError; 10 | 11 | use cassandra_sys::CassErrorResult as _CassErrorResult; 12 | use cassandra_sys::cass_error_desc; 13 | use cassandra_sys::cass_error_num_arg_types; 14 | use cassandra_sys::cass_error_result_arg_type; 15 | use cassandra_sys::cass_error_result_code; 16 | use cassandra_sys::cass_error_result_consistency; 17 | use cassandra_sys::cass_error_result_data_present; 18 | use cassandra_sys::cass_error_result_free; 19 | use cassandra_sys::cass_error_result_function; 20 | use cassandra_sys::cass_error_result_keyspace; 21 | use cassandra_sys::cass_error_result_num_failures; 22 | use cassandra_sys::cass_error_result_responses_received; 23 | use cassandra_sys::cass_error_result_responses_required; 24 | use cassandra_sys::cass_error_result_table; 25 | use cassandra_sys::cass_error_result_write_type; 26 | use errors::*; 27 | use errors::*; 28 | use std::{fmt, mem, slice, str}; 29 | use std::error::Error as IError; 30 | // use std::error::Error; 31 | use std::ffi::{CStr, CString}; 32 | use std::fmt::{Debug, Display, Formatter}; 33 | use std::os::raw::c_char; 34 | 35 | // Simple and robust error handling with error-chain! 36 | // Use this as a template for new projects. 37 | 38 | // #[macro_export] 39 | // macro_rules! err_wrap { 40 | // ( $s:expr,$x:expr ) => {match $x { 41 | // CASS_OK => Ok($s), 42 | // err => Err(Error::from(err.into())) 43 | // } 44 | // } 45 | // } 46 | 47 | error_chain! { 48 | // Automatic conversions between this error chain and other 49 | // error types not defined by the `error_chain!`. These will be 50 | // wrapped in a new error with, in this case, the 51 | // `ErrorKind::Temp` variant. The description and cause will 52 | // forward to the description and cause of the original error. 53 | // 54 | // Optionally, some attributes can be added to a variant. 55 | // 56 | // This section can be empty. 57 | foreign_links { 58 | Fmt(::std::fmt::Error); 59 | Io(::std::io::Error) #[cfg(unix)]; 60 | Null(::std::ffi::NulError); 61 | Cass(_CassError); 62 | Utf8(::std::str::Utf8Error); 63 | } 64 | 65 | // Define additional `ErrorKind` variants. The syntax here is 66 | // the same as `quick_error!`, but the `from()` and `cause()` 67 | // syntax is not supported. 68 | errors { 69 | CassError(t: String) { 70 | //description("invalid toolchain name") 71 | //display("invalid toolchain name: '{}'", t) 72 | } 73 | } 74 | } 75 | 76 | 77 | 78 | /// An error returned by Cassandra or the driver 79 | pub struct CassError(_CassError); 80 | 81 | // ///An error generated by the C++ driver 82 | // pub struct CassLibError { 83 | // err: _CassError, 84 | // msg: String, 85 | // } 86 | 87 | // impl From<_CassError> for CassError { 88 | // fn from(err:_CassError) -> CassError { 89 | // CassError 90 | // } 91 | // } 92 | 93 | // ///An error signaled by the server and sent to the client over CQL transport 94 | // pub struct CassServerError(_CassError); 95 | // ///An error signaled by the client-linked SSL library 96 | // pub struct CassSslError(_CassError); 97 | 98 | impl ::std::error::Error for CassError { 99 | fn description(&self) -> &str { 100 | unimplemented!() 101 | // self.desc() 102 | // let c_buf: *const i8 = self.desc(); 103 | // let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() }; 104 | // from_utf8(buf).unwrap() 105 | } 106 | } 107 | 108 | // impl From for CassError { 109 | // fn from(err: AddrParseError) -> CassError { 110 | // CassError::Rust(CassRustError::BadAddress(err)) 111 | // } 112 | // } 113 | 114 | // impl From for CassError { 115 | // fn from(err: NulError) -> CassError { 116 | // CassError::Rust(CassRustError::NulInString(err)) 117 | // } 118 | // } 119 | 120 | impl Display for CassError { 121 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 122 | write!(f, "{}", self.description()) 123 | // let c_buf: *const i8 = self.desc(); 124 | // let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() }; 125 | // match str::from_utf8(buf) { 126 | // Ok(str_slice) => write!(f, "{}", str_slice), 127 | // Err(err) => panic!("unreachable? {:?}", err), 128 | // } 129 | } 130 | } 131 | // 132 | impl Debug for CassError { 133 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 134 | write!(f, "{}", self.description()) 135 | // let c_buf: *const i8 = self.desc(); 136 | // let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() }; 137 | // match str::from_utf8(buf) { 138 | // Ok(str_slice) => write!(f, "{:?}", str_slice), 139 | // Err(err) => panic!("unreachable? {:?}", err), 140 | // } 141 | } 142 | } 143 | 144 | // impl From for CassError { 145 | // fn from(err: NulError) -> CassError { 146 | // CliError::Io(err) 147 | // } 148 | // } 149 | 150 | // impl CassError { 151 | // /// Takes an upstream error and wraps it into the appropriate CassError 152 | // pub fn wrap(self, wrappee: T) -> Result { 153 | // match self.0 { 154 | // CASS_OK => Ok(wrappee), 155 | // err => Err(Error::from(err.into())), 156 | // } 157 | // } 158 | // // 159 | // } 160 | /// An error result of a request 161 | #[derive(Debug)] 162 | pub struct CassErrorResult(*const _CassErrorResult); 163 | 164 | impl Protected<*const _CassErrorResult> for CassErrorResult { 165 | fn inner(&self) -> *const _CassErrorResult { self.0 } 166 | fn build(inner: *const _CassErrorResult) -> Self { CassErrorResult(inner) } 167 | } 168 | 169 | // impl CassErrorResult { 170 | // /// Gets error code for the error result. This error code will always 171 | // /// have an server error source. 172 | // pub fn result_code(&self) -> u32 { unsafe { cass_error_result_code(self.0) as u32 } } 173 | // 174 | // /// Gets consistency that triggered the error result of the 175 | // /// following types: 176 | // /// 177 | // ///
    178 | // ///
  • CASS_ERROR_SERVER_READ_TIMEOUT
  • 179 | // ///
  • CASS_ERROR_SERVER_WRITE_TIMEOUT
  • 180 | // ///
  • CASS_ERROR_SERVER_READ_FAILURE
  • 181 | // ///
  • CASS_ERROR_SERVER_WRITE_FAILURE
  • 182 | // ///
  • CASS_ERROR_SERVER_UNAVAILABLE
  • 183 | // ///
184 | // pub fn result_consistency(&self) -> Consistency { 185 | // unsafe { Consistency::build(cass_error_result_consistency(self.0)) } 186 | // } 187 | // 188 | // /// Gets the actual number of received responses, received acknowledgments 189 | // /// or alive nodes for following error result types, respectively: 190 | // /// 191 | // ///
    192 | // ///
  • CASS_ERROR_SERVER_READ_TIMEOUT
  • 193 | // ///
  • CASS_ERROR_SERVER_WRITE_TIMEOUT
  • 194 | // ///
  • CASS_ERROR_SERVER_READ_FAILURE
  • 195 | // ///
  • CASS_ERROR_SERVER_WRITE_FAILURE
  • 196 | // ///
  • CASS_ERROR_SERVER_UNAVAILABLE
  • 197 | // ///
198 | // pub fn responses_received(&self) -> i32 { unsafe { cass_error_result_responses_received(self.0) } } 199 | // 200 | // /// Gets required responses, required acknowledgments or required alive nodes 201 | // /// needed to successfully complete the request for following error result types, 202 | // /// respectively: 203 | // /// 204 | // ///
    205 | // ///
  • CASS_ERROR_SERVER_READ_TIMEOUT
  • 206 | // ///
  • CASS_ERROR_SERVER_WRITE_TIMEOUT
  • 207 | // ///
  • CASS_ERROR_SERVER_READ_FAILURE
  • 208 | // ///
  • CASS_ERROR_SERVER_WRITE_FAILURE
  • 209 | // ///
  • CASS_ERROR_SERVER_UNAVAILABLE
  • 210 | // ///
211 | // pub fn responses_required(&self) -> i32 { unsafe { cass_error_result_responses_required(self.0) } } 212 | // 213 | // /// Gets the number of nodes that experienced failures for the following error types: 214 | // /// 215 | // ///
    216 | // ///
  • CASS_ERROR_SERVER_READ_FAILURE
  • 217 | // ///
  • CASS_ERROR_SERVER_WRITE_FAILURE
  • 218 | // ///
219 | // pub fn num_failures(&self) -> i32 { unsafe { cass_error_result_num_failures(self.0) } } 220 | // 221 | // /// Determines whether the actual data was present in the responses from the 222 | // /// replicas for the following error result types: 223 | // /// 224 | // ///
    225 | // ///
  • CASS_ERROR_SERVER_READ_TIMEOUT
  • 226 | // ///
  • CASS_ERROR_SERVER_READ_FAILURE
  • 227 | // ///
228 | // pub fn data_present(&self) -> bool { unsafe { cass_error_result_data_present(self.0) as i32 > 0 } } 229 | // 230 | // 231 | // /// Gets the write type of a request for the following error result types: 232 | // /// 233 | // ///
    234 | // ///
  • CASS_ERROR_SERVER_WRITE_TIMEOUT
  • 235 | // ///
  • CASS_ERROR_SERVER_WRITE_FAILURE
  • 236 | // ///
237 | // pub fn write_type(&self) -> WriteType { unsafe { WriteType(cass_error_result_write_type(self.0)) } } 238 | // 239 | // /// Gets the affected keyspace for the following error result types: 240 | // /// 241 | // ///
    242 | // ///
  • CASS_ERROR_SERVER_ALREADY_EXISTS
  • 243 | // ///
  • CASS_ERROR_SERVER_FUNCTION_FAILURE
  • 244 | // ///
245 | // #[allow(cast_possible_truncation)] 246 | // pub fn keyspace(&self) -> String { 247 | // unsafe { 248 | // let mut name = mem::zeroed(); 249 | // let mut length = mem::zeroed(); 250 | // match cass_error_result_keyspace(self.0, &mut name, &mut length) { 251 | // CASS_OK => { 252 | // let slice = slice::from_raw_parts(name as *const u8, length as usize); 253 | // str::from_utf8(slice).expect("must be utf8").to_owned() 254 | // } 255 | // err => panic!("impossible: {:?}", err), 256 | // } 257 | // } 258 | // } 259 | // 260 | // /// Gets the affected table for the already exists error 261 | // /// (CASS_ERROR_SERVER_ALREADY_EXISTS) result type. 262 | // #[allow(cast_possible_truncation)] 263 | // pub fn table(&self) -> String { 264 | // unsafe { 265 | // let mut name = mem::zeroed(); 266 | // let mut length = mem::zeroed(); 267 | // match cass_error_result_table(self.0, &mut name, &mut length) { 268 | // CASS_OK => { 269 | // let slice = slice::from_raw_parts(name as *const u8, length as usize); 270 | // str::from_utf8(slice).expect("must be utf8").to_owned() 271 | // } 272 | // err => panic!("impossible: {:?}", err), 273 | // } 274 | // } 275 | // } 276 | // 277 | // /// Gets the affected function for the function failure error 278 | // /// (CASS_ERROR_SERVER_FUNCTION_FAILURE) result type. 279 | // #[allow(cast_possible_truncation)] 280 | // pub fn function(&self) -> String { 281 | // unsafe { 282 | // let mut name = mem::zeroed(); 283 | // let mut length = mem::zeroed(); 284 | // match cass_error_result_function(self.0, &mut name, &mut length) { 285 | // CASS_OK => { 286 | // let slice = slice::from_raw_parts(name as *const u8, length as usize); 287 | // str::from_utf8(slice).expect("must be utf8").to_owned() 288 | // } 289 | // err => panic!("impossible: {:?}", err), 290 | // } 291 | // } 292 | // } 293 | // 294 | // /// Gets the number of argument types for the function failure error 295 | // /// (CASS_ERROR_SERVER_FUNCTION_FAILURE) result type. 296 | // pub fn num_arg_types(error_result: CassErrorResult) -> usize { unsafe { cass_error_num_arg_types(error_result.0) } } 297 | // 298 | // /// Gets the argument type at the specified index for the function failure 299 | // /// error (CASS_ERROR_SERVER_FUNCTION_FAILURE) result type. 300 | // pub fn arg_type(&self, index: usize, arg_type: &str) -> u32 { 301 | // unsafe { 302 | // let cstr = CString::new(arg_type).expect("must be utf8"); 303 | // cass_error_result_arg_type(self.0, 304 | // index, 305 | // &mut cstr.as_ptr(), 306 | // &mut (cstr.to_bytes().len())) as u32 307 | // } 308 | // } 309 | // } 310 | // impl Drop for CassErrorResult { 311 | // fn drop(&mut self) { unsafe { cass_error_result_free(self.0) } } 312 | // } 313 | // 314 | // impl CassError { 315 | // pub fn new(err:_CassError) -> Self { 316 | // CassError(err) 317 | // } 318 | // fn result_from(self, t:T) -> Result { 319 | // match self.0 { 320 | // CASS_OK => Ok(t), 321 | // err => Err(Error::from(err.into())) 322 | // } 323 | // } 324 | 325 | fn pointer_to_string<'a>(c_buf: *const c_char) -> &'a str { 326 | let buf: &[u8] = unsafe { CStr::from_ptr(c_buf).to_bytes() }; 327 | str::from_utf8(buf).unwrap() 328 | } 329 | // /// Gets the textual description for this error 330 | // pub fn desc(&self) -> &str { 331 | // { 332 | // CassError::pointer_to_string(unsafe { cass_error_desc(self.0) }) 333 | // // match *self { 334 | // // CassError::Lib(ref err) => CassError::pointer_to_string(cass_error_desc(err.err)), 335 | // // CassError::Ssl(ref err) => CassError::pointer_to_string(cass_error_desc(err.0)), 336 | // // CassError::Server(ref err) => CassError::pointer_to_string(cass_error_desc(err.0)), 337 | // // CassError::Rust(ref err) => { 338 | // // match err { 339 | // // &CassRustError::NulInString(_) => "Tried to create a CString with a nul in the middle", 340 | // // /// /FIXME how do i return a slice created from self? 341 | // // &CassRustError::BadAddress(_) => "Tried to parse an invalid ip address", 342 | // // } 343 | // // } 344 | // // } 345 | // } 346 | // } 347 | // } 348 | -------------------------------------------------------------------------------- /src/cassandra/future.rs: -------------------------------------------------------------------------------- 1 | use Session; 2 | 3 | use cassandra::error::{CassError, CassErrorResult}; 4 | use cassandra::prepared::PreparedStatement; 5 | use cassandra::result::CassResult; 6 | use cassandra::util::Protected; 7 | use cassandra_sys::CASS_OK; 8 | 9 | use cassandra_sys::CassFuture as _Future; 10 | use cassandra_sys::CassFutureCallback as _CassFutureCallback; 11 | use cassandra_sys::cass_future_custom_payload_item; 12 | use cassandra_sys::cass_future_custom_payload_item_count; 13 | use cassandra_sys::cass_future_error_code; 14 | use cassandra_sys::cass_future_error_message; 15 | // use cassandra_sys::CassResult as _CassResult; 16 | use cassandra_sys::cass_future_free; 17 | use cassandra_sys::cass_future_get_error_result; 18 | use cassandra_sys::cass_future_get_prepared; 19 | use cassandra_sys::cass_future_get_result; 20 | use cassandra_sys::cass_future_ready; 21 | use cassandra_sys::cass_future_set_callback; 22 | use cassandra_sys::cass_future_wait; 23 | use cassandra_sys::cass_future_wait_timed; 24 | 25 | use cassandra_sys::cass_true; 26 | use errors::*; 27 | use std::mem; 28 | use std::os::raw; 29 | use std::slice; 30 | use std::str; 31 | 32 | /// A CQL Future representing the status of any asynchronous calls to Cassandra 33 | #[derive(Debug)] 34 | pub struct Future(*mut _Future); 35 | 36 | /// A callback registered to execute when the future returns 37 | #[derive(Debug)] 38 | pub struct FutureCallback(_CassFutureCallback); 39 | 40 | impl Drop for Future { 41 | /// Frees a future instance. A future can be freed anytime. 42 | fn drop(&mut self) { unsafe { cass_future_free(self.0) } } 43 | } 44 | 45 | impl Future { 46 | /// Sets a callback that is called when a future is set 47 | pub unsafe fn set_callback(&mut self, callback: FutureCallback, data: *mut raw::c_void) -> Result<&mut Self> { 48 | cass_future_set_callback(self.0, callback.0, data).to_result(self).chain_err(|| "") 49 | } 50 | 51 | /// Gets the set status of the future. 52 | pub fn ready(&mut self) -> bool { unsafe { cass_future_ready(self.0) == cass_true } } 53 | 54 | /// Wait for the future to be set with either a result or error. 55 | /// 56 | /// Important: Do not wait in a future callback. Waiting in a future 57 | /// callback will cause a deadlock. 58 | pub fn wait(self) -> Result<()> { 59 | unsafe { 60 | cass_future_wait(self.0); 61 | self.error_code() 62 | } 63 | } 64 | 65 | /// Wait for the future to be set or timeout. 66 | pub fn wait_timed(&mut self, timeout_us: u64) -> bool { 67 | unsafe { cass_future_wait_timed(self.0, timeout_us) == cass_true } 68 | } 69 | 70 | /// Gets the result of a successful future. If the future is not ready this method will 71 | /// wait for the future to be set. 72 | pub fn get_result(&self) -> CassResult { unsafe { CassResult::build((cass_future_get_result(self.0))) } } 73 | 74 | /// Gets the error result from a future that failed as a result of a server error. If the 75 | /// future is not ready this method will wait for the future to be set. 76 | pub fn get_error_result(&self) -> CassErrorResult { 77 | unsafe { CassErrorResult::build(cass_future_get_error_result(self.0)) } 78 | } 79 | 80 | /// Gets the error code from future. If the future is not ready this method will 81 | // wait for the future to be set. 82 | fn error_code(self) -> Result<()> { unsafe { cass_future_error_code(self.0).to_result(()).chain_err(|| "") } } 83 | 84 | /// Gets the error message from future. If the future is not ready this method will 85 | /// wait for the future to be set. 86 | pub fn error_message(&mut self) -> String { 87 | unsafe { 88 | let message = mem::zeroed(); 89 | let message_length = mem::zeroed(); 90 | cass_future_error_message(self.0, message, message_length); 91 | 92 | let slice: &[u8] = slice::from_raw_parts(message as *const u8, message_length as usize); 93 | str::from_utf8(slice).expect("must be utf8").to_owned() 94 | } 95 | } 96 | 97 | 98 | /// Gets a the number of custom payload items from a response future. If the future is not 99 | /// ready this method will wait for the future to be set. 100 | pub fn payload_item_count(&self) -> usize { unsafe { cass_future_custom_payload_item_count(self.0) } } 101 | 102 | /// Gets a custom payload item from a response future at the specified index. If the future is not 103 | /// ready this method will wait for the future to be set. 104 | pub fn payload_item(&self, index: usize) -> Result<(String, String)> { 105 | unsafe { 106 | let name = mem::zeroed(); 107 | let name_length = mem::zeroed(); 108 | let value = mem::zeroed(); 109 | let value_length = mem::zeroed(); 110 | match cass_future_custom_payload_item(self.0, index, name, name_length, value, value_length) { 111 | CASS_OK => { 112 | Ok((str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 113 | .expect("must be utf8") 114 | .to_owned(), 115 | str::from_utf8(slice::from_raw_parts(value as *const u8, value_length as usize)) 116 | .expect("must be utf8") 117 | .to_owned())) 118 | } 119 | err => Err(err.to_result("").unwrap().into()), 120 | } 121 | 122 | } 123 | } 124 | } 125 | 126 | #[must_use] 127 | /// The future result of an operation. 128 | /// It can represent a result if the operation completed successfully or an 129 | /// error if the operation failed. It can be waited on, polled or a callback 130 | /// can be attached. 131 | #[derive(Debug)] 132 | pub struct ResultFuture(*mut _Future); 133 | 134 | impl Drop for ResultFuture { 135 | fn drop(&mut self) { unsafe { cass_future_free(self.0) } } 136 | } 137 | 138 | impl ResultFuture { 139 | /// Blocks until the future returns or times out 140 | pub fn wait(&mut self) -> Result { 141 | unsafe { 142 | cass_future_wait(self.0); 143 | self.error_code() 144 | } 145 | } 146 | 147 | /// Gets the error code from future. If the future is not ready this method will 148 | /// wait for the future to be set. 149 | pub fn error_code(&mut self) -> Result { 150 | unsafe { 151 | let x = self.get(); 152 | let error_code = cass_future_error_code(self.0); 153 | match (x, error_code) { 154 | (Some(x), _) => Ok(x), 155 | (None, CASS_OK) => unimplemented!(), 156 | (None, err) => Err(err.to_result("").unwrap().into()), 157 | } 158 | } 159 | } 160 | 161 | /// Gets the error message from future. If the future is not ready this method will 162 | /// wait for the future to be set. 163 | pub fn error_message(&mut self) -> String { 164 | unsafe { 165 | let message = mem::zeroed(); 166 | let message_length = mem::zeroed(); 167 | cass_future_error_message(self.0, message, message_length); 168 | 169 | let slice = slice::from_raw_parts(message as *const u8, message_length as usize); 170 | str::from_utf8(slice).expect("must be utf8").to_owned() 171 | } 172 | } 173 | 174 | 175 | 176 | /// Gets the result of a successful future. If the future is not ready this method will 177 | /// wait for the future to be set. 178 | /// a None response indicates that there was an error 179 | pub fn get(&mut self) -> Option { 180 | unsafe { 181 | let result = cass_future_get_result(self.0); 182 | if result.is_null() { 183 | None 184 | } else { 185 | Some((CassResult::build(result))) 186 | } 187 | } 188 | } 189 | } 190 | 191 | 192 | /// The future result of an prepared statement. 193 | /// It can represent a result if the operation completed successfully or an 194 | /// error if the operation failed. It can be waited on, polled or a callback 195 | /// can be attached. 196 | #[derive(Debug)] 197 | pub struct PreparedFuture(*mut _Future); 198 | 199 | impl Drop for PreparedFuture { 200 | fn drop(&mut self) { unsafe { cass_future_free(self.0) } } 201 | } 202 | 203 | impl PreparedFuture { 204 | /// Wait for the future to be set with either a result or error. 205 | /// 206 | /// Important: Do not wait in a future callback. Waiting in a future 207 | /// callback will cause a deadlock. 208 | pub fn wait(&mut self) -> Result { 209 | unsafe { 210 | cass_future_wait(self.0); 211 | self.error_code() 212 | } 213 | } 214 | 215 | /// Gets the error code from future. If the future is not ready this method will 216 | /// wait for the future to be set. 217 | pub fn error_code(&mut self) -> Result { 218 | unsafe { cass_future_error_code(self.0).to_result(self.get()).chain_err(|| "") } 219 | } 220 | 221 | /// Gets the error message from future. If the future is not ready this method will 222 | /// wait for the future to be set. 223 | pub fn get(&mut self) -> PreparedStatement { unsafe { PreparedStatement::build(cass_future_get_prepared(self.0)) } } 224 | } 225 | 226 | #[derive(Debug)] 227 | pub struct ConnectFuture(*mut _Future); 228 | 229 | impl Protected<*mut _Future> for ConnectFuture { 230 | fn inner(&self) -> *mut _Future { self.0 } 231 | fn build(inner: *mut _Future) -> Self { ConnectFuture(inner) } 232 | } 233 | 234 | impl Drop for ConnectFuture { 235 | fn drop(&mut self) { unsafe { cass_future_free(self.0) } } 236 | } 237 | /// The future result of an attempt to create a new Cassandra session 238 | /// It can be waited on, polled or a callback 239 | /// can be attached. 240 | #[derive(Debug)] 241 | pub struct SessionFuture(*mut _Future); 242 | 243 | impl SessionFuture { 244 | /// blocks until the session connects or errors out 245 | pub fn wait(&mut self) -> Result<()> { 246 | unsafe { 247 | cass_future_wait(self.0); 248 | self.error_code() 249 | } 250 | } 251 | 252 | /// Gets the error code from future. If the future is not ready this method will 253 | /// wait for the future to be set. 254 | pub fn error_code(&self) -> Result<()> { unsafe { cass_future_error_code(self.0).to_result(()).chain_err(|| "") } } 255 | 256 | /// Gets the result of a successful future. If the future is not ready this method will 257 | /// wait for the future to be set. 258 | /// a None response indicates that there was an error 259 | pub fn get(&self) -> Option { 260 | unsafe { 261 | let result = cass_future_get_result(self.0); 262 | debug!("result is null: {}", result.is_null()); 263 | if result.is_null() { 264 | None 265 | } else { 266 | Some(CassResult::build(result)) 267 | } 268 | } 269 | } 270 | } 271 | 272 | impl Drop for SessionFuture { 273 | fn drop(&mut self) { unsafe { cass_future_free(self.0) } } 274 | } 275 | 276 | /// The future result of a session close statement. 277 | /// It can represent a result if the operation completed successfully or an 278 | /// error if the operation failed. It can be waited on, polled or a callback 279 | /// can be attached. 280 | #[derive(Debug)] 281 | pub struct CloseFuture(*mut _Future); 282 | 283 | impl Protected<*mut _Future> for Future { 284 | fn inner(&self) -> *mut _Future { self.0 } 285 | fn build(inner: *mut _Future) -> Self { Future(inner) } 286 | } 287 | 288 | impl Protected<*mut _Future> for PreparedFuture { 289 | fn inner(&self) -> *mut _Future { self.0 } 290 | fn build(inner: *mut _Future) -> Self { PreparedFuture(inner) } 291 | } 292 | 293 | impl Protected<*mut _Future> for ResultFuture { 294 | fn inner(&self) -> *mut _Future { self.0 } 295 | fn build(inner: *mut _Future) -> Self { ResultFuture(inner) } 296 | } 297 | 298 | impl Protected<*mut _Future> for SessionFuture { 299 | fn inner(&self) -> *mut _Future { self.0 } 300 | fn build(inner: *mut _Future) -> Self { SessionFuture(inner) } 301 | } 302 | 303 | impl Protected<*mut _Future> for CloseFuture { 304 | fn inner(&self) -> *mut _Future { self.0 } 305 | fn build(inner: *mut _Future) -> Self { CloseFuture(inner) } 306 | } 307 | 308 | 309 | impl Drop for CloseFuture { 310 | fn drop(&mut self) { unsafe { cass_future_free(self.0) } } 311 | } 312 | 313 | impl CloseFuture { 314 | /// Wait for the future to be set with either a result or error. 315 | /// 316 | /// Important: Do not wait in a future callback. Waiting in a future 317 | /// callback will cause a deadlock. 318 | pub fn wait(&self) -> Result<()> { 319 | unsafe { 320 | cass_future_wait(self.0); 321 | self.error_code() 322 | } 323 | } 324 | 325 | /// Gets the error code from future. If the future is not ready this method will 326 | /// wait for the future to be set. 327 | pub fn error_code(&self) -> Result<()> { unsafe { cass_future_error_code(self.0).to_result(()).chain_err(|| "") } } 328 | 329 | /// Gets the error message from future. If the future is not ready this method will 330 | /// wait for the future to be set. 331 | pub fn get(&self) -> PreparedStatement { unsafe { PreparedStatement::build(cass_future_get_prepared(self.0)) } } 332 | } 333 | -------------------------------------------------------------------------------- /src/cassandra/helpers.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::slice; 3 | 4 | #[allow(unused)] 5 | unsafe fn raw_byte_repr(ptr: &T) -> &[u8] { 6 | mem::transmute(slice::from_raw_parts(ptr as *const _ as *const u8, mem::size_of::())) 7 | } 8 | 9 | // ~ pub fn str_to_ref(mystr:&str) -> *const i8 { 10 | // ~ let s = CString::new(mystr).unwrap(); 11 | // ~ s.as_ptr() // s is still alive here } 12 | 13 | // ~ let cstr = CString::new(mystr.as_bytes()).unwrap(); 14 | // ~ cstr.as_bytes().as_ptr() as *const i8 15 | // ~ } 16 | 17 | // ~ pub fn str_to_ref(mystr: &str) -> *const i8 { 18 | // ~ let l = mystr.as_bytes(); 19 | // ~ unsafe { 20 | // ~ let b = alloc::heap::allocate(mystr.len()+1, 8); 21 | // ~ let s = slice::from_raw_parts_mut(b, mystr.len()+1); 22 | // ~ slice::bytes::copy_memory(s, l); 23 | // ~ s[mystr.len()] = 0; 24 | // ~ return b as *const i8; 25 | // ~ } 26 | // ~ } 27 | -------------------------------------------------------------------------------- /src/cassandra/inet.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use cassandra::error::CassError; 4 | use cassandra::util::Protected; 5 | use cassandra_sys::CASS_OK; 6 | use cassandra_sys::CassInet as _Inet; 7 | use cassandra_sys::cass_inet_from_string; 8 | use cassandra_sys::cass_inet_init_v4; 9 | use cassandra_sys::cass_inet_init_v6; 10 | use cassandra_sys::cass_inet_string; 11 | use errors::*; 12 | use std::default::Default; 13 | // use std::ffi::NulError; 14 | use std::ffi::CStr; 15 | use std::ffi::CString; 16 | use std::fmt; 17 | use std::fmt::{Debug, Formatter}; 18 | use std::mem; 19 | use std::net::{Ipv4Addr, Ipv6Addr}; 20 | use std::net::SocketAddr; 21 | use std::str::FromStr; 22 | use std::string::ToString; 23 | // use cassandra::error::CassLibError; 24 | 25 | #[repr(C)] 26 | /// Cassandra's version of an IP address 27 | 28 | pub struct Inet(_Inet); 29 | 30 | impl Debug for Inet { 31 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "can't format an inet") } 32 | } 33 | 34 | impl Protected<_Inet> for Inet { 35 | fn inner(&self) -> _Inet { self.0 } 36 | fn build(inner: _Inet) -> Self { Inet(inner) } 37 | } 38 | 39 | impl Default for Inet { 40 | fn default() -> Inet { unsafe { ::std::mem::zeroed() } } 41 | } 42 | 43 | /// Lets various things get converted to a Inet 44 | pub trait AsInet { 45 | /// Converts to a Cassandra Inet 46 | fn as_cass_inet(&self) -> Inet; 47 | } 48 | 49 | impl AsInet for SocketAddr { 50 | fn as_cass_inet(&self) -> Inet { 51 | match *self { 52 | SocketAddr::V4(ipv4_addr) => unsafe { Inet(cass_inet_init_v4(ipv4_addr.ip().octets().as_ptr())) }, 53 | SocketAddr::V6(ipv6_addr) => { 54 | unsafe { 55 | let seg = ipv6_addr.ip().segments(); 56 | // FIXME does this really work? 57 | Inet(cass_inet_init_v6(seg.as_ptr() as *const u8)) 58 | } 59 | } 60 | } 61 | // ~ let foo:_Inet = Default::default(); 62 | // ~ Inet(foo) 63 | } 64 | } 65 | 66 | /// The types of errors that can occur when trying to parse an Inet String 67 | // pub enum InetParseError { 68 | // ///Don't put a null in a string, silly! 69 | // NulInString(NulError), 70 | // ///Not a valiid address 71 | // LibBadParams(CassLibError), 72 | // } 73 | 74 | impl FromStr for Inet { 75 | type Err = Error; 76 | 77 | fn from_str(s: &str) -> Result { 78 | unsafe { 79 | let mut inet = mem::zeroed(); 80 | 81 | let str = CString::new(s).expect("must be utf8"); 82 | match cass_inet_from_string(str.as_ptr(), &mut inet) { 83 | CASS_OK => Ok(Inet(inet)), 84 | err => err.to_result(Inet(inet)).chain_err(|| ""), 85 | } 86 | } 87 | } 88 | } 89 | 90 | impl ToString for Inet { 91 | fn to_string(&self) -> String { 92 | unsafe { 93 | let mut inet_str = mem::zeroed(); 94 | cass_inet_string(self.0, &mut inet_str); 95 | CStr::from_ptr(&inet_str).to_string_lossy().into_owned() 96 | } 97 | } 98 | } 99 | 100 | /// Converts from an Cassandra Inet address 101 | pub trait FromInet { 102 | /// Converts from an Cassandra Inet address 103 | fn from_cass_inet(inet: Inet) -> Self; 104 | } 105 | 106 | impl FromInet for Ipv4Addr { 107 | fn from_cass_inet(inet: Inet) -> Self { 108 | let raw_addr: [u8; 16] = inet.0.address; 109 | match inet.0.address_length { 110 | 4 => Ipv4Addr::new(raw_addr[0], raw_addr[1], raw_addr[2], raw_addr[3]), 111 | 16 => panic!(), 112 | unsupported => panic!("impossible inet type: {:?}", unsupported), 113 | } 114 | } 115 | } 116 | 117 | impl FromInet for Ipv6Addr { 118 | fn from_cass_inet(inet: Inet) -> Self { 119 | let raw_addr: [u8; 16] = inet.0.address; 120 | match inet.0.address_length { 121 | 4 => panic!(), 122 | 16 => { 123 | Ipv6Addr::new((raw_addr[1] as u16) << (8 + raw_addr[0] as u16), 124 | (raw_addr[3] as u16) << (8 + raw_addr[2] as u16), 125 | (raw_addr[5] as u16) << (8 + raw_addr[4] as u16), 126 | (raw_addr[7] as u16) << (8 + raw_addr[6] as u16), 127 | (raw_addr[9] as u16) << (8 + raw_addr[8] as u16), 128 | (raw_addr[11] as u16) << (8 + raw_addr[10] as u16), 129 | (raw_addr[13] as u16) << (8 + raw_addr[12] as u16), 130 | (raw_addr[15] as u16) << (8 + raw_addr[14] as u16)) 131 | } 132 | unsupported => panic!("impossible inet type: {}", unsupported), 133 | } 134 | } 135 | } 136 | 137 | impl Inet { 138 | /// Constructs an inet v4 object. 139 | pub fn cass_inet_init_v4(address: Ipv4Addr) -> Inet { 140 | unsafe { Inet(cass_inet_init_v4(address.octets().as_ptr())) } 141 | } 142 | 143 | /// Constructs an inet v6 object. 144 | pub fn cass_inet_init_v6(address: Ipv6Addr) -> Inet { 145 | unsafe { Inet(cass_inet_init_v6(address.segments().as_ptr() as *const u8)) } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/cassandra/iterator.rs: -------------------------------------------------------------------------------- 1 | use cassandra::data_type::ConstDataType; 2 | use cassandra::field::Field; 3 | use cassandra::schema::aggregate_meta::AggregateMeta; 4 | use cassandra::schema::column_meta::ColumnMeta; 5 | use cassandra::schema::function_meta::FunctionMeta; 6 | use cassandra::schema::keyspace_meta::KeyspaceMeta; 7 | use cassandra::schema::table_meta::TableMeta; 8 | use cassandra::util::Protected; 9 | use cassandra::value::Value; 10 | 11 | use cassandra_sys::CASS_OK; 12 | 13 | // use cassandra_sys::CassIteratorType as _CassIteratorType; 14 | use cassandra_sys::CassIterator as _CassIterator; 15 | use cassandra_sys::cass_false; 16 | // use cassandra_sys::cass_iterator_type; 17 | use cassandra_sys::cass_iterator_free; 18 | use cassandra_sys::cass_iterator_get_aggregate_meta; 19 | use cassandra_sys::cass_iterator_get_column_meta; 20 | use cassandra_sys::cass_iterator_get_function_meta; 21 | use cassandra_sys::cass_iterator_get_keyspace_meta; 22 | use cassandra_sys::cass_iterator_get_map_key; 23 | use cassandra_sys::cass_iterator_get_map_value; 24 | use cassandra_sys::cass_iterator_get_meta_field_name; 25 | use cassandra_sys::cass_iterator_get_meta_field_value; 26 | use cassandra_sys::cass_iterator_get_table_meta; 27 | use cassandra_sys::cass_iterator_get_user_type; 28 | use cassandra_sys::cass_iterator_get_value; 29 | use cassandra_sys::cass_iterator_next; 30 | use cassandra_sys::cass_true; 31 | use std::{mem, slice, str}; 32 | 33 | /// Iterates over the aggregate metadata entries(??) 34 | #[derive(Debug)] 35 | pub struct AggregateIterator(*mut _CassIterator); 36 | 37 | impl Drop for AggregateIterator { 38 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 39 | } 40 | 41 | impl Iterator for AggregateIterator { 42 | type Item = AggregateMeta; 43 | fn next(&mut self) -> Option<::Item> { 44 | unsafe { 45 | match cass_iterator_next(self.0) { 46 | cass_false => None, 47 | cass_true => { 48 | let field_value = cass_iterator_get_aggregate_meta(self.0); 49 | Some(AggregateMeta::build(field_value)) 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | /// Iterater over the fields of a UDT 57 | #[derive(Debug)] 58 | pub struct UserTypeIterator(*mut _CassIterator); 59 | 60 | impl Drop for UserTypeIterator { 61 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 62 | } 63 | 64 | impl Iterator for UserTypeIterator { 65 | type Item = ConstDataType; 66 | fn next(&mut self) -> Option<::Item> { 67 | unsafe { 68 | match cass_iterator_next(self.0) { 69 | cass_false => None, 70 | cass_true => Some(ConstDataType(cass_iterator_get_user_type(self.0))), 71 | } 72 | } 73 | } 74 | } 75 | 76 | impl UserTypeIterator { 77 | // pub fn get_field_name(&mut self)-> Value {unsafe{ 78 | // 79 | // Value::new(cass_iterator_get_user_type_field_name(self.0)) 80 | // }} 81 | } 82 | 83 | 84 | /// Iterater over the function metadata entries(??) 85 | #[derive(Debug)] 86 | pub struct FunctionIterator(*mut _CassIterator); 87 | 88 | impl Iterator for FunctionIterator { 89 | type Item = FunctionMeta; 90 | fn next(&mut self) -> Option<::Item> { 91 | unsafe { 92 | match cass_iterator_next(self.0) { 93 | cass_false => None, 94 | cass_true => Some(FunctionMeta::build(cass_iterator_get_function_meta(self.0))), 95 | } 96 | } 97 | } 98 | } 99 | 100 | 101 | /// Iterater over the table's metadata entries(??) 102 | #[derive(Debug)] 103 | pub struct TableIterator(*mut _CassIterator); 104 | 105 | impl Iterator for TableIterator { 106 | type Item = TableMeta; 107 | fn next(&mut self) -> Option<::Item> { 108 | unsafe { 109 | match cass_iterator_next(self.0) { 110 | cass_false => None, 111 | cass_true => Some(TableMeta::build(cass_iterator_get_table_meta(self.0))), 112 | } 113 | } 114 | } 115 | } 116 | 117 | /// Iterater over the keyspace's metadata entries(??) 118 | #[derive(Debug)] 119 | pub struct KeyspaceIterator(*mut _CassIterator); 120 | 121 | impl Iterator for KeyspaceIterator { 122 | type Item = KeyspaceMeta; 123 | fn next(&mut self) -> Option<::Item> { 124 | unsafe { 125 | match cass_iterator_next(self.0) { 126 | cass_false => None, 127 | cass_true => Some(KeyspaceMeta::build(cass_iterator_get_keyspace_meta(self.0))), 128 | } 129 | } 130 | } 131 | } 132 | 133 | /// Iterater over the columns's metadata entries(??) 134 | #[derive(Debug)] 135 | pub struct ColumnIterator(*mut _CassIterator); 136 | 137 | impl Iterator for ColumnIterator { 138 | type Item = ColumnMeta; 139 | fn next(&mut self) -> Option<::Item> { 140 | unsafe { 141 | match cass_iterator_next(self.0) { 142 | cass_false => None, 143 | cass_true => Some(ColumnMeta::build(cass_iterator_get_column_meta(self.0))), 144 | } 145 | } 146 | } 147 | } 148 | 149 | /// Iterater over the field's metadata entries(??) 150 | #[derive(Debug)] 151 | pub struct FieldIterator(*mut _CassIterator); 152 | 153 | impl Iterator for FieldIterator { 154 | type Item = Field; 155 | #[allow(cast_possible_truncation)] 156 | fn next(&mut self) -> Option<::Item> { 157 | unsafe { 158 | match cass_iterator_next(self.0) { 159 | cass_false => None, 160 | cass_true => { 161 | let mut name = mem::zeroed(); 162 | let mut name_length = mem::zeroed(); 163 | match cass_iterator_get_meta_field_name(self.0, &mut name, &mut name_length) { 164 | CASS_OK => { 165 | let slice = slice::from_raw_parts(name as *const u8, name_length as usize); 166 | Some(Field { 167 | name: str::from_utf8(slice).expect("must be utf8").to_owned(), 168 | value: Value::build(cass_iterator_get_meta_field_value(self.0)), 169 | }) 170 | } 171 | err => panic!("FIXME: no error handling. Err {:?}", err), 172 | } 173 | } 174 | } 175 | } 176 | } 177 | } 178 | 179 | 180 | // pub struct CassIteratorType(_CassIteratorType); 181 | 182 | // impl CassIteratorType { 183 | // pub fn new(_type: _CassIteratorType) -> Self { CassIteratorType(_type) } 184 | // } 185 | 186 | // impl Protected<*mut _Batch> for CassIterator { 187 | // fn inner(&self) -> *mut _CassIterator { 188 | // self.0 189 | // } 190 | // fn build(inner: *mut _CassIterator) -> Self { 191 | // CassIterator(inner) 192 | // } 193 | // } 194 | 195 | impl Protected<*mut _CassIterator> for UserTypeIterator { 196 | fn inner(&self) -> *mut _CassIterator { self.0 } 197 | fn build(inner: *mut _CassIterator) -> Self { UserTypeIterator(inner) } 198 | } 199 | 200 | impl Protected<*mut _CassIterator> for AggregateIterator { 201 | fn inner(&self) -> *mut _CassIterator { self.0 } 202 | fn build(inner: *mut _CassIterator) -> Self { AggregateIterator(inner) } 203 | } 204 | 205 | impl Protected<*mut _CassIterator> for FunctionIterator { 206 | fn inner(&self) -> *mut _CassIterator { self.0 } 207 | fn build(inner: *mut _CassIterator) -> Self { FunctionIterator(inner) } 208 | } 209 | 210 | impl Protected<*mut _CassIterator> for KeyspaceIterator { 211 | fn inner(&self) -> *mut _CassIterator { self.0 } 212 | fn build(inner: *mut _CassIterator) -> Self { KeyspaceIterator(inner) } 213 | } 214 | 215 | impl Protected<*mut _CassIterator> for FieldIterator { 216 | fn inner(&self) -> *mut _CassIterator { self.0 } 217 | fn build(inner: *mut _CassIterator) -> Self { FieldIterator(inner) } 218 | } 219 | 220 | impl Protected<*mut _CassIterator> for ColumnIterator { 221 | fn inner(&self) -> *mut _CassIterator { self.0 } 222 | fn build(inner: *mut _CassIterator) -> Self { ColumnIterator(inner) } 223 | } 224 | 225 | impl Protected<*mut _CassIterator> for TableIterator { 226 | fn inner(&self) -> *mut _CassIterator { self.0 } 227 | fn build(inner: *mut _CassIterator) -> Self { TableIterator(inner) } 228 | } 229 | 230 | impl Protected<*mut _CassIterator> for MapIterator { 231 | fn inner(&self) -> *mut _CassIterator { self.0 } 232 | fn build(inner: *mut _CassIterator) -> Self { MapIterator(inner) } 233 | } 234 | 235 | impl Protected<*mut _CassIterator> for SetIterator { 236 | fn inner(&self) -> *mut _CassIterator { self.0 } 237 | fn build(inner: *mut _CassIterator) -> Self { SetIterator(inner) } 238 | } 239 | 240 | 241 | /// Iterater over the set's metadata entries(??) 242 | #[derive(Debug)] 243 | pub struct SetIterator(*mut _CassIterator); 244 | 245 | // impl<'a> Display for &'a SetIterator { 246 | // fn fmt(&self, f:&mut Formatter) -> fmt::Result { 247 | // for item in self { 248 | // try!(write!(f, "{}\t", item)); 249 | // } 250 | // Ok(()) 251 | // } 252 | // } 253 | 254 | impl Drop for SetIterator { 255 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 256 | } 257 | 258 | 259 | impl Iterator for SetIterator { 260 | type Item = Value; 261 | 262 | fn next(&mut self) -> Option<::Item> { 263 | unsafe { 264 | match cass_iterator_next(self.0) { 265 | cass_false => None, 266 | cass_true => Some(self.get_value()), 267 | } 268 | } 269 | } 270 | } 271 | 272 | impl SetIterator { 273 | fn get_value(&mut self) -> Value { unsafe { Value::build(cass_iterator_get_value(self.0)) } } 274 | } 275 | 276 | /// An iterator over the k/v pair in the map 277 | #[derive(Debug)] 278 | pub struct MapIterator(*mut _CassIterator); 279 | 280 | impl MapIterator { 281 | fn get_key(&mut self) -> Value { unsafe { Value::build(cass_iterator_get_map_key(self.0)) } } 282 | fn get_value(&mut self) -> Value { unsafe { Value::build(cass_iterator_get_map_value(self.0)) } } 283 | 284 | /// Gets the next k/v pair in the map 285 | pub fn get_pair(&mut self) -> (Value, Value) { (self.get_key(), self.get_value()) } 286 | } 287 | 288 | /// An iterator over the elements of a Cassandra tuple 289 | #[derive(Debug)] 290 | pub struct TupleIterator(pub *mut _CassIterator); 291 | 292 | impl Drop for TupleIterator { 293 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 294 | } 295 | 296 | impl Iterator for TupleIterator { 297 | type Item = Value; 298 | fn next(&mut self) -> Option<::Item> { 299 | unsafe { 300 | match cass_iterator_next(self.0) { 301 | cass_false => None, 302 | cass_true => Some(self.get_value()), 303 | } 304 | } 305 | } 306 | } 307 | 308 | impl TupleIterator { 309 | fn get_value(&mut self) -> Value { unsafe { Value::build(cass_iterator_get_value(self.0)) } } 310 | } 311 | 312 | 313 | 314 | impl Drop for MapIterator { 315 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 316 | } 317 | 318 | impl Iterator for MapIterator { 319 | type Item = (Value, Value); 320 | fn next(&mut self) -> Option<::Item> { 321 | unsafe { 322 | match cass_iterator_next(self.0) { 323 | cass_false => None, 324 | cass_true => Some(self.get_pair()), 325 | } 326 | } 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /src/cassandra/log.rs: -------------------------------------------------------------------------------- 1 | use cassandra_sys::CassLogLevel; 2 | 3 | use cassandra_sys::CassLogMessage; 4 | 5 | // use cassandra_sys::cass_log_cleanup; @deprecated 6 | use cassandra_sys::cass_log_level_string; 7 | use cassandra_sys::cass_log_set_callback; 8 | use cassandra_sys::cass_log_set_level; 9 | use std::ffi::CStr; 10 | use std::os::raw; 11 | // use cassandra_sys::cass_log_set_queue_size; @deprecated 12 | 13 | 14 | #[repr(C)] 15 | /// The possible logging levels that can be set 16 | #[derive(Debug)] 17 | pub struct LogLevel(CassLogLevel); 18 | 19 | 20 | impl LogLevel { 21 | /// Gets the string for a log level. 22 | pub fn as_string(&self) -> String { 23 | unsafe { CStr::from_ptr(cass_log_level_string(self.0)).to_str().expect("must be utf8").to_owned() } 24 | } 25 | } 26 | 27 | /// A callback that's used to handle logging. 28 | pub type CassLogCallback = Option; 29 | 30 | /// Sets the log level. 31 | /// 32 | /// Note: This needs to be done before any call that might log, such as 33 | /// any of the cass_cluster_*() or cass_ssl_*() functions. 34 | /// Default: CASS_LOG_WARN 35 | pub fn set_level(level: LogLevel) { unsafe { cass_log_set_level(level.0) } } 36 | 37 | /// Sets a callback for handling logging events. 38 | pub fn set_callback(callback: CassLogCallback, mut data: Vec) { 39 | unsafe { cass_log_set_callback(callback, &mut data as *mut _ as *mut raw::c_void) } 40 | } 41 | -------------------------------------------------------------------------------- /src/cassandra/metrics.rs: -------------------------------------------------------------------------------- 1 | use cassandra::util::Protected; 2 | use cassandra_sys::CassMetrics as _CassMetrics; 3 | 4 | /// A view into server metrics FIXME not meaingfully implemented 5 | #[derive(Debug)] 6 | pub struct SessionMetrics(*const _CassMetrics); 7 | 8 | 9 | impl Protected<*const _CassMetrics> for SessionMetrics { 10 | fn inner(&self) -> *const _CassMetrics { self.0 } 11 | fn build(inner: *const _CassMetrics) -> Self { SessionMetrics(inner) } 12 | } 13 | -------------------------------------------------------------------------------- /src/cassandra/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(dead_code)] 3 | #![allow(missing_copy_implementations)] 4 | 5 | pub mod cass_list; 6 | pub mod cass_map; 7 | pub mod collection; 8 | pub mod cass_set; 9 | -------------------------------------------------------------------------------- /src/cassandra/policy/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod retry; 2 | -------------------------------------------------------------------------------- /src/cassandra/policy/retry.rs: -------------------------------------------------------------------------------- 1 | use cassandra::util::Protected; 2 | use cassandra_sys::CassRetryPolicy as _RetryPolicy; 3 | use cassandra_sys::cass_retry_policy_default_new; 4 | use cassandra_sys::cass_retry_policy_downgrading_consistency_new; 5 | use cassandra_sys::cass_retry_policy_fallthrough_new; 6 | use cassandra_sys::cass_retry_policy_free; 7 | use cassandra_sys::cass_retry_policy_logging_new; 8 | 9 | /// The selected retry policy 10 | #[derive(Debug)] 11 | pub struct RetryPolicy(*mut _RetryPolicy); 12 | 13 | impl Protected<*mut _RetryPolicy> for RetryPolicy { 14 | fn inner(&self) -> *mut _RetryPolicy { self.0 } 15 | fn build(inner: *mut _RetryPolicy) -> Self { RetryPolicy(inner) } 16 | } 17 | 18 | impl RetryPolicy { 19 | /// The default retry policy 20 | pub fn default_new() -> Self { unsafe { RetryPolicy(cass_retry_policy_default_new()) } } 21 | 22 | /// An auto-CL-downgrading consistency level 23 | pub fn downgrading_consistency_new() -> Self { 24 | unsafe { RetryPolicy(cass_retry_policy_downgrading_consistency_new()) } 25 | } 26 | 27 | /// a fallthrough retry policy 28 | pub fn fallthrough_new() -> Self { unsafe { RetryPolicy(cass_retry_policy_fallthrough_new()) } } 29 | 30 | /// The a logging retry policy 31 | pub fn logging_new(child_retry_policy: RetryPolicy) -> Self { 32 | unsafe { RetryPolicy(cass_retry_policy_logging_new(child_retry_policy.0)) } 33 | } 34 | } 35 | 36 | impl Drop for RetryPolicy { 37 | fn drop(&mut self) { 38 | unsafe { 39 | cass_retry_policy_free(self.0); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/cassandra/prepared.rs: -------------------------------------------------------------------------------- 1 | use cassandra::data_type::ConstDataType; 2 | use cassandra::statement::Statement; 3 | use cassandra::util::Protected; 4 | 5 | use cassandra_sys::CassPrepared as _PreparedStatement; 6 | use cassandra_sys::cass_prepared_bind; 7 | use cassandra_sys::cass_prepared_free; 8 | use cassandra_sys::cass_prepared_parameter_data_type; 9 | use cassandra_sys::cass_prepared_parameter_data_type_by_name; 10 | use cassandra_sys::cass_prepared_parameter_name; 11 | use std::{mem, slice, str}; 12 | use std::ffi::CString; 13 | 14 | /// A statement that has been prepared against at least one Cassandra node. 15 | /// Instances of this class should not be created directly, but through Session.prepare(). 16 | #[derive(Debug)] 17 | pub struct PreparedStatement(*const _PreparedStatement); 18 | 19 | unsafe impl Sync for PreparedStatement {} 20 | unsafe impl Send for PreparedStatement {} 21 | 22 | impl Drop for PreparedStatement { 23 | /// Frees a prepared statement 24 | fn drop(&mut self) { 25 | if !self.0.is_null() { 26 | unsafe { cass_prepared_free(self.0) } 27 | } 28 | } 29 | } 30 | 31 | 32 | impl Protected<*const _PreparedStatement> for PreparedStatement { 33 | fn inner(&self) -> *const _PreparedStatement { self.0 } 34 | fn build(inner: *const _PreparedStatement) -> Self { PreparedStatement(inner) } 35 | } 36 | 37 | impl PreparedStatement { 38 | /// Creates a bound statement from a pre-prepared statement. 39 | pub fn bind(&self) -> Statement { unsafe { Statement::build(cass_prepared_bind(self.0)) } } 40 | 41 | /// Gets the name of a parameter at the specified index. 42 | #[allow(cast_possible_truncation)] 43 | pub fn parameter_name(&self, index: usize) -> Result<&str, str::Utf8Error> { 44 | unsafe { 45 | let mut name = mem::zeroed(); 46 | let mut name_length = mem::zeroed(); 47 | cass_prepared_parameter_name(self.0, index, &mut name, &mut name_length); 48 | str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 49 | } 50 | } 51 | 52 | /// Gets the data type of a parameter at the specified index. 53 | /// 54 | /// Returns a reference to the data type of the parameter. Do not free 55 | /// this reference as it is bound to the lifetime of the prepared. 56 | pub fn parameter_data_type(&self, index: usize) -> ConstDataType { 57 | unsafe { ConstDataType(cass_prepared_parameter_data_type(self.0, index)) } 58 | } 59 | 60 | /// Gets the data type of a parameter for the specified name. 61 | /// 62 | /// Returns a reference to the data type of the parameter. Do not free 63 | /// this reference as it is bound to the lifetime of the prepared. 64 | pub fn parameter_data_type_by_name(&self, name: &str) -> ConstDataType { 65 | unsafe { 66 | ConstDataType(cass_prepared_parameter_data_type_by_name(self.0, 67 | CString::new(name) 68 | .expect("must be utf8") 69 | .as_ptr())) 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/cassandra/result.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(dead_code)] 3 | #![allow(missing_copy_implementations)] 4 | 5 | use cassandra::data_type::ConstDataType; 6 | use cassandra::error::CassError; 7 | use cassandra::row::Row; 8 | use cassandra::util::Protected; 9 | 10 | use cassandra::value::ValueType; 11 | use cassandra_sys::CassIterator as _CassIterator; 12 | 13 | use cassandra_sys::CassResult as _CassResult; 14 | use cassandra_sys::cass_false; 15 | use cassandra_sys::cass_iterator_free; 16 | use cassandra_sys::cass_iterator_from_result; 17 | use cassandra_sys::cass_iterator_get_row; 18 | use cassandra_sys::cass_iterator_next; 19 | use cassandra_sys::cass_result_column_count; 20 | use cassandra_sys::cass_result_column_data_type; 21 | use cassandra_sys::cass_result_column_name; 22 | use cassandra_sys::cass_result_column_type; 23 | use cassandra_sys::cass_result_first_row; 24 | #[allow(unused_imports)] 25 | use cassandra_sys::cass_result_free; 26 | use cassandra_sys::cass_result_has_more_pages; 27 | use cassandra_sys::cass_result_paging_state_token; 28 | use cassandra_sys::cass_result_row_count; 29 | 30 | use cassandra_sys::cass_true; 31 | use errors::*; 32 | use std::ffi::CString; 33 | use std::fmt; 34 | use std::fmt::Debug; 35 | use std::fmt::Display; 36 | use std::fmt::Formatter; 37 | use std::mem; 38 | use std::slice; 39 | use std::str; 40 | 41 | /// The result of a query. 42 | /// A result object is read-only and is thread-safe to read or iterate over 43 | /// concurrently. 44 | pub struct CassResult(*const _CassResult); 45 | unsafe impl Sync for CassResult {} 46 | unsafe impl Send for CassResult {} 47 | 48 | impl Protected<*const _CassResult> for CassResult { 49 | fn inner(&self) -> *const _CassResult { self.0 } 50 | fn build(inner: *const _CassResult) -> Self { CassResult(inner) } 51 | } 52 | 53 | impl Debug for CassResult { 54 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 55 | write!(f, "Result row count: {:?}\n", self.row_count())?; 56 | for row in self.iter() { 57 | write!(f, "{:?}\n", row)?; 58 | } 59 | Ok(()) 60 | } 61 | } 62 | 63 | impl Display for CassResult { 64 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 65 | write!(f, "Result row count: {}\n", self.row_count())?; 66 | for row in self.iter() { 67 | write!(f, "{}\n", row)?; 68 | } 69 | Ok(()) 70 | } 71 | } 72 | 73 | // FIXME Understand why this drop results in double freeing when binding by name 74 | // impl Drop for CassResult { 75 | // fn drop(&mut self) { 76 | // unsafe { cass_result_free(self.0) } 77 | // } 78 | // } 79 | 80 | impl CassResult { 81 | /// Gets the number of rows for the specified result. 82 | pub fn row_count(&self) -> u64 { unsafe { cass_result_row_count(self.0) as u64 } } 83 | 84 | /// Gets the number of columns per row for the specified result. 85 | pub fn column_count(&self) -> u64 { unsafe { cass_result_column_count(self.0) as u64 } } 86 | 87 | /// Gets the column name at index for the specified result. 88 | pub fn column_name(&self, index: usize) -> String { 89 | unsafe { 90 | let name = mem::zeroed(); 91 | let name_length = mem::zeroed(); 92 | cass_result_column_name(self.0, index, name, name_length); 93 | let slice = slice::from_raw_parts(name as *const u8, name_length as usize); 94 | str::from_utf8(slice).expect("must be utf8").to_owned() 95 | } 96 | } 97 | 98 | /// Gets the column type at index for the specified result. 99 | pub fn column_type(&self, index: usize) -> ValueType { 100 | unsafe { ValueType::build(cass_result_column_type(self.0, index)) } 101 | } 102 | 103 | /// Gets the column datatype at index for the specified result. 104 | pub fn column_data_type(&self, index: usize) -> ConstDataType { 105 | unsafe { ConstDataType(cass_result_column_data_type(self.0, index)) } 106 | } 107 | 108 | /// Gets the first row of the result. 109 | pub fn first_row(&self) -> Option { 110 | unsafe { 111 | match self.row_count() { 112 | 0 => None, 113 | _ => Some(Row::build(cass_result_first_row(self.0))), 114 | } 115 | } 116 | } 117 | 118 | /// Returns true if there are more pages. 119 | pub fn has_more_pages(&self) -> bool { unsafe { cass_result_has_more_pages(self.0) == cass_true } } 120 | 121 | /// Sets the statement's paging state. This can be used to get the next page of 122 | /// data in a multi-page query. 123 | /// 124 | /// Warning: The paging state should not be exposed to or come from 125 | /// untrusted environments. The paging state could be spoofed and potentially 126 | // used to gain access to other data. 127 | pub fn set_paging_state_token(&mut self, paging_state: &str) -> Result<&mut Self> { 128 | unsafe { 129 | let state = CString::new(paging_state).expect("must be utf8"); 130 | 131 | cass_result_paging_state_token(self.0, &mut state.as_ptr(), &mut (state.to_bytes().len())) 132 | .to_result(self) 133 | .chain_err(|| "") 134 | } 135 | } 136 | 137 | 138 | /// Creates a new iterator for the specified result. This can be 139 | /// used to iterate over rows in the result. 140 | pub fn iter(&self) -> ResultIterator { unsafe { ResultIterator(cass_iterator_from_result(self.0)) } } 141 | } 142 | 143 | /// An iterator over the results of a query 144 | #[derive(Debug)] 145 | pub struct ResultIterator(pub *mut _CassIterator); 146 | 147 | impl Drop for ResultIterator { 148 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 149 | } 150 | 151 | impl Iterator for ResultIterator { 152 | type Item = Row; 153 | fn next(&mut self) -> Option<::Item> { 154 | unsafe { 155 | match cass_iterator_next(self.0) { 156 | cass_false => None, 157 | cass_true => Some(self.get_row()), 158 | } 159 | } 160 | } 161 | } 162 | 163 | impl ResultIterator { 164 | /// Gets the next row in the result set 165 | pub fn get_row(&mut self) -> Row { unsafe { Row::build(cass_iterator_get_row(self.0)) } } 166 | } 167 | 168 | impl IntoIterator for CassResult { 169 | type Item = Row; 170 | type IntoIter = ResultIterator; 171 | 172 | fn into_iter(self) -> Self::IntoIter { self.iter() } 173 | } 174 | 175 | // impl<'a> IntoIterator for &'a CassandraResult { 176 | // type Item = Row; 177 | // type IntoIter = ResultIterator; 178 | // 179 | // fn into_iter(self) -> Self::IntoIter {unsafe{ 180 | // ResultIterator(cass_iterator_from_result(self.0)) 181 | // }} 182 | // } 183 | -------------------------------------------------------------------------------- /src/cassandra/row.rs: -------------------------------------------------------------------------------- 1 | use cassandra::column::Column; 2 | use cassandra::error::*; 3 | 4 | use cassandra::iterator::{MapIterator, SetIterator}; 5 | use cassandra::util::Protected; 6 | use cassandra::value::Value; 7 | use cassandra_sys::CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS; 8 | use cassandra_sys::CassIterator as _CassIterator; 9 | use cassandra_sys::CassRow as _Row; 10 | use cassandra_sys::cass_false; 11 | use cassandra_sys::cass_iterator_free; 12 | use cassandra_sys::cass_iterator_from_row; 13 | use cassandra_sys::cass_iterator_get_column; 14 | use cassandra_sys::cass_iterator_next; 15 | use cassandra_sys::cass_row_get_column; 16 | use cassandra_sys::cass_row_get_column_by_name; 17 | use cassandra_sys::cass_true; 18 | use errors::*; 19 | use std::ffi::CString; 20 | use std::fmt; 21 | use std::fmt::Debug; 22 | use std::fmt::Display; 23 | use std::fmt::Formatter; 24 | use std::iter; 25 | use std::iter::IntoIterator; 26 | 27 | /// A collection of column values. 28 | pub struct Row(*const _Row); 29 | 30 | impl Protected<*const _Row> for Row { 31 | fn inner(&self) -> *const _Row { self.0 } 32 | fn build(inner: *const _Row) -> Self { Row(inner) } 33 | } 34 | 35 | impl Debug for Row { 36 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 37 | for column in self { 38 | write!(f, "{:?}\t", Value::build(column.inner()))?; 39 | } 40 | Ok(()) 41 | } 42 | } 43 | 44 | impl Display for Row { 45 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 46 | for column in self { 47 | write!(f, "{}\t", Value::build(column.inner()))?; 48 | } 49 | Ok(()) 50 | } 51 | } 52 | 53 | /// Auto inferencing conversion from c* to rust 54 | pub trait AsRustType { 55 | /// convert while reading cassandra columns 56 | fn get_col(&self, index: usize) -> Result; 57 | 58 | /// convert while reading cassandra columns by name 59 | fn get_col_by_name(&self, name: S) -> Result 60 | where S: Into; 61 | } 62 | 63 | impl AsRustType for Row { 64 | fn get_col(&self, index: usize) -> Result { 65 | let col = self.get_column(index)?; 66 | col.get_bool() 67 | } 68 | 69 | fn get_col_by_name(&self, name: S) -> Result 70 | where S: Into { 71 | self.get_column_by_name(name)?.get_bool() 72 | } 73 | } 74 | 75 | impl AsRustType for Row { 76 | fn get_col(&self, index: usize) -> Result { 77 | let col = self.get_column(index)?; 78 | col.get_string() 79 | } 80 | 81 | fn get_col_by_name(&self, name: S) -> Result 82 | where S: Into { 83 | let col = self.get_column_by_name(name)?; 84 | col.get_string() 85 | } 86 | } 87 | 88 | impl AsRustType for Row { 89 | fn get_col(&self, index: usize) -> Result { 90 | let col = self.get_column(index)?; 91 | col.get_double() 92 | } 93 | 94 | fn get_col_by_name(&self, name: S) -> Result 95 | where S: Into { 96 | let col = self.get_column_by_name(name)?; 97 | col.get_double() 98 | } 99 | } 100 | 101 | impl AsRustType for Row { 102 | fn get_col(&self, index: usize) -> Result { 103 | let col = self.get_column(index)?; 104 | col.get_float() 105 | } 106 | 107 | fn get_col_by_name(&self, name: S) -> Result 108 | where S: Into { 109 | let col = self.get_column_by_name(name)?; 110 | col.get_float() 111 | } 112 | } 113 | 114 | impl AsRustType for Row { 115 | fn get_col(&self, index: usize) -> Result { 116 | let col = self.get_column(index)?; 117 | col.get_i64() 118 | } 119 | 120 | fn get_col_by_name(&self, name: S) -> Result 121 | where S: Into { 122 | let col = self.get_column_by_name(name)?; 123 | col.get_i64() 124 | } 125 | } 126 | 127 | impl AsRustType for Row { 128 | fn get_col(&self, index: usize) -> Result { 129 | let col = self.get_column(index)?; 130 | col.get_i32() 131 | } 132 | 133 | fn get_col_by_name(&self, name: S) -> Result 134 | where S: Into { 135 | let col = self.get_column_by_name(name)?; 136 | col.get_i32() 137 | } 138 | } 139 | 140 | impl AsRustType for Row { 141 | fn get_col(&self, index: usize) -> Result { 142 | let col = self.get_column(index)?; 143 | col.set_iter() 144 | } 145 | 146 | fn get_col_by_name(&self, name: S) -> Result 147 | where S: Into { 148 | let col = self.get_column_by_name(name)?; 149 | col.set_iter() 150 | } 151 | } 152 | 153 | impl AsRustType for Row { 154 | fn get_col(&self, index: usize) -> Result { 155 | let col = self.get_column(index)?; 156 | col.map_iter() 157 | } 158 | 159 | fn get_col_by_name(&self, name: S) -> Result 160 | where S: Into { 161 | let col = self.get_column_by_name(name)?; 162 | col.map_iter() 163 | } 164 | } 165 | 166 | impl AsRustType> for Row { 167 | fn get_col(&self, index: usize) -> Result> { 168 | let col = self.get_column(index)?; 169 | col.get_blob() 170 | } 171 | 172 | fn get_col_by_name(&self, name: S) -> Result> 173 | where S: Into { 174 | let col = self.get_column_by_name(name)?; 175 | col.get_blob() 176 | } 177 | } 178 | 179 | impl Row { 180 | /// Get a particular column by index 181 | pub fn get_column(&self, index: usize) -> Result { 182 | unsafe { 183 | let col = cass_row_get_column(self.0, index); 184 | if col.is_null() { 185 | Err("LIB_INDEX_OUT_OF_BOUNDS".into()) 186 | } else { 187 | Ok(Column::build(col)) 188 | } 189 | } 190 | } 191 | 192 | /// Get a particular column by name 193 | pub fn get_column_by_name(&self, name: S) -> Result 194 | where S: Into { 195 | unsafe { 196 | let col = cass_row_get_column_by_name(self.0, 197 | CString::new(name.into()).expect("must be utf8").as_ptr()); 198 | if col.is_null() { 199 | Err("LIB_INDEX_OUT_OF_BOUNDS".into()) 200 | } else { 201 | Ok(Column::build(col)) 202 | } 203 | } 204 | } 205 | } 206 | 207 | /// An iterator over the columns in a row 208 | #[derive(Debug)] 209 | pub struct RowIterator(pub *mut _CassIterator); 210 | 211 | 212 | impl Drop for RowIterator { 213 | fn drop(&mut self) { unsafe { cass_iterator_free(self.0) } } 214 | } 215 | 216 | impl iter::Iterator for RowIterator { 217 | type Item = Column; 218 | 219 | fn next(&mut self) -> Option<::Item> { 220 | unsafe { 221 | match cass_iterator_next(self.0) { 222 | cass_false => None, 223 | cass_true => Some(Column::build(cass_iterator_get_column(self.0))), 224 | } 225 | } 226 | } 227 | } 228 | 229 | impl<'a> Iterator for &'a RowIterator { 230 | type Item = Column; 231 | 232 | fn next(&mut self) -> Option<::Item> { 233 | unsafe { 234 | match cass_iterator_next(self.0) { 235 | cass_false => None, 236 | cass_true => Some(Column::build(cass_iterator_get_column(self.0))), 237 | } 238 | } 239 | } 240 | } 241 | 242 | impl Display for RowIterator { 243 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 244 | for item in self { 245 | write!(f, "{}\t", Value::build(item.inner()))?; 246 | } 247 | Ok(()) 248 | } 249 | } 250 | 251 | impl IntoIterator for Row { 252 | type Item = Column; 253 | type IntoIter = RowIterator; 254 | 255 | /// Creates a new iterator for the specified row. This can be 256 | /// used to iterate over columns in a row. 257 | fn into_iter(self) -> Self::IntoIter { unsafe { RowIterator(cass_iterator_from_row(self.0)) } } 258 | } 259 | 260 | impl<'a> IntoIterator for &'a Row { 261 | type Item = Column; 262 | type IntoIter = RowIterator; 263 | fn into_iter(self) -> Self::IntoIter { unsafe { RowIterator(cass_iterator_from_row(self.0)) } } 264 | } 265 | -------------------------------------------------------------------------------- /src/cassandra/schema/aggregate_meta.rs: -------------------------------------------------------------------------------- 1 | use cassandra::data_type::ConstDataType; 2 | use cassandra::iterator::FieldIterator; 3 | 4 | use cassandra::schema::function_meta::FunctionMeta; 5 | use cassandra::util::Protected; 6 | use cassandra::value::Value; 7 | 8 | use cassandra_sys::CassAggregateMeta as _CassAggregateMeta; 9 | use cassandra_sys::cass_aggregate_meta_argument_count; 10 | use cassandra_sys::cass_aggregate_meta_argument_type; 11 | use cassandra_sys::cass_aggregate_meta_field_by_name; 12 | use cassandra_sys::cass_aggregate_meta_final_func; 13 | use cassandra_sys::cass_aggregate_meta_full_name; 14 | use cassandra_sys::cass_aggregate_meta_init_cond; 15 | use cassandra_sys::cass_aggregate_meta_name; 16 | use cassandra_sys::cass_aggregate_meta_return_type; 17 | use cassandra_sys::cass_aggregate_meta_state_func; 18 | use cassandra_sys::cass_aggregate_meta_state_type; 19 | use cassandra_sys::cass_iterator_fields_from_aggregate_meta; 20 | use cassandra_sys::raw2utf8; 21 | use std::ffi::CString; 22 | use std::mem; 23 | 24 | 25 | /// Metadata about a cassandra aggregate 26 | #[derive(Debug)] 27 | pub struct AggregateMeta(*const _CassAggregateMeta); 28 | 29 | impl Protected<*const _CassAggregateMeta> for AggregateMeta { 30 | fn inner(&self) -> *const _CassAggregateMeta { self.0 } 31 | fn build(inner: *const _CassAggregateMeta) -> Self { AggregateMeta(inner) } 32 | } 33 | 34 | impl AggregateMeta { 35 | /// An iterator over the fields of an aggregate 36 | pub fn fields_iter(&self) -> FieldIterator { 37 | unsafe { FieldIterator::build(cass_iterator_fields_from_aggregate_meta(self.0)) } 38 | } 39 | 40 | 41 | /// Gets the name of the aggregate. 42 | pub fn get_name(&self) -> String { 43 | unsafe { 44 | let mut name = mem::zeroed(); 45 | let mut name_length = mem::zeroed(); 46 | cass_aggregate_meta_name(self.0, &mut name, &mut name_length); 47 | raw2utf8(name, name_length).expect("must be utf8") 48 | } 49 | } 50 | 51 | /// Gets the full name of the aggregate. 52 | pub fn full_name(&self) -> String { 53 | unsafe { 54 | let mut name = mem::zeroed(); 55 | let mut name_length = mem::zeroed(); 56 | cass_aggregate_meta_full_name(self.0, &mut name, &mut name_length); 57 | raw2utf8(name, name_length).expect("must be utf8") 58 | } 59 | } 60 | 61 | /// Gets the number of arguments this aggregate takes. 62 | pub fn argument_count(&self) -> usize { unsafe { cass_aggregate_meta_argument_count(self.0) } } 63 | 64 | /// Gets the aggregate's argument type for the provided index. 65 | pub fn argument_type(&self, index: usize) -> ConstDataType { 66 | unsafe { ConstDataType(cass_aggregate_meta_argument_type(self.0, index)) } 67 | } 68 | 69 | /// Gets the aggregate's argument return type. 70 | pub fn return_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_aggregate_meta_return_type(self.0)) } } 71 | 72 | /// Gets the aggregate's argument state type. 73 | pub fn state_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_aggregate_meta_state_type(self.0)) } } 74 | 75 | /// Gets the function metadata for the aggregate's state function. 76 | pub fn state_func(&self) -> FunctionMeta { unsafe { FunctionMeta::build(cass_aggregate_meta_state_func(self.0)) } } 77 | 78 | /// Gets the function metadata for the aggregates's final function. 79 | pub fn final_func(&self) -> FunctionMeta { unsafe { FunctionMeta::build(cass_aggregate_meta_final_func(self.0)) } } 80 | 81 | /// Gets the initial condition value for the aggregate. 82 | pub fn init_cond(&self) -> Value { unsafe { Value::build(cass_aggregate_meta_init_cond(self.0)) } } 83 | 84 | /// Gets a metadata field for the provided name. Metadata fields allow direct 85 | /// access to the column data found in the underlying "aggregates" metadata table. 86 | pub fn field_by_name(&self, name: &str) -> Option { 87 | unsafe { 88 | let agg = cass_aggregate_meta_field_by_name(self.0, CString::new(name).expect("must be utf8").as_ptr()); 89 | if agg.is_null() { 90 | None 91 | } else { 92 | Some(Value::build(agg)) 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/cassandra/schema/column_meta.rs: -------------------------------------------------------------------------------- 1 | use cassandra::data_type::ConstDataType; 2 | 3 | use cassandra::iterator::FieldIterator; 4 | use cassandra::util::Protected; 5 | use cassandra::value::Value; 6 | use cassandra_sys::CassColumnMeta as _CassColumnMeta; 7 | use cassandra_sys::CassColumnType as _CassColumnType; 8 | use cassandra_sys::cass_column_meta_data_type; 9 | use cassandra_sys::cass_column_meta_field_by_name; 10 | use cassandra_sys::cass_column_meta_name; 11 | use cassandra_sys::cass_column_meta_type; 12 | use cassandra_sys::cass_iterator_fields_from_column_meta; 13 | 14 | /// Column metadata 15 | #[derive(Debug)] 16 | pub struct ColumnMeta(*const _CassColumnMeta); 17 | 18 | use std::ffi::CString; 19 | use std::mem; 20 | use std::slice; 21 | use std::str; 22 | 23 | impl Protected<*const _CassColumnMeta> for ColumnMeta { 24 | fn inner(&self) -> *const _CassColumnMeta { self.0 } 25 | fn build(inner: *const _CassColumnMeta) -> Self { ColumnMeta(inner) } 26 | } 27 | 28 | 29 | impl ColumnMeta { 30 | /// returns an iterator over the fields of this column 31 | pub fn field_iter(&mut self) -> FieldIterator { 32 | unsafe { FieldIterator::build(cass_iterator_fields_from_column_meta(self.0)) } 33 | } 34 | 35 | /// Gets the name of the column. 36 | #[allow(cast_possible_truncation)] 37 | pub fn name(&self) -> String { 38 | unsafe { 39 | let mut name = mem::zeroed(); 40 | let mut name_length = mem::zeroed(); 41 | cass_column_meta_name(self.0, &mut name, &mut name_length); 42 | let slice = slice::from_raw_parts(name as *const u8, name_length as usize); 43 | str::from_utf8(slice).expect("must be utf8").to_owned() 44 | } 45 | } 46 | 47 | /// Gets the type of the column. 48 | pub fn get_type(&self) -> _CassColumnType { unsafe { cass_column_meta_type(self.0) } } 49 | 50 | /// Gets the data type of the column. 51 | pub fn data_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_column_meta_data_type(self.0)) } } 52 | 53 | /// Gets a metadata field for the provided name. Metadata fields allow direct 54 | /// access to the column data found in the underlying "columns" metadata table. 55 | pub fn field_by_name(&self, name: &str) -> Option { 56 | unsafe { 57 | let field = cass_column_meta_field_by_name(self.0, CString::new(name).expect("must be utf8").as_ptr()); 58 | if field.is_null() { 59 | None 60 | } else { 61 | Some(Value::build(field)) 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/cassandra/schema/function_meta.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use cassandra::data_type::ConstDataType; 4 | use cassandra::error::CassError; 5 | 6 | use cassandra::iterator::FieldIterator; 7 | use cassandra::util::Protected; 8 | use cassandra::value::Value; 9 | use cassandra_sys::CASS_OK; 10 | use cassandra_sys::CassFunctionMeta as _CassFunctionMeta; 11 | use cassandra_sys::cass_function_meta_argument; 12 | use cassandra_sys::cass_function_meta_argument_count; 13 | use cassandra_sys::cass_function_meta_argument_type_by_name; 14 | use cassandra_sys::cass_function_meta_body; 15 | use cassandra_sys::cass_function_meta_called_on_null_input; 16 | use cassandra_sys::cass_function_meta_field_by_name; 17 | use cassandra_sys::cass_function_meta_full_name; 18 | use cassandra_sys::cass_function_meta_language; 19 | use cassandra_sys::cass_function_meta_name; 20 | use cassandra_sys::cass_function_meta_return_type; 21 | use cassandra_sys::cass_iterator_fields_from_function_meta; 22 | use cassandra_sys::cass_true; 23 | use errors::*; 24 | 25 | use std::{mem, slice, str}; 26 | use std::ffi::CString; 27 | /// The metadata for a function 28 | #[derive(Debug)] 29 | pub struct FunctionMeta(*const _CassFunctionMeta); 30 | 31 | impl Protected<*const _CassFunctionMeta> for FunctionMeta { 32 | fn inner(&self) -> *const _CassFunctionMeta { self.0 } 33 | fn build(inner: *const _CassFunctionMeta) -> Self { FunctionMeta(inner) } 34 | } 35 | 36 | impl FunctionMeta { 37 | /// Iterator over the fields in this function 38 | pub fn fields_iter(&self) -> FieldIterator { 39 | unsafe { FieldIterator::build(cass_iterator_fields_from_function_meta(self.0)) } 40 | } 41 | 42 | /// Gets the name of the function. 43 | #[allow(cast_possible_truncation)] 44 | pub fn get_name(&self) -> String { 45 | unsafe { 46 | let mut name = mem::zeroed(); 47 | let mut name_length = mem::zeroed(); 48 | cass_function_meta_name(self.0, &mut name, &mut name_length); 49 | str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 50 | .expect("must be utf8") 51 | .to_owned() 52 | } 53 | } 54 | 55 | /// Gets the full name of the function. The full name includes the 56 | /// function's name and the function's signature: 57 | /// "name(type1 type2.. typeN)". 58 | #[allow(cast_possible_truncation)] 59 | pub fn full_name(&self) -> String { 60 | unsafe { 61 | let mut name = mem::zeroed(); 62 | let mut name_length = mem::zeroed(); 63 | cass_function_meta_full_name(self.0, &mut name, &mut name_length); 64 | str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 65 | .expect("must be utf8") 66 | .to_owned() 67 | } 68 | } 69 | 70 | /// Gets the body of the function. 71 | #[allow(cast_possible_truncation)] 72 | pub fn body(&self) -> String { 73 | unsafe { 74 | let mut name = mem::zeroed(); 75 | let mut name_length = mem::zeroed(); 76 | cass_function_meta_body(self.0, &mut name, &mut name_length); 77 | str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 78 | .expect("must be utf8") 79 | .to_owned() 80 | } 81 | } 82 | 83 | /// Gets the language of the function. 84 | #[allow(cast_possible_truncation)] 85 | pub fn language(&self) -> String { 86 | unsafe { 87 | let mut name = mem::zeroed(); 88 | let mut name_length = mem::zeroed(); 89 | cass_function_meta_language(self.0, &mut name, &mut name_length); 90 | str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 91 | .expect("must be utf8") 92 | .to_owned() 93 | } 94 | } 95 | 96 | /// Gets whether a function is called on "null". 97 | pub fn called_on_null_input(&self) -> bool { 98 | unsafe { cass_function_meta_called_on_null_input(self.0) == cass_true } 99 | } 100 | 101 | /// Gets the number of arguments this function takes. 102 | pub fn argument_count(&self) -> usize { unsafe { cass_function_meta_argument_count(self.0) } } 103 | 104 | /// Gets the function's argument name and type for the provided index. 105 | pub fn argument(&self, index: usize) -> Result<()> { 106 | unsafe { 107 | let mut name = mem::zeroed(); 108 | let mut name_length = mem::zeroed(); 109 | let mut data_type = mem::zeroed(); 110 | 111 | match cass_function_meta_argument(self.0, index, &mut name, &mut name_length, &mut data_type) { 112 | CASS_OK => Ok(()), 113 | err => err.to_result(()).chain_err(|| ""), 114 | } 115 | } 116 | } 117 | 118 | /// Gets the function's argument and type for the provided name. 119 | pub fn argument_type_by_name(&self, name: &str) -> ConstDataType { 120 | unsafe { 121 | ConstDataType(cass_function_meta_argument_type_by_name(self.0, 122 | CString::new(name) 123 | .expect("must be utf8") 124 | .as_ptr())) 125 | } 126 | } 127 | 128 | /// Gets the return type of the function. 129 | pub fn return_type(&self) -> ConstDataType { unsafe { ConstDataType(cass_function_meta_return_type(self.0)) } } 130 | 131 | /// Gets a metadata field for the provided name. Metadata fields allow direct 132 | /// access to the column data found in the underlying "functions" metadata table. 133 | pub fn field_by_name(&self, name: &str) -> Value { 134 | unsafe { 135 | Value::build(cass_function_meta_field_by_name(self.0, CString::new(name).expect("must be utf8").as_ptr())) 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/cassandra/schema/keyspace_meta.rs: -------------------------------------------------------------------------------- 1 | use cassandra::data_type::ConstDataType; 2 | use cassandra::iterator::AggregateIterator; 3 | use cassandra::iterator::FieldIterator; 4 | use cassandra::iterator::FunctionIterator; 5 | use cassandra::iterator::TableIterator; 6 | use cassandra::iterator::UserTypeIterator; 7 | use cassandra::schema::aggregate_meta::AggregateMeta; 8 | 9 | use cassandra::schema::function_meta::FunctionMeta; 10 | use cassandra::schema::table_meta::TableMeta; 11 | use cassandra::util::Protected; 12 | 13 | use cassandra_sys::CassKeyspaceMeta as _CassKeyspaceMeta; 14 | use cassandra_sys::CassValue as _CassValue; 15 | use cassandra_sys::cass_iterator_aggregates_from_keyspace_meta; 16 | use cassandra_sys::cass_iterator_fields_from_keyspace_meta; 17 | use cassandra_sys::cass_iterator_functions_from_keyspace_meta; 18 | 19 | use cassandra_sys::cass_iterator_tables_from_keyspace_meta; 20 | use cassandra_sys::cass_iterator_user_types_from_keyspace_meta; 21 | use cassandra_sys::cass_keyspace_meta_aggregate_by_name; 22 | use cassandra_sys::cass_keyspace_meta_field_by_name; 23 | use cassandra_sys::cass_keyspace_meta_function_by_name; 24 | use cassandra_sys::cass_keyspace_meta_name; 25 | use cassandra_sys::cass_keyspace_meta_table_by_name; 26 | use cassandra_sys::cass_keyspace_meta_user_type_by_name; 27 | use cassandra_sys::raw2utf8; 28 | use std::ffi::CString; 29 | use std::mem; 30 | 31 | /// A snapshot of the schema's metadata. 32 | #[derive(Debug)] 33 | pub struct KeyspaceMeta(*const _CassKeyspaceMeta); 34 | 35 | impl Protected<*const _CassKeyspaceMeta> for KeyspaceMeta { 36 | fn inner(&self) -> *const _CassKeyspaceMeta { self.0 } 37 | fn build(inner: *const _CassKeyspaceMeta) -> Self { KeyspaceMeta(inner) } 38 | } 39 | 40 | #[derive(Debug)] 41 | pub struct MetadataFieldValue(*const _CassValue); 42 | 43 | impl KeyspaceMeta { 44 | /// Iterator over the aggregates in this keyspace 45 | pub fn aggregrates_iter(&self) -> AggregateIterator { 46 | unsafe { AggregateIterator::build(cass_iterator_aggregates_from_keyspace_meta(self.0)) } 47 | } 48 | 49 | /// Iterator over the field in this keyspace 50 | pub fn fields_iter(&self) -> FieldIterator { 51 | unsafe { FieldIterator::build(cass_iterator_fields_from_keyspace_meta(self.0)) } 52 | } 53 | 54 | /// Gets the table metadata for the provided table name. 55 | pub fn table_by_name(&self, name: &str) -> Option { 56 | unsafe { 57 | let value = cass_keyspace_meta_table_by_name(self.0, CString::new(name).expect("must be utf8").as_ptr()); 58 | if value.is_null() { 59 | None 60 | } else { 61 | Some(TableMeta::build(value)) 62 | } 63 | } 64 | } 65 | 66 | /// Gets the data type for the provided type name. 67 | pub fn user_type_by_name(&self, name: &str) -> Option { 68 | unsafe { 69 | let value = cass_keyspace_meta_user_type_by_name(self.0, 70 | CString::new(name).expect("must be utf8").as_ptr()); 71 | if value.is_null() { 72 | None 73 | } else { 74 | Some(ConstDataType(value)) 75 | } 76 | } 77 | } 78 | 79 | /// Gets the function metadata for the provided function name. 80 | pub fn get_function_by_name(&self, name: &str, arguments: Vec<&str>) -> Option { 81 | unsafe { 82 | let value = cass_keyspace_meta_function_by_name(self.0, 83 | CString::new(name).expect("must be utf8").as_ptr(), 84 | CString::new(arguments.join(",")) 85 | .expect("must be utf8") 86 | .as_ptr()); 87 | if value.is_null() { 88 | None 89 | } else { 90 | Some(FunctionMeta::build(value)) 91 | } 92 | } 93 | } 94 | 95 | /// Gets the aggregate metadata for the provided aggregate name. 96 | pub fn aggregate_by_name(&self, name: &str, arguments: Vec<&str>) -> Option { 97 | unsafe { 98 | let agg = cass_keyspace_meta_aggregate_by_name(self.0, 99 | CString::new(name).expect("must be utf8").as_ptr(), 100 | CString::new(arguments.join(",")) 101 | .expect("must be utf8") 102 | .as_ptr()); 103 | if agg.is_null() { 104 | None 105 | } else { 106 | Some(AggregateMeta::build((agg))) 107 | } 108 | } 109 | } 110 | 111 | /// Iterator over the tables in this keyspaces 112 | pub fn table_iter(&mut self) -> TableIterator { 113 | unsafe { TableIterator::build(cass_iterator_tables_from_keyspace_meta(self.0)) } 114 | } 115 | 116 | /// Iterator over the functions in this keyspaces 117 | pub fn function_iter(&mut self) -> FunctionIterator { 118 | unsafe { FunctionIterator::build(cass_iterator_functions_from_keyspace_meta(self.0)) } 119 | } 120 | 121 | /// Iterator over the UDTs in this keyspaces 122 | pub fn user_type_iter(&mut self) -> UserTypeIterator { 123 | unsafe { UserTypeIterator::build(cass_iterator_user_types_from_keyspace_meta(self.0)) } 124 | } 125 | 126 | /// Gets the name of the keyspace. 127 | pub fn name(&self) -> String { 128 | unsafe { 129 | let mut name = mem::zeroed(); 130 | let mut name_length = mem::zeroed(); 131 | cass_keyspace_meta_name(self.0, &mut name, &mut name_length); 132 | raw2utf8(name, name_length).expect("must be utf8") 133 | } 134 | } 135 | 136 | /// Gets a metadata field for the provided name. Metadata fields allow direct 137 | /// access to the column data found in the underlying "keyspaces" metadata table. 138 | pub fn field_by_name(&self, name: &str) -> Option { 139 | unsafe { 140 | let value = cass_keyspace_meta_field_by_name(self.0, CString::new(name).expect("must be utf8").as_ptr()); 141 | if value.is_null() { 142 | None 143 | } else { 144 | Some(MetadataFieldValue(value)) 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/cassandra/schema/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod keyspace_meta; 2 | pub mod schema_meta; 3 | pub mod column_meta; 4 | pub mod table_meta; 5 | pub mod function_meta; 6 | pub mod aggregate_meta; 7 | -------------------------------------------------------------------------------- /src/cassandra/schema/schema_meta.rs: -------------------------------------------------------------------------------- 1 | use cassandra::iterator::KeyspaceIterator; 2 | 3 | use cassandra::schema::keyspace_meta::KeyspaceMeta; 4 | use cassandra::util::Protected; 5 | use cassandra_sys::CassSchemaMeta as _CassSchemaMeta; 6 | use cassandra_sys::cass_iterator_keyspaces_from_schema_meta; 7 | use cassandra_sys::cass_schema_meta_free; 8 | use cassandra_sys::cass_schema_meta_keyspace_by_name; 9 | use cassandra_sys::cass_schema_meta_snapshot_version; 10 | 11 | /// A snapshot of the schema's metadata 12 | #[derive(Debug)] 13 | pub struct SchemaMeta(*const _CassSchemaMeta); 14 | 15 | impl Drop for SchemaMeta { 16 | fn drop(&mut self) { 17 | unsafe { 18 | cass_schema_meta_free(self.0); 19 | } 20 | } 21 | } 22 | 23 | impl Protected<*const _CassSchemaMeta> for SchemaMeta { 24 | fn inner(&self) -> *const _CassSchemaMeta { self.0 } 25 | fn build(inner: *const _CassSchemaMeta) -> Self { SchemaMeta(inner) } 26 | } 27 | 28 | impl SchemaMeta { 29 | /// Gets the version of the schema metadata snapshot. 30 | pub fn snapshot_version(&self) -> u32 { unsafe { cass_schema_meta_snapshot_version(self.0) } } 31 | 32 | /// Gets the keyspace metadata for the provided keyspace name. 33 | pub fn get_keyspace_by_name(&self, keyspace: &str) -> KeyspaceMeta { 34 | unsafe { KeyspaceMeta::build(cass_schema_meta_keyspace_by_name(self.0, keyspace.as_ptr() as *const i8)) } 35 | } 36 | 37 | /// Returns an iterator over the keyspaces in this schema 38 | pub fn keyspace_iter(&mut self) -> KeyspaceIterator { 39 | unsafe { KeyspaceIterator::build(cass_iterator_keyspaces_from_schema_meta(self.0)) } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/cassandra/schema/table_meta.rs: -------------------------------------------------------------------------------- 1 | use cassandra::iterator::ColumnIterator; 2 | use cassandra::iterator::FieldIterator; 3 | 4 | use cassandra::schema::column_meta::ColumnMeta; 5 | use cassandra::util::Protected; 6 | use cassandra::value::Value; 7 | use cassandra_sys::CassTableMeta as _CassTableMeta; 8 | use cassandra_sys::cass_iterator_columns_from_table_meta; 9 | use cassandra_sys::cass_iterator_fields_from_table_meta; 10 | use cassandra_sys::cass_table_meta_clustering_key; 11 | use cassandra_sys::cass_table_meta_clustering_key_count; 12 | use cassandra_sys::cass_table_meta_column; 13 | use cassandra_sys::cass_table_meta_column_by_name; 14 | use cassandra_sys::cass_table_meta_column_count; 15 | use cassandra_sys::cass_table_meta_field_by_name; 16 | use cassandra_sys::cass_table_meta_name; 17 | use cassandra_sys::cass_table_meta_partition_key; 18 | use cassandra_sys::cass_table_meta_partition_key_count; 19 | use std::mem; 20 | use std::slice; 21 | 22 | use std::str; 23 | 24 | /// Table metadata 25 | #[derive(Debug)] 26 | pub struct TableMeta(*const _CassTableMeta); 27 | 28 | impl Protected<*const _CassTableMeta> for TableMeta { 29 | fn inner(&self) -> *const _CassTableMeta { self.0 } 30 | fn build(inner: *const _CassTableMeta) -> Self { TableMeta(inner) } 31 | } 32 | 33 | impl TableMeta { 34 | /// returns an iterator over the fields of this table 35 | pub fn field_iter(&mut self) -> FieldIterator { 36 | unsafe { FieldIterator::build(cass_iterator_fields_from_table_meta(self.0)) } 37 | } 38 | 39 | /// An iterator over the columns in this table 40 | pub fn columns_iter(&self) -> ColumnIterator { 41 | unsafe { ColumnIterator::build(cass_iterator_columns_from_table_meta(self.0)) } 42 | } 43 | 44 | /// Gets the column metadata for the provided column name. 45 | pub fn column_by_name(&self, name: &str) -> ColumnMeta { 46 | unsafe { ColumnMeta::build(cass_table_meta_column_by_name(self.0, name.as_ptr() as *const i8)) } 47 | } 48 | 49 | /// Gets the name of the table. 50 | #[allow(cast_possible_truncation)] 51 | pub fn get_name(&self) -> String { 52 | unsafe { 53 | let mut name = mem::zeroed(); 54 | let mut name_length = mem::zeroed(); 55 | cass_table_meta_name(self.0, &mut name, &mut name_length); 56 | str::from_utf8(slice::from_raw_parts(name as *const u8, name_length as usize)) 57 | .expect("must be utf8") 58 | .to_owned() 59 | } 60 | } 61 | 62 | /// Gets the total number of columns for the table. 63 | pub fn column_count(&self) -> usize { unsafe { cass_table_meta_column_count(self.0) } } 64 | 65 | /// Gets the column metadata for the provided index. 66 | pub fn column(&self, index: usize) -> ColumnMeta { 67 | unsafe { ColumnMeta::build(cass_table_meta_column(self.0, index)) } 68 | } 69 | 70 | /// Gets the number of columns for the table's partition key. 71 | pub fn partition_key_count(&self) -> usize { unsafe { cass_table_meta_partition_key_count(self.0) } } 72 | 73 | /// Gets the partition key column metadata for the provided index. 74 | pub fn partition_key(&self, index: usize) -> Option { 75 | unsafe { 76 | let key = cass_table_meta_partition_key(self.0, index); 77 | if key.is_null() { 78 | None 79 | } else { 80 | Some(ColumnMeta::build(key)) 81 | } 82 | } 83 | } 84 | 85 | /// Gets the number of columns for the table's clustering key 86 | pub fn clustering_key_count(&self) -> usize { unsafe { cass_table_meta_clustering_key_count(self.0) } } 87 | 88 | /// Gets the clustering key column metadata for the provided index. 89 | pub fn cluster_key(&self, index: usize) -> Option { 90 | unsafe { 91 | let key = cass_table_meta_clustering_key(self.0, index); 92 | if key.is_null() { 93 | None 94 | } else { 95 | Some(ColumnMeta::build(key)) 96 | } 97 | } 98 | } 99 | 100 | 101 | /// Gets a metadata field for the provided name. Metadata fields allow direct 102 | /// access to the column data found in the underlying "tables" metadata table. 103 | pub fn field_by_name(&self, name: &str) -> Option { 104 | // fixme replace CassValule with a custom type 105 | unsafe { 106 | let value = cass_table_meta_field_by_name(self.0, name.as_ptr() as *const i8); 107 | if value.is_null() { 108 | None 109 | } else { 110 | Some(Value::build(value)) 111 | } 112 | 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/cassandra/session.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types)] 2 | #![allow(dead_code)] 3 | #![allow(missing_copy_implementations)] 4 | 5 | use cassandra::batch::Batch; 6 | use cassandra::cluster::Cluster; 7 | use cassandra::error::CassError; 8 | use cassandra::future::{CloseFuture, Future, PreparedFuture, ResultFuture, SessionFuture}; 9 | use cassandra::metrics::SessionMetrics; 10 | use cassandra::schema::schema_meta::SchemaMeta; 11 | use cassandra::statement::Statement; 12 | use cassandra::util::Protected; 13 | 14 | use cassandra_sys::CassSession as _Session; 15 | use cassandra_sys::cass_session_close; 16 | use cassandra_sys::cass_session_connect; 17 | use cassandra_sys::cass_session_connect_keyspace; 18 | use cassandra_sys::cass_session_execute; 19 | use cassandra_sys::cass_session_execute_batch; 20 | use cassandra_sys::cass_session_free; 21 | use cassandra_sys::cass_session_get_metrics; 22 | use cassandra_sys::cass_session_get_schema_meta; 23 | use cassandra_sys::cass_session_new; 24 | use cassandra_sys::cass_session_prepare; 25 | 26 | use std::ffi::CString; 27 | use std::ffi::NulError; 28 | use std::mem; 29 | 30 | /// A session object is used to execute queries and maintains cluster state through 31 | /// the control connection. The control connection is used to auto-discover nodes and 32 | /// monitor cluster changes (topology and schema). Each session also maintains multiple 33 | /// /pools of connections to cluster nodes which are used to query the cluster. 34 | /// 35 | /// Instances of the session object are thread-safe to execute queries. 36 | #[derive(Debug)] 37 | pub struct Session(pub *mut _Session); 38 | unsafe impl Sync for Session {} 39 | unsafe impl Send for Session {} 40 | 41 | impl Protected<*mut _Session> for Session { 42 | fn inner(&self) -> *mut _Session { self.0 } 43 | fn build(inner: *mut _Session) -> Self { Session(inner) } 44 | } 45 | 46 | impl Drop for Session { 47 | /// Frees a session instance. If the session is still connected it will be synchronously 48 | /// closed before being deallocated. 49 | fn drop(&mut self) { 50 | debug!("dropping session"); 51 | unsafe { cass_session_free(self.0) } 52 | } 53 | } 54 | 55 | impl Default for Session { 56 | fn default() -> Session { Session::new() } 57 | } 58 | 59 | impl Session { 60 | /// Create a new Cassanda session. 61 | /// It's recommended to use Cluster.connect() instead 62 | pub fn new() -> Session { unsafe { Session(cass_session_new()) } } 63 | 64 | // pub fn new2() -> *mut _Session { 65 | // unsafe { cass_session_new() } 66 | // } 67 | 68 | /// Connects a session. 69 | pub fn connect(self, cluster: &Cluster) -> SessionFuture { 70 | unsafe { SessionFuture::build(cass_session_connect(self.0, cluster.inner())) } 71 | } 72 | 73 | /// Connects a session and sets the keyspace. 74 | pub fn connect_keyspace(&self, cluster: &Cluster, keyspace: &str) -> Result { 75 | unsafe { 76 | Ok(Future::build(cass_session_connect_keyspace(self.0, cluster.inner(), CString::new(keyspace)?.as_ptr()))) 77 | } 78 | } 79 | 80 | /// Closes the session instance, outputs a close future which can 81 | /// be used to determine when the session has been terminated. This allows 82 | /// in-flight requests to finish. 83 | pub fn close(self) -> CloseFuture { unsafe { CloseFuture::build(cass_session_close(self.0)) } } 84 | 85 | /// Create a prepared statement. 86 | pub fn prepare(&self, query: &str) -> Result { 87 | unsafe { 88 | Ok(PreparedFuture::build(cass_session_prepare(self.0, CString::new(query).expect("must be utf8").as_ptr()))) 89 | } 90 | } 91 | 92 | // ///Execute a query or bound statement. 93 | // pub fn execute(&self, statement: &str, parameter_count: u64) -> ResultFuture { 94 | // unsafe { 95 | // ResultFuture::build(cass_session_execute(self.0, 96 | // Statement::new(statement, parameter_count).inner())) 97 | // } 98 | // } 99 | 100 | /// Execute a batch statement. 101 | pub fn execute_batch(&self, batch: Batch) -> ResultFuture { 102 | ResultFuture::build(unsafe { cass_session_execute_batch(self.0, batch.inner()) }) 103 | } 104 | 105 | /// Execute a statement. 106 | pub fn execute(&self, statement: &Statement) -> ResultFuture { 107 | unsafe { ResultFuture::build(cass_session_execute(self.0, statement.inner())) } 108 | } 109 | 110 | /// Gets a snapshot of this session's schema metadata. The returned 111 | /// snapshot of the schema metadata is not updated. This function 112 | /// must be called again to retrieve any schema changes since the 113 | /// previous call. 114 | pub fn get_schema_meta(&self) -> SchemaMeta { unsafe { SchemaMeta::build(cass_session_get_schema_meta(self.0)) } } 115 | 116 | /// Gets a copy of this session's performance/diagnostic metrics. 117 | pub fn get_metrics(&self) -> SessionMetrics { 118 | unsafe { 119 | let mut metrics = mem::zeroed(); 120 | cass_session_get_metrics(self.0, &mut metrics); 121 | SessionMetrics::build(&metrics) 122 | } 123 | } 124 | 125 | // pub fn get_schema(&self) -> Schema { 126 | // unsafe { Schema(cass_session_get_schema(self.0)) } 127 | // } 128 | } 129 | -------------------------------------------------------------------------------- /src/cassandra/ssl.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use cassandra::error::CassError; 4 | use cassandra::util::Protected; 5 | use cassandra_sys::CassSsl as _Ssl; 6 | use cassandra_sys::cass_ssl_add_trusted_cert; 7 | use cassandra_sys::cass_ssl_free; 8 | use cassandra_sys::cass_ssl_new; 9 | use cassandra_sys::cass_ssl_set_cert; 10 | use cassandra_sys::cass_ssl_set_private_key; 11 | use cassandra_sys::cass_ssl_set_verify_flags; 12 | use errors::*; 13 | use std::ffi::CString; 14 | 15 | /// Describes the SSL configuration of a cluster. 16 | #[derive(Debug)] 17 | pub struct Ssl(*mut _Ssl); 18 | 19 | impl Protected<*mut _Ssl> for Ssl { 20 | fn inner(&self) -> *mut _Ssl { self.0 } 21 | fn build(inner: *mut _Ssl) -> Self { Ssl(inner) } 22 | } 23 | 24 | 25 | impl Drop for Ssl { 26 | /// Frees a SSL context instance. 27 | fn drop(&mut self) { unsafe { cass_ssl_free(self.0) } } 28 | } 29 | 30 | impl Default for Ssl { 31 | /// Creates a new SSL context. 32 | fn default() -> Ssl { unsafe { Ssl(cass_ssl_new()) } } 33 | } 34 | 35 | impl Ssl { 36 | /// Adds a trusted certificate. This is used to verify 37 | /// the peer's certificate. 38 | pub fn add_trusted_cert(&mut self, cert: &str) -> Result<&mut Self> { 39 | unsafe { 40 | cass_ssl_add_trusted_cert(self.0, CString::new(cert).expect("must be utf8").as_ptr()) 41 | .to_result(self) 42 | .chain_err(|| "") 43 | } 44 | } 45 | 46 | /// Sets verification performed on the peer's certificate. 47 | /// 48 | /// CASS_SSL_VERIFY_NONE - No verification is performed 49 | /// 50 | /// CASS_SSL_VERIFY_PEER_CERT - Certificate is present and valid 51 | /// 52 | /// CASS_SSL_VERIFY_PEER_IDENTITY - IP address matches the certificate's 53 | /// common name or one of its subject alternative names. This implies the 54 | /// certificate is also present. 55 | /// 56 | /// Default: CASS_SSL_VERIFY_PEER_CERT 57 | pub fn set_verify_flags(&mut self, flags: i32) { unsafe { cass_ssl_set_verify_flags(self.0, flags) } } 58 | 59 | /// Set client-side certificate chain. This is used to authenticate 60 | /// the client on the server-side. This should contain the entire 61 | /// Certificate chain starting with the certificate itself. 62 | pub fn set_cert(&mut self, cert: &str) -> Result<&mut Self> { 63 | unsafe { 64 | cass_ssl_set_cert(self.0, CString::new(cert).expect("must be utf8").as_ptr()) 65 | .to_result(self) 66 | .chain_err(|| "") 67 | } 68 | } 69 | 70 | /// Set client-side private key. This is used to authenticate 71 | /// the client on the server-side. 72 | pub fn set_private_key(&mut self, key: &str, password: &str) -> Result<&mut Self> { 73 | unsafe { 74 | cass_ssl_set_private_key(self.0, 75 | CString::new(key).expect("must be utf8").as_ptr(), 76 | password.as_ptr() as *const i8) 77 | .to_result(self) 78 | .chain_err(|| "") 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/cassandra/time.rs: -------------------------------------------------------------------------------- 1 | use cassandra::util::Protected; 2 | 3 | use cassandra_sys::CassTimestampGen as _TimestampGen; 4 | use cassandra_sys::cass_time_from_epoch; 5 | use cassandra_sys::cass_timestamp_gen_free; 6 | use cassandra_sys::cass_timestamp_gen_monotonic_new; 7 | use cassandra_sys::cass_timestamp_gen_server_side_new; 8 | // use cassandra_sys::cass_date_from_epoch; 9 | // use cassandra_sys::cass_date_time_to_epoch; 10 | use time::Duration; 11 | 12 | /// Generators of client-side, microsecond-precision timestamps. 13 | /// Note: This generator is thread-safe and can be shared by multiple sessions. 14 | #[derive(Debug)] 15 | pub struct TimestampGen(*mut _TimestampGen); 16 | unsafe impl Send for TimestampGen {} 17 | unsafe impl Sync for TimestampGen {} 18 | 19 | impl Protected<*mut _TimestampGen> for TimestampGen { 20 | fn inner(&self) -> *mut _TimestampGen { self.0 } 21 | fn build(inner: *mut _TimestampGen) -> Self { TimestampGen(inner) } 22 | } 23 | 24 | 25 | // ///Cassandra representation of the number of days since epoch 26 | // pub struct Date(u32); 27 | 28 | /// Converts a unix timestamp (in seconds) to the Cassandra "time" type. The "time" type 29 | /// represents the number of nanoseconds since midnight (range 0 to 86399999999999). 30 | #[derive(Debug)] 31 | pub struct Time(i64); 32 | 33 | 34 | impl TimestampGen { 35 | /// Converts a unix timestamp (in seconds) to the Cassandra "time" type. The "time" type 36 | /// represents the number of nanoseconds since midnight (range 0 to 86399999999999). 37 | pub fn time_from_epoch(epoch_seconds: Duration) -> Time { 38 | unsafe { Time(cass_time_from_epoch(epoch_seconds.num_seconds())) } 39 | } 40 | 41 | /// Creates a new monotonically increasing timestamp generator. This generates 42 | /// microsecond timestamps with the sub-millisecond part generated using a counter. 43 | /// The implementation guarantees that no more than 1000 timestamps will be generated 44 | /// for a given clock tick even if shared by multiple session objects. If that rate is 45 | /// exceeded then a warning is logged and timestamps stop incrementing until the next 46 | /// clock tick. 47 | pub fn gen_monotonic_new() -> Self { unsafe { TimestampGen(cass_timestamp_gen_monotonic_new()) } } 48 | 49 | /// Creates a new server-side timestamp generator. This generator allows Cassandra 50 | /// to assign timestamps server-side. 51 | /// 52 | /// Note: This is the default timestamp generator. 53 | pub fn gen_server_side_new() -> Self { unsafe { TimestampGen(cass_timestamp_gen_server_side_new()) } } 54 | 55 | // pub fn from_epoch() -> Self { 56 | // unsafe { TimestampGen(cass_timestamp_gen_monotonic_new()) } 57 | // } 58 | } 59 | 60 | // Converts a unix timestamp (in seconds) to the Cassandra "date" type. The "date" type 61 | // represents the number of days since the Epoch (1970-01-01) with the Epoch centered at 62 | // the value 2^31. 63 | // fn date_from_epoch(epoch_secs: Duration) -> Date { 64 | // unsafe { Date(cass_date_from_epoch(epoch_secs.num_days())) } 65 | // } 66 | 67 | // Combines the Cassandra "date" and "time" types to Epoch time in seconds. 68 | // fn date_time_to_epoch(date: Date, time: Time) -> Duration { 69 | // unsafe { Duration::seconds(cass_date_time_to_epoch(date.0, time.0)) } 70 | // } 71 | 72 | impl Drop for TimestampGen { 73 | fn drop(&mut self) { unsafe { cass_timestamp_gen_free(self.0) } } 74 | } 75 | -------------------------------------------------------------------------------- /src/cassandra/tuple.rs: -------------------------------------------------------------------------------- 1 | use cassandra::collection::Set; 2 | use cassandra::data_type::ConstDataType; 3 | use cassandra::data_type::DataType; 4 | use cassandra::error::CassError; 5 | 6 | use cassandra::inet::AsInet; 7 | use cassandra::user_type::UserType; 8 | use cassandra::util::Protected; 9 | use cassandra::uuid::Uuid; 10 | use cassandra_sys::CassTuple as _Tuple; 11 | use cassandra_sys::cass_false; 12 | use cassandra_sys::cass_true; 13 | use cassandra_sys::cass_tuple_data_type; 14 | use cassandra_sys::cass_tuple_free; 15 | use cassandra_sys::cass_tuple_new; 16 | use cassandra_sys::cass_tuple_new_from_data_type; 17 | use cassandra_sys::cass_tuple_set_bool; 18 | use cassandra_sys::cass_tuple_set_bytes; 19 | use cassandra_sys::cass_tuple_set_collection; 20 | #[allow(unused_imports)] 21 | use cassandra_sys::cass_tuple_set_decimal; 22 | use cassandra_sys::cass_tuple_set_double; 23 | use cassandra_sys::cass_tuple_set_float; 24 | use cassandra_sys::cass_tuple_set_inet; 25 | use cassandra_sys::cass_tuple_set_int16; 26 | use cassandra_sys::cass_tuple_set_int32; 27 | use cassandra_sys::cass_tuple_set_int64; 28 | use cassandra_sys::cass_tuple_set_int8; 29 | use cassandra_sys::cass_tuple_set_null; 30 | use cassandra_sys::cass_tuple_set_string; 31 | use cassandra_sys::cass_tuple_set_tuple; 32 | use cassandra_sys::cass_tuple_set_uint32; 33 | use cassandra_sys::cass_tuple_set_user_type; 34 | use cassandra_sys::cass_tuple_set_uuid; 35 | use errors::*; 36 | use std::ffi::CString; 37 | use std::net::SocketAddr; 38 | 39 | 40 | /// A tuple of values. 41 | #[derive(Debug)] 42 | pub struct Tuple(*mut _Tuple); 43 | 44 | impl Protected<*mut _Tuple> for Tuple { 45 | fn inner(&self) -> *mut _Tuple { self.0 } 46 | fn build(inner: *mut _Tuple) -> Self { Tuple(inner) } 47 | } 48 | 49 | impl Tuple { 50 | /// Creates a new tuple. 51 | pub fn new(item_count: usize) -> Self { unsafe { Tuple(cass_tuple_new(item_count)) } } 52 | 53 | /// Creates a new tuple from an existing data type. 54 | pub fn new_from_data_type(data_type: DataType) -> Tuple { 55 | unsafe { Tuple(cass_tuple_new_from_data_type(data_type.inner())) } 56 | } 57 | 58 | /// Gets the data type of a tuple. 59 | pub fn data_type(&mut self) -> ConstDataType { unsafe { ConstDataType(cass_tuple_data_type(self.0)) } } 60 | 61 | /// Sets an null in a tuple at the specified index. 62 | pub fn set_null(&mut self, index: usize) -> Result<&mut Self> { 63 | unsafe { 64 | cass_tuple_set_null(self.0, index) 65 | .to_result(self) 66 | .chain_err(|| "") 67 | } 68 | } 69 | 70 | /// Sets a "tinyint" in a tuple at the specified index. 71 | pub fn set_int8(&mut self, index: usize, value: i8) -> Result<&mut Self> { 72 | unsafe { 73 | cass_tuple_set_int8(self.0, index, value) 74 | .to_result(self) 75 | .chain_err(|| "") 76 | } 77 | } 78 | 79 | /// Sets an "smallint" in a tuple at the specified index. 80 | pub fn set_int16(&mut self, index: usize, value: i16) -> Result<&mut Self> { 81 | unsafe { 82 | cass_tuple_set_int16(self.0, index, value) 83 | .to_result(self) 84 | .chain_err(|| "") 85 | } 86 | } 87 | 88 | /// Sets an "int" in a tuple at the specified index. 89 | pub fn set_int32(&mut self, index: usize, value: i32) -> Result<&mut Self> { 90 | unsafe { 91 | cass_tuple_set_int32(self.0, index, value) 92 | .to_result(self) 93 | .chain_err(|| "") 94 | } 95 | } 96 | 97 | /// Sets a "date" in a tuple at the specified index. 98 | pub fn set_uint32(&mut self, index: usize, value: u32) -> Result<&mut Self> { 99 | unsafe { 100 | cass_tuple_set_uint32(self.0, index, value) 101 | .to_result(self) 102 | .chain_err(|| "") 103 | } 104 | } 105 | 106 | /// Sets a "bigint", "counter", "timestamp" or "time" in a tuple at the 107 | /// specified index. 108 | pub fn set_int64(&mut self, index: usize, value: i64) -> Result<&mut Self> { 109 | unsafe { 110 | cass_tuple_set_int64(self.0, index, value) 111 | .to_result(self) 112 | .chain_err(|| "") 113 | } 114 | } 115 | 116 | /// Sets a "float" in a tuple at the specified index. 117 | pub fn set_float(&mut self, index: usize, value: f32) -> Result<&mut Self> { 118 | unsafe { 119 | cass_tuple_set_float(self.0, index, value) 120 | .to_result(self) 121 | .chain_err(|| "") 122 | } 123 | } 124 | 125 | /// Sets a "double" in a tuple at the specified index. 126 | pub fn set_double(&mut self, index: usize, value: f64) -> Result<&mut Self> { 127 | unsafe { 128 | cass_tuple_set_double(self.0, index, value) 129 | .to_result(self) 130 | .chain_err(|| "") 131 | } 132 | } 133 | 134 | /// Sets a "boolean" in a tuple at the specified index. 135 | pub fn set_bool(&mut self, index: usize, value: bool) -> Result<&mut Self> { 136 | unsafe { 137 | cass_tuple_set_bool(self.0, index, if value { cass_true } else { cass_false }) 138 | .to_result(self) 139 | .chain_err(|| "") 140 | } 141 | } 142 | 143 | /// Sets an "ascii", "text" or "varchar" in a tuple at the specified index. 144 | pub fn set_string(&mut self, index: usize, value: S) -> Result<&mut Self> 145 | where S: Into { 146 | unsafe { 147 | cass_tuple_set_string(self.0, 148 | index, 149 | CString::new(value.into()).expect("must be utf8").as_ptr()) 150 | .to_result(self) 151 | .chain_err(|| "") 152 | } 153 | } 154 | 155 | /// Sets a "blob", "varint" or "custom" in a tuple at the specified index. 156 | pub fn set_bytes(&mut self, index: usize, value: Vec) -> Result<&mut Self> { 157 | unsafe { 158 | cass_tuple_set_bytes(self.0, index, value.as_ptr(), value.len()) 159 | .to_result(self) 160 | .chain_err(|| "") 161 | } 162 | } 163 | 164 | /// Sets a "uuid" or "timeuuid" in a tuple at the specified index. 165 | pub fn set_uuid(&mut self, index: usize, value: S) -> Result<&mut Self> 166 | where S: Into { 167 | unsafe { 168 | cass_tuple_set_uuid(self.0, index, value.into().inner()) 169 | .to_result(self) 170 | .chain_err(|| "") 171 | } 172 | } 173 | 174 | /// Sets an "inet" in a tuple at the specified index. 175 | pub fn set_inet(&mut self, index: usize, value: SocketAddr) -> Result<&mut Self> { 176 | let inet = AsInet::as_cass_inet(&value); 177 | unsafe { 178 | cass_tuple_set_inet(self.0, index, inet.inner()) 179 | .to_result(self) 180 | .chain_err(|| "") 181 | } 182 | } 183 | 184 | /// Sets a "list", "map" or "set" in a tuple at the specified index. 185 | pub fn set_collection(&mut self, index: usize, value: S) -> Result<&mut Self> 186 | where S: Into { 187 | unsafe { 188 | cass_tuple_set_collection(self.0, index, value.into().inner()) 189 | .to_result(self) 190 | .chain_err(|| "") 191 | } 192 | } 193 | 194 | /// Sets a "tuple" in a tuple at the specified index. 195 | pub fn set_tuple(&mut self, index: usize, value: Tuple) -> Result<&mut Self> { 196 | unsafe { 197 | cass_tuple_set_tuple(self.0, index, value.0) 198 | .to_result(self) 199 | .chain_err(|| "") 200 | } 201 | } 202 | 203 | /// Sets a "udt" in a tuple at the specified index. 204 | pub fn set_user_type(&mut self, index: usize, value: &UserType) -> Result<&mut Self> { 205 | unsafe { 206 | cass_tuple_set_user_type(self.0, index, value.inner()) 207 | .to_result(self) 208 | .chain_err(|| "") 209 | } 210 | } 211 | } 212 | 213 | impl Drop for Tuple { 214 | fn drop(&mut self) { unsafe { cass_tuple_free(self.0) } } 215 | } 216 | -------------------------------------------------------------------------------- /src/cassandra/util.rs: -------------------------------------------------------------------------------- 1 | pub trait Protected { 2 | fn build(inner: T) -> Self; 3 | fn inner(&self) -> T; 4 | } 5 | -------------------------------------------------------------------------------- /src/cassandra/uuid.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use cassandra::error::CassError; 4 | use cassandra::util::Protected; 5 | 6 | 7 | use cassandra_sys::CASS_OK; 8 | use cassandra_sys::CassUuid as _Uuid; 9 | use cassandra_sys::CassUuidGen as _UuidGen; 10 | use cassandra_sys::cass_uuid_from_string; 11 | use cassandra_sys::cass_uuid_gen_free; 12 | use cassandra_sys::cass_uuid_gen_from_time; 13 | use cassandra_sys::cass_uuid_gen_new; 14 | use cassandra_sys::cass_uuid_gen_new_with_node; 15 | use cassandra_sys::cass_uuid_gen_random; 16 | use cassandra_sys::cass_uuid_gen_time; 17 | use cassandra_sys::cass_uuid_max_from_time; 18 | use cassandra_sys::cass_uuid_min_from_time; 19 | 20 | use cassandra_sys::cass_uuid_string; 21 | use cassandra_sys::cass_uuid_timestamp; 22 | use cassandra_sys::cass_uuid_version; 23 | use errors::*; 24 | use std::ffi::CString; 25 | use std::fmt; 26 | use std::fmt::{Debug, Display}; 27 | use std::fmt::Formatter; 28 | use std::mem; 29 | use std::str; 30 | 31 | const CASS_UUID_STRING_LENGTH: usize = 37; 32 | 33 | 34 | #[derive(Copy,Clone)] 35 | /// Version 1 (time-based) or version 4 (random) UUID. 36 | pub struct Uuid(_Uuid); 37 | 38 | impl Protected<_Uuid> for Uuid { 39 | fn inner(&self) -> _Uuid { self.0 } 40 | fn build(inner: _Uuid) -> Self { Uuid(inner) } 41 | } 42 | 43 | impl Default for Uuid { 44 | fn default() -> Uuid { unsafe { ::std::mem::zeroed() } } 45 | } 46 | 47 | /// A UUID generator object. 48 | /// 49 | /// Instances of the UUID generator object are thread-safe to generate UUIDs. 50 | #[derive(Debug)] 51 | pub struct UuidGen(*mut _UuidGen); 52 | unsafe impl Sync for UuidGen {} 53 | unsafe impl Send for UuidGen {} 54 | 55 | impl Drop for UuidGen { 56 | fn drop(&mut self) { unsafe { cass_uuid_gen_free(self.0) } } 57 | } 58 | 59 | impl Debug for Uuid { 60 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { fmt::Display::fmt(self, f) } 61 | } 62 | 63 | impl Display for Uuid { 64 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { 65 | unsafe { 66 | // Allocate a CString large enough for cass_uuid_string to write to. 67 | let mut buf = CString::from_vec_unchecked(vec!(0u8; CASS_UUID_STRING_LENGTH)); 68 | let cstr = buf.into_raw(); // Convert to *mut c_char 69 | cass_uuid_string(self.0, cstr); // Write the UUID to *c_char 70 | buf = CString::from_raw(cstr); // Convert from *c_char back to a CString. 71 | let str = match buf.into_string() { 72 | Ok(s) => s, 73 | Err(_) => return Err(fmt::Error), 74 | }; 75 | fmt::Display::fmt(&str, f) 76 | } 77 | } 78 | } 79 | 80 | impl Uuid { 81 | /// Generates a V1 (time) UUID for the specified time. 82 | pub fn min_from_time(&mut self, time: u64) { unsafe { cass_uuid_min_from_time(time, &mut self.0) } } 83 | 84 | /// Sets the UUID to the minimum V1 (time) value for the specified tim 85 | pub fn max_from_time(&mut self, time: u64) { unsafe { cass_uuid_max_from_time(time, &mut self.0) } } 86 | 87 | /// Gets the timestamp for a V1 UUID 88 | pub fn timestamp(&self) -> u64 { unsafe { cass_uuid_timestamp(self.0) } } 89 | 90 | /// Gets the version for a UUID 91 | pub fn version(&self) -> u8 { unsafe { cass_uuid_version(self.0) } } 92 | } 93 | 94 | impl str::FromStr for Uuid { 95 | type Err = Error; 96 | fn from_str(str: &str) -> Result { 97 | unsafe { 98 | let mut uuid = mem::zeroed(); 99 | match cass_uuid_from_string(CString::new(str).expect("must be utf8").as_ptr(), &mut uuid) { 100 | CASS_OK => Ok(Uuid(uuid)), 101 | err => { 102 | err.to_result(Uuid(uuid)) 103 | .chain_err(|| "") 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | impl Default for UuidGen { 111 | /// Creates a new thread-safe UUID generator 112 | fn default() -> Self { unsafe { UuidGen(cass_uuid_gen_new()) } } 113 | } 114 | 115 | impl UuidGen { 116 | /// Creates a new UUID generator with custom node information. 117 | /// Note: This object is thread-safe. It is best practice to create and reuse 118 | /// a single object per application. 119 | pub fn new_with_node(node: u64) -> UuidGen { unsafe { UuidGen(cass_uuid_gen_new_with_node(node)) } } 120 | 121 | /// Generates a V1 (time) UUID. 122 | pub fn gen_time(&self) -> Uuid { 123 | unsafe { 124 | let mut output: _Uuid = mem::zeroed(); 125 | cass_uuid_gen_time(self.0, &mut output); 126 | Uuid(output) 127 | } 128 | } 129 | 130 | /// Generates a new V4 (random) UUID 131 | pub fn gen_random(&self) -> Uuid { 132 | unsafe { 133 | let mut output: _Uuid = mem::zeroed(); 134 | cass_uuid_gen_random(self.0, &mut output); 135 | Uuid(output) 136 | } 137 | } 138 | 139 | /// Generates a V1 (time) UUID for the specified time. 140 | /// 141 | /// # Examples 142 | /// 143 | /// ``` 144 | /// # use cassandra::{UuidGen, Uuid}; 145 | /// # #[allow(dead_code)] 146 | /// # fn example() -> Uuid { 147 | /// let generator = UuidGen::default(); 148 | /// let uuid = generator.gen_from_time(1457486866742u64); 149 | /// # uuid 150 | /// # } 151 | /// ``` 152 | pub fn gen_from_time(&self, timestamp: u64) -> Uuid { 153 | unsafe { 154 | let mut output: _Uuid = mem::zeroed(); 155 | cass_uuid_gen_from_time(self.0, timestamp, &mut output); 156 | Uuid(output) 157 | } 158 | } 159 | } 160 | 161 | #[test] 162 | #[allow(unused_variables)] 163 | fn test_uuid_display_gentime() { 164 | let generator = UuidGen::default(); 165 | let uuid = generator.gen_from_time(1457486866742u64); 166 | assert_eq!(uuid.timestamp(), 1457486866742u64); 167 | let uuidstr = format!("{}", uuid); // Test Display trait 168 | } 169 | 170 | #[test] 171 | #[allow(unused_variables)] 172 | fn test_uuid_debug_genrand() { 173 | let generator = UuidGen::default(); 174 | let uuid = generator.gen_random(); 175 | let uuidstr = format!("{:?}", uuid); // Test Debug trait 176 | } 177 | -------------------------------------------------------------------------------- /src/cassandra/write_type.rs: -------------------------------------------------------------------------------- 1 | // use std::ffi::CStr; 2 | 3 | // use cassandra_sys::cass_write_type_string; 4 | 5 | use cassandra_sys::CassWriteType; 6 | 7 | 8 | /// The write type of a request 9 | #[derive(Debug)] 10 | pub struct WriteType(pub CassWriteType); 11 | 12 | impl WriteType { 13 | // ///Gets the string for a write type. 14 | // pub fn write_type_string(&self) -> String { 15 | // unsafe { CStr::from_ptr(cass_write_type_string(self.0)).to_str().unwrap().to_owned() } 16 | // } 17 | } 18 | -------------------------------------------------------------------------------- /src/examples/async.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | extern crate num; 6 | 7 | use std::str::FromStr; 8 | 9 | 10 | 11 | static NUM_CONCURRENT_REQUESTS: usize = 1000; 12 | 13 | fn insert_into_async(session: &mut Session, key: String) -> Result> { 14 | let mut futures = Vec::::new(); 15 | for i in 0..NUM_CONCURRENT_REQUESTS { 16 | let key: &str = &(key.clone() + &i.to_string()); 17 | let mut statement = stmt!("INSERT INTO examples.async (key, bln, flt, dbl, i32, i64) 18 | VALUES (?, ?, \ 19 | ?, ?, ?, ?);"); 20 | 21 | statement.bind(0, key)?; 22 | statement.bind(1, i % 2 == 0)?; 23 | statement.bind(2, i as f32 / 2.0f32)?; 24 | statement.bind(3, i as f64 / 200.0)?; 25 | statement.bind(4, i as i32 * 10)?; 26 | statement.bind(5, i as i64 * 100)?; 27 | 28 | let future = session.execute(&statement); 29 | futures.push(future); 30 | } 31 | Ok(futures) 32 | } 33 | 34 | pub fn main() { 35 | let mut cluster = Cluster::default(); 36 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 37 | match cluster.connect() { 38 | Ok(ref mut session) => { 39 | session.execute(&stmt!("CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 40 | \'SimpleStrategy\', \'replication_factor\': \'1\' };")) 41 | .wait() 42 | .unwrap(); 43 | session.execute(&stmt!("CREATE TABLE IF NOT EXISTS examples.async(key text, bln boolean, flt float, dbl \ 44 | double, i32 int, i64 bigint, PRIMARY KEY (key));")) 45 | .wait() 46 | .unwrap(); 47 | session.execute(&stmt!("USE examples")).wait().unwrap(); 48 | let futures = insert_into_async(session, "test".to_owned()).unwrap(); 49 | for mut future in futures { 50 | println!("insert result={:?}", future.wait()); 51 | } 52 | } 53 | Err(err) => panic!("couldn't connect: {:?}", err), 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/examples/basic.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | use std::str::FromStr; 6 | 7 | 8 | #[derive(Debug,PartialEq,Clone,Copy)] 9 | struct Basic { 10 | bln: bool, 11 | flt: f32, 12 | dbl: f64, 13 | i32: i32, 14 | i64: i64, 15 | } 16 | 17 | fn insert_into_basic(session: &mut Session, key: &str, basic: Basic) -> Result { 18 | 19 | let mut statement = stmt!("INSERT INTO examples.basic (key, bln, flt, dbl, i32, i64) VALUES (?, ?, ?, ?, ?, ?);"); 20 | statement.bind(0, key)?; 21 | statement.bind(1, basic.bln)?; 22 | statement.bind(2, basic.flt)?; 23 | statement.bind(3, basic.dbl)?; 24 | statement.bind(4, basic.i32)?; 25 | statement.bind(5, basic.i64)?; 26 | session.execute(&statement).wait() 27 | } 28 | 29 | fn select_from_basic(session: &mut Session, key: &str) -> Result> { 30 | let mut statement = stmt!("SELECT * FROM examples.basic WHERE key = ?"); 31 | statement.bind_string(0, key)?; 32 | let result = session.execute(&statement).wait()?; 33 | println!("Result: \n{:?}\n", result); 34 | match result.first_row() { 35 | None => Ok(None), 36 | Some(row) => { 37 | Ok(Some(Basic { 38 | bln: row.get_col(1)?, 39 | dbl: row.get_col(2)?, 40 | flt: row.get_col(3)?, 41 | i32: row.get_col(4)?, 42 | i64: row.get_col(5)?, 43 | })) 44 | } 45 | } 46 | } 47 | 48 | fn main() { 49 | 50 | let input = Basic { 51 | bln: true, 52 | flt: 0.001f32, 53 | dbl: 0.0002f64, 54 | i32: 1, 55 | i64: 2, 56 | }; 57 | 58 | let contact_points = ContactPoints::from_str("127.0.0.1").unwrap(); 59 | 60 | let mut cluster = Cluster::default(); 61 | cluster.set_contact_points(contact_points).unwrap(); 62 | cluster.set_load_balance_round_robin(); 63 | 64 | match cluster.connect() { 65 | Ok(ref mut session) => { 66 | let ks_statement = &stmt!("CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 67 | \'SimpleStrategy\', \'replication_factor\': \'1\' };"); 68 | 69 | let table_statement = &stmt!("CREATE TABLE IF NOT EXISTS examples.basic (key text, bln boolean, flt \ 70 | float, dbl double, i32 int, i64 bigint, PRIMARY KEY (key));"); 71 | 72 | session.execute(ks_statement).wait().unwrap(); 73 | session.execute(table_statement).wait().unwrap(); 74 | 75 | insert_into_basic(session, "test", input).unwrap(); 76 | let output = select_from_basic(session, "test").unwrap().expect("no output from select"); 77 | 78 | println!("{:?}", input); 79 | println!("{:?}", output); 80 | 81 | assert!(input == output); 82 | } 83 | err => println!("{:?}", err), 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/examples/batch.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | use std::str::FromStr; 6 | 7 | struct Pair<'a> { 8 | key: &'a str, 9 | value: &'a str, 10 | } 11 | 12 | 13 | fn insert_into_batch_with_prepared(session: &mut Session, pairs: Vec) -> Result { 14 | let insert_query = "INSERT INTO examples.pairs (key, value) VALUES (?, ?)"; 15 | let prepared = session.prepare(insert_query).unwrap().wait().unwrap(); 16 | let mut batch = Batch::new(CASS_BATCH_TYPE_LOGGED); 17 | for pair in pairs { 18 | let mut statement = prepared.bind(); 19 | statement.bind(0, pair.key)?; 20 | statement.bind(1, pair.value)?; 21 | match batch.add_statement(&statement) { 22 | Ok(_) => {} 23 | Err(err) => panic!("{:?}", err), 24 | } 25 | } 26 | session.execute_batch(batch).wait()?; 27 | Ok(prepared) 28 | } 29 | 30 | pub fn verify_batch(session: &mut Session) { 31 | let select_query = stmt!("SELECT * from examples.pairs"); 32 | 33 | let result = session.execute(&select_query).wait().unwrap(); 34 | println!("{:?}", result); 35 | } 36 | 37 | fn main() { 38 | let create_ks = "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \'SimpleStrategy\', \ 39 | \'replication_factor\': \'1\' };"; 40 | let create_table = "CREATE TABLE IF NOT EXISTS examples.pairs (key text, value text, PRIMARY KEY (key));"; 41 | 42 | let pairs = vec!( 43 | Pair{key:"a", value:"1"}, 44 | Pair{key:"b", value:"2"}, 45 | Pair{key:"c", value:"3"}, 46 | Pair{key:"d", value:"4"}, 47 | ); 48 | 49 | let mut cluster = Cluster::default(); 50 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 51 | 52 | match cluster.connect() { 53 | Ok(ref mut session) => { 54 | session.execute(&stmt!(create_ks)).wait().unwrap(); 55 | session.execute(&stmt!(create_table)).wait().unwrap(); 56 | insert_into_batch_with_prepared(session, pairs).unwrap(); 57 | verify_batch(session); 58 | } 59 | err => println!("{:?}", err), 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/examples/bind_by_name.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use std::str::FromStr; 5 | 6 | fn main() { 7 | 8 | let keyspace = "system_schema"; 9 | let table = "tables"; 10 | 11 | let contact_points = ContactPoints::from_str("127.0.0.1").unwrap(); 12 | 13 | let mut cluster = Cluster::default(); 14 | cluster.set_contact_points(contact_points).unwrap(); 15 | cluster.set_load_balance_round_robin(); 16 | match cluster.connect() { 17 | Ok(ref mut session) => { 18 | let query = format!("select column_name, type from system_schema.columns where keyspace_name = '{}' and \ 19 | table_name = '{}'", 20 | keyspace, 21 | table); 22 | let schema_query = Statement::new(&query, 0); 23 | for _ in 0..1000 { 24 | let result = session.execute(&schema_query).wait().unwrap(); 25 | for row in result { 26 | let name: String = row.get_col_by_name("column_name").unwrap(); 27 | let ftype: String = row.get_col_by_name("type").unwrap(); 28 | 29 | println!("{} {}", name, ftype); 30 | } 31 | } 32 | } 33 | Err(_) => unimplemented!(), 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/examples/callbacks.rs: -------------------------------------------------------------------------------- 1 | #![allow(unstable)] 2 | extern crate cql_ffi; 3 | use std::ffi::CString; 4 | use std::slice; 5 | use cassandra::*; 6 | 7 | //~ uv_mutex_t mutex; 8 | //~ uv_cond_t cond; 9 | //~ Future* close_future = NULL; 10 | //~ UuidGen* uuid_gen = NULL; 11 | 12 | 13 | fn wait_exit() { 14 | uv_mutex_lock(&mutex); 15 | while (close_future == NULL) { 16 | uv_cond_wait(&cond, &mutex); 17 | } 18 | uv_mutex_unlock(&mutex); 19 | cass_future_wait(close_future); 20 | cass_future_free(close_future); 21 | } 22 | 23 | fn signal_exit(session: &Session) { 24 | uv_mutex_lock(&mutex); 25 | close_future = cass_session_close(session); 26 | uv_cond_signal(&cond); 27 | uv_mutex_unlock(&mutex); 28 | } 29 | 30 | //~ void on_create_keyspace(Future* future, void* data); 31 | //~ void on_create_table(Future* future, void* data); 32 | //~ void on_insert(Future* future, void* data); 33 | //~ void on_select(Future* future, void* data); 34 | //~ void on_session_connect(Future* future, void* data); 35 | //~ void on_session_close(Future* future, void* data); 36 | 37 | unsafe fn print_error(future: &mut Future) { 38 | let message = cass_future_error_message(future); 39 | let message = slice::from_raw_buf(&message.data, message.length as usize); 40 | println!("Error: {:?}", message); 41 | } 42 | 43 | unsafe fn create_cluster() -> *mut Cluster { 44 | let cluster = cass_cluster_new(); 45 | cass_cluster_set_contact_points(cluster, str2ref("127.0.0.1,127.0.0.2,127.0.0.3")); 46 | cluster 47 | } 48 | 49 | 50 | fn connect_session(session: Session, cluster: &Cluster, callback: FutureCallback) { 51 | let future = cass_session_connect_keyspace(session, cluster, "examples"); 52 | cass_future_set_callback(future, callback, session); 53 | cass_future_free(future); 54 | } 55 | 56 | fn execute_query(session: Session, query: &str, callback: FutureCallback) { 57 | let statement = cass_statement_new(cass_string_init(query), 0); 58 | let future = cass_session_execute(session, statement); 59 | cass_future_set_callback(future, callback, session); 60 | cass_future_free(future); 61 | cass_statement_free(statement); 62 | } 63 | 64 | fn on_session_connect(future: Future, data: void) { 65 | let session: Session = data; 66 | let code = cass_future_error_code(future); 67 | if (code != CASS_OK) { 68 | print_error(future); 69 | uv_cond_signal(&cond); 70 | return; 71 | } 72 | execute_query(session, 73 | "CREATE KEYSPACE examples WITH replication = {\'class\': \'SimpleStrategy\', \ 74 | \'replication_factor\': \'3\' };", 75 | on_create_keyspace); 76 | } 77 | 78 | fn on_create_keyspace(future: Future, data: void) { 79 | let code = cass_future_error_code(future); 80 | if (code != CASS_OK) { 81 | print_error(future); 82 | } 83 | execute_query(data, 84 | "CREATE TABLE callbacks (key timeuuid PRIMARY KEY, value bigint)", 85 | on_create_table); 86 | } 87 | 88 | fn on_create_table(future: Future, data: Session) { 89 | let insert_query = cass_string_init("INSERT INTO callbacks (key, value) VALUES (?, ?)"); 90 | let code = cass_future_error_code(future); 91 | if (code != CASS_OK) { 92 | print_error(future); 93 | } 94 | statement = cass_statement_new(insert_query, 2); 95 | cass_uuid_gen_time(uuid_gen, &key); 96 | cass_statement_bind_uuid(statement, 0, key); 97 | cass_statement_bind_int64(statement, 1, cass_uuid_timestamp(key)); 98 | insert_future = cass_session_execute(data, statement); 99 | cass_future_set_callback(insert_future, on_insert, data); 100 | cass_statement_free(statement); 101 | cass_future_free(insert_future); 102 | } 103 | 104 | fn on_insert(future: Future, data: Session) { 105 | let code = cass_future_error_code(future); 106 | if (code != CASS_OK) { 107 | print_error(future); 108 | signal_exit(data); 109 | } else { 110 | let select_query = cass_string_init("SELECT * FROM callbacks"); 111 | let statement = cass_statement_new(select_query, 0); 112 | let select_future = cass_session_execute(data, statement); 113 | cass_future_set_callback(select_future, on_select, data); 114 | cass_statement_free(statement); 115 | cass_future_free(select_future); 116 | } 117 | } 118 | 119 | fn on_select(future: Future, data: Session) { 120 | let code = cass_future_error_code(future); 121 | if (code != CASS_OK) { 122 | print_error(future); 123 | } else { 124 | let result = cass_future_get_result(future); 125 | let iterator = cass_iterator_from_result(result); 126 | while (cass_iterator_next(iterator)) { 127 | //Uuid key; 128 | //char key_str[CASS_UUID_STRING_LENGTH]; 129 | let value = 0u64; 130 | let row = cass_iterator_get_row(iterator); 131 | cass_value_get_uuid(cass_row_get_column(row, 0), &key); 132 | cass_uuid_string(key, key_str); 133 | cass_value_get_int64(cass_row_get_column(row, 1), &value); 134 | printf("%s, %llu\n", key_str, value); 135 | } 136 | cass_iterator_free(iterator); 137 | cass_result_free(result); 138 | } 139 | signal_exit(data); 140 | } 141 | 142 | fn main() { 143 | Cluster * cluster = create_cluster(); 144 | Session * session = cass_session_new(); 145 | uuid_gen = cass_uuid_gen_new(); 146 | uv_mutex_init(&mutex); 147 | uv_cond_init(&cond); 148 | connect_session(session, cluster, on_session_connect); 149 | /* Code running in parallel with queries */ 150 | wait_exit(); 151 | uv_cond_destroy(&cond); 152 | uv_mutex_destroy(&mutex); 153 | cass_cluster_free(cluster); 154 | cass_uuid_gen_free(uuid_gen); 155 | cass_session_free(session); 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /src/examples/collections.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | use std::str::FromStr; 6 | 7 | 8 | fn insert_into_collections(session: &mut Session, key: &str, items: Vec<&str>) -> Result { 9 | let mut statement = stmt!("INSERT INTO examples.collections (key, items) VALUES (?, ?);"); 10 | statement.bind(0, key)?; 11 | let mut set = Set::new(2); 12 | for item in items { 13 | set.append_string(item)?; 14 | } 15 | statement.bind_set(1, set)?; 16 | session.execute(&statement).wait() 17 | } 18 | 19 | fn select_from_collections(session: &mut Session, key: &str) -> Result<()> { 20 | let mut statement = stmt!("SELECT items FROM examples.collections WHERE key = ?"); 21 | statement.bind(0, key)?; 22 | let result = session.execute(&statement).wait()?; 23 | println!("{:?}", result); 24 | for row in result.iter() { 25 | let column = row.get_column(0); 26 | let items_iterator: SetIterator = column?.set_iter()?; 27 | for item in items_iterator { 28 | println!("item: {:?}", item); 29 | } 30 | } 31 | Ok(()) 32 | } 33 | 34 | fn main() { 35 | let create_ks = stmt!("CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 36 | \'SimpleStrategy\', \'replication_factor\': \'1\' };"); 37 | let create_table = stmt!("CREATE TABLE IF NOT EXISTS examples.collections (key text, items set, PRIMARY \ 38 | KEY (key))"); 39 | 40 | let items = vec!["apple", "orange", "banana", "mango"]; 41 | let contact_points = ContactPoints::from_str("127.0.0.1").unwrap(); 42 | let mut cluster = Cluster::default(); 43 | cluster.set_contact_points(contact_points).unwrap(); 44 | 45 | match cluster.connect() { 46 | Ok(ref mut session) => { 47 | session.execute(&create_ks).wait().unwrap(); 48 | session.execute(&create_table).wait().unwrap(); 49 | insert_into_collections(session, "test", items).unwrap(); 50 | select_from_collections(session, "test").unwrap(); 51 | } 52 | err => println!("{:?}", err), 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/examples/logging.rs: -------------------------------------------------------------------------------- 1 | extern crate cassandra; 2 | 3 | use std::slice; 4 | use std::str::FromStr; 5 | 6 | use cassandra::*; 7 | 8 | fn print_error(future: &mut Future) { 9 | let message = future.error_message(); 10 | println!("Error: {:?}", message); 11 | } 12 | 13 | unsafe fn create_cluster() -> Result { 14 | let cluster = Cluster::default(); 15 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1,127.0.0.2,127.0.0.3")?); 16 | cluster 17 | } 18 | 19 | unsafe fn connect_session(session: &mut Session, cluster: &mut Cluster) -> CassError { 20 | let future: Future = &mut session.connect(cluster); 21 | future.wait(); 22 | future 23 | } 24 | 25 | //~ fn on_log(message:&CassLogMessage, data:data) { 26 | 27 | //~ println!("{}", 28 | //~ message.time_ms / 1000, 29 | //~ message->time_ms % 1000, 30 | //~ cass_log_level_string(message.severity), 31 | //~ message.file, message.line, message.function, 32 | //~ message.message); 33 | //~ } 34 | 35 | fn main() { 36 | //~ Cluster* cluster = NULL; 37 | //~ Session* session = NULL; 38 | //~ Future* close_future = NULL; 39 | //~ FILE* log_file = fopen("driver.log", "w+"); 40 | //~ if (log_file == NULL) { 41 | //~ fprintf(stderr, "Unable to open log file\n"); 42 | //~ } 43 | /* Log configuration *MUST* be done before any other driver call */ 44 | use CassLogLevel::*; 45 | cass_log_set_level(CASS_LOG_INFO); 46 | cass_log_set_callback(on_log, log_file); 47 | cluster = create_cluster(); 48 | session = cass_session_new(); 49 | if connect_session(session, cluster) != CASS_OK { 50 | cass_cluster_free(cluster); 51 | cass_session_free(session); 52 | return -1; 53 | } 54 | close_future = cass_session_close(session); 55 | cass_future_wait(close_future); 56 | cass_future_free(close_future); 57 | cass_cluster_free(cluster); 58 | cass_session_free(session); 59 | /* This *MUST* be the last driver call */ 60 | cass_log_cleanup(); 61 | fclose(log_file); 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/examples/maps.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | use std::error::Error; 6 | use std::str::FromStr; 7 | 8 | struct Pair<'a> { 9 | key: &'a str, 10 | value: i32, 11 | } 12 | static CREATE_KEYSPACE: &'static str = "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 13 | \'SimpleStrategy\', \'replication_factor\': \'3\' };"; 14 | static CREATE_TABLE: &'static str = "CREATE TABLE IF NOT EXISTS examples.maps (key text, items map, \ 15 | PRIMARY KEY (key))"; 16 | static SELECT_QUERY: &'static str = "SELECT items FROM examples.maps WHERE key = ?"; 17 | 18 | fn insert_into_maps(session: &mut Session, key: &str, items: Vec) -> Result<()> { 19 | let mut insert_statement = stmt!("INSERT INTO examples.maps (key, items) VALUES (?, ?);"); 20 | insert_statement.bind(0, key).unwrap(); 21 | 22 | let mut map = Map::new(5); 23 | for item in items { 24 | map.append_string(item.key).unwrap(); 25 | map.append_int32(item.value).unwrap(); 26 | } 27 | insert_statement.bind(1, map)?; 28 | session.execute(&insert_statement).wait()?; 29 | Ok(()) 30 | } 31 | 32 | fn select_from_maps(session: &mut Session, key: &str) -> Result<()> { 33 | let mut statement = Statement::new(SELECT_QUERY, 1); 34 | statement.bind(0, key)?; 35 | let result = session.execute(&statement).wait()?; 36 | // println!("{:?}", result); 37 | for row in result.iter() { 38 | let column = row.get_column(0).unwrap(); //FIXME 39 | let items_iterator: MapIterator = column.map_iter().unwrap(); 40 | for item in items_iterator { 41 | println!("item: {:?}", item); 42 | } 43 | } 44 | Ok(()) 45 | } 46 | 47 | fn main() { 48 | match foo() { 49 | Ok(()) => {} 50 | Err(err) => println!("Error: {:?}", err), 51 | } 52 | } 53 | 54 | fn foo() -> Result<()> { 55 | let mut cluster = Cluster::default(); 56 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 57 | cluster.set_load_balance_round_robin(); 58 | 59 | let items: Vec = vec![Pair { 60 | key: "apple", 61 | value: 1, 62 | }, 63 | Pair { 64 | key: "orange", 65 | value: 2, 66 | }, 67 | Pair { 68 | key: "banana", 69 | value: 3, 70 | }, 71 | Pair { 72 | key: "mango", 73 | value: 4, 74 | }]; 75 | match cluster.connect() { 76 | Ok(ref mut session) => { 77 | session.execute(&stmt!(CREATE_KEYSPACE)).wait()?; 78 | session.execute(&stmt!(CREATE_TABLE)).wait()?; 79 | insert_into_maps(session, "test", items)?; 80 | select_from_maps(session, "test")?; 81 | Ok(()) 82 | } 83 | Err(err) => Err(err), 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/examples/paging.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | 4 | use cassandra::*; 5 | use errors::*; 6 | use std::str::FromStr; 7 | 8 | static NUM_CONCURRENT_REQUESTS: isize = 100; 9 | static CREATE_KEYSPACE: &'static str = "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 10 | \'SimpleStrategy\', \'replication_factor\': \'1\' };"; 11 | static CREATE_TABLE: &'static str = "CREATE TABLE IF NOT EXISTS examples.paging (key ascii, value text, PRIMARY KEY \ 12 | (key));"; 13 | static SELECT_QUERY: &'static str = "SELECT * FROM paging"; 14 | static INSERT_QUERY: &'static str = "INSERT INTO paging (key, value) VALUES (?, ?);"; 15 | 16 | // FIXME uuids not yet working 17 | fn insert_into_paging(session: &mut Session /* , uuid_gen:&mut UuidGen */) -> Result>> { 18 | let mut futures = Vec::with_capacity(NUM_CONCURRENT_REQUESTS as usize); 19 | let mut results = Vec::with_capacity(NUM_CONCURRENT_REQUESTS as usize); 20 | 21 | for i in 0..NUM_CONCURRENT_REQUESTS { 22 | let key: &str = &(i.to_string()); 23 | println!("key ={:?}", key); 24 | let mut statement = Statement::new(INSERT_QUERY, 2); 25 | statement.bind(0, key)?; 26 | statement.bind(1, key)?; 27 | let future = session.execute(&statement); 28 | futures.push(future); 29 | } 30 | 31 | while !futures.is_empty() { 32 | results.push(futures.pop()); 33 | } 34 | Ok(results) 35 | } 36 | 37 | fn select_from_paging(session: &mut Session) -> Result<()> { 38 | let has_more_pages = true; 39 | let mut statement = Statement::new(SELECT_QUERY, 0); 40 | statement.set_paging_size(100).unwrap(); 41 | 42 | // FIXME must understand statement lifetime better for paging 43 | while has_more_pages { 44 | let result = session.execute(&statement).wait()?; 45 | // println!("{:?}", result); 46 | for row in result.iter() { 47 | match row.get_column(0)?.get_string() { 48 | Ok(key) => { 49 | let key_str = key.to_string(); 50 | let value = row.get_column(1)?; 51 | println!("key: '{:?}' value: '{:?}'", 52 | key_str, 53 | &value.get_string().unwrap()); 54 | } 55 | Err(err) => panic!(err), 56 | } 57 | } 58 | // if result.has_more_pages() { 59 | // try!(statement.set_paging_state(&result)); 60 | // } 61 | // has_more_pages = result.has_more_pages(); 62 | } 63 | Ok(()) 64 | } 65 | 66 | fn main() { 67 | // let uuid_gen = &mut UuidGen::new(); 68 | 69 | let mut cluster = Cluster::default(); 70 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 71 | cluster.set_load_balance_round_robin(); 72 | 73 | match cluster.connect() { 74 | Ok(ref mut session) => { 75 | session.execute(&stmt!(CREATE_KEYSPACE)).wait().unwrap(); 76 | session.execute(&stmt!(CREATE_TABLE)).wait().unwrap(); 77 | session.execute(&stmt!("USE examples")).wait().unwrap(); 78 | let results = insert_into_paging(session /* , uuid_gen */).unwrap(); 79 | for result in results { 80 | print!("{:?}", result.unwrap().wait().unwrap()); 81 | } 82 | select_from_paging(session).unwrap(); 83 | } 84 | err => println!("{:?}", err), 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/examples/perf.rs: -------------------------------------------------------------------------------- 1 | //~ #include 2 | //~ #include 3 | //~ #include 4 | //~ #include 5 | //~ #include 6 | //~ #include 7 | //~ #include "cassandra.h" 8 | //~ /* 9 | //~ * Use this example with caution. It's just used as a scratch example for debugging and 10 | //~ * roughly analyzing performance. 11 | //~ */ 12 | //~ #define NUM_THREADS 1 13 | //~ #define NUM_IO_WORKER_THREADS 4 14 | //~ #define NUM_CONCURRENT_REQUESTS 10000 15 | //~ #define NUM_SAMPLES 1000 16 | //~ #define USE_PREPARED 1 17 | //~ const char* big_string = "0123456701234567012345670123456701234567012345670123456701234567" 18 | //~ "0123456701234567012345670123456701234567012345670123456701234567" 19 | //~ "0123456701234567012345670123456701234567012345670123456701234567" 20 | //~ "0123456701234567012345670123456701234567012345670123456701234567" 21 | //~ "0123456701234567012345670123456701234567012345670123456701234567" 22 | //~ "0123456701234567012345670123456701234567012345670123456701234567" 23 | //~ "0123456701234567012345670123456701234567012345670123456701234567"; 24 | //~ UuidGen* uuid_gen; 25 | //~ typedef struct ThreadStats_ { 26 | //~ long count; 27 | //~ double total_averages; 28 | //~ double samples[NUM_SAMPLES]; 29 | //~ } ThreadStats; 30 | //~ void print_error(Future* future) { 31 | //~ CassString message = cass_future_error_message(future); 32 | //~ fprintf(stderr, "Error: %.*s\n", (int)message.length, message.data); 33 | //~ } 34 | //~ Cluster* create_cluster() { 35 | //~ Cluster* cluster = cass_cluster_new(); 36 | //~ cass_cluster_set_contact_points(cluster, "127.0.0.1"); 37 | //~ cass_cluster_set_credentials(cluster, "cassandra", "cassandra"); 38 | //~ cass_cluster_set_num_threads_io(cluster, NUM_IO_WORKER_THREADS); 39 | //~ cass_cluster_set_queue_size_io(cluster, 10000); 40 | //~ cass_cluster_set_pending_requests_low_water_mark(cluster, 5000); 41 | //~ cass_cluster_set_pending_requests_high_water_mark(cluster, 10000); 42 | //~ cass_cluster_set_core_connections_per_host(cluster, 1); 43 | //~ cass_cluster_set_max_connections_per_host(cluster, 2); 44 | //~ return cluster; 45 | //~ } 46 | //~ CassandraError connect_session(Session* session, const Cluster* cluster) { 47 | //~ CassandraError rc = CASS_OK; 48 | //~ Future* future = cass_session_connect_keyspace(session, cluster, "examples"); 49 | //~ cass_future_wait(future); 50 | //~ rc = cass_future_error_code(future); 51 | //~ if (rc != CASS_OK) { 52 | //~ print_error(future); 53 | //~ } 54 | //~ cass_future_free(future); 55 | //~ return rc; 56 | //~ } 57 | //~ CassandraError execute_query(Session* session, const char* query) { 58 | //~ CassandraError rc = CASS_OK; 59 | //~ Future* future = NULL; 60 | //~ Statement* statement = cass_statement_new(cass_string_init(query), 0); 61 | //~ future = cass_session_execute(session, statement); 62 | //~ cass_future_wait(future); 63 | //~ rc = cass_future_error_code(future); 64 | //~ if (rc != CASS_OK) { 65 | //~ print_error(future); 66 | //~ } 67 | //~ cass_future_free(future); 68 | //~ cass_statement_free(statement); 69 | //~ return rc; 70 | //~ } 71 | //~ CassandraError prepare_query(Session* session, CassString query, const PreparedStatement** prepared) { 72 | //~ CassandraError rc = CASS_OK; 73 | //~ Future* future = NULL; 74 | //~ future = cass_session_prepare(session, query); 75 | //~ cass_future_wait(future); 76 | //~ rc = cass_future_error_code(future); 77 | //~ if (rc != CASS_OK) { 78 | //~ print_error(future); 79 | //~ } else { 80 | //~ *prepared = cass_future_get_prepared(future); 81 | //~ } 82 | //~ cass_future_free(future); 83 | //~ return rc; 84 | //~ } 85 | //~ int compare_dbl(const void* d1, const void* d2) { 86 | //~ if (*((double*)d1) < *((double*)d2)) { 87 | //~ return -1; 88 | //~ } else if (*((double*)d1) > *((double*)d2)) { 89 | //~ return 1; 90 | //~ } else { 91 | //~ return 0; 92 | //~ } 93 | //~ } 94 | //~ void print_thread_stats(ThreadStats* thread_stats) { 95 | //~ double throughput_avg = 0.0; 96 | //~ double throughput_min = 0.0; 97 | //~ double throughput_median = 0.0; 98 | //~ double throughput_max = 0.0; 99 | //~ int index_median = ceil(0.5 * NUM_SAMPLES); 100 | //~ qsort(thread_stats->samples, NUM_SAMPLES, sizeof(double), compare_dbl); 101 | //~ throughput_avg = thread_stats->total_averages / thread_stats->count; 102 | //~ throughput_min = thread_stats->samples[0]; 103 | //~ throughput_median = thread_stats->samples[index_median]; 104 | //~ throughput_max = thread_stats->samples[NUM_SAMPLES - 1]; 105 | //~ printf("%d IO threads, %d requests/batch:\navg: %f\nmin: %f\nmedian: %f\nmax: %f\n", 106 | //~ NUM_IO_WORKER_THREADS, 107 | //~ NUM_CONCURRENT_REQUESTS, 108 | //~ throughput_avg, 109 | //~ throughput_min, 110 | //~ throughput_median, 111 | //~ throughput_max); 112 | //~ } 113 | //~ void insert_into_perf(Session* session, CassString query, const PreparedStatement* prepared, 114 | //~ ThreadStats* thread_stats) { 115 | //~ int i; 116 | //~ double elapsed, throughput; 117 | //~ uint64_t start; 118 | //~ int num_requests = 0; 119 | //~ Future* futures[NUM_CONCURRENT_REQUESTS]; 120 | //~ unsigned long thread_id = uv_thread_self(); 121 | //~ CassCollection* collection = cass_collection_new(CASS_COLLECTION_TYPE_SET, 2); 122 | //~ cass_collection_append_string(collection, cass_string_init("jazz")); 123 | //~ cass_collection_append_string(collection, cass_string_init("2013")); 124 | //~ start = uv_hrtime(); 125 | //~ for (i = 0; i < NUM_CONCURRENT_REQUESTS; ++i) { 126 | //~ Uuid id; 127 | //~ Statement* statement; 128 | //~ if (prepared != NULL) { 129 | //~ statement = cass_prepared_bind(prepared); 130 | //~ } else { 131 | //~ statement = cass_statement_new(query, 5); 132 | //~ } 133 | //~ cass_uuid_gen_time(uuid_gen, &id); 134 | //~ cass_statement_bind_uuid(statement, 0, id); 135 | //~ cass_statement_bind_string(statement, 1, cass_string_init(big_string)); 136 | //~ cass_statement_bind_string(statement, 2, cass_string_init(big_string)); 137 | //~ cass_statement_bind_string(statement, 3, cass_string_init(big_string)); 138 | //~ cass_statement_bind_collection(statement, 4, collection); 139 | //~ futures[i] = cass_session_execute(session, statement); 140 | //~ cass_statement_free(statement); 141 | //~ } 142 | //~ for (i = 0; i < NUM_CONCURRENT_REQUESTS; ++i) { 143 | //~ Future* future = futures[i]; 144 | //~ CassandraError rc = cass_future_error_code(future); 145 | //~ if (rc != CASS_OK) { 146 | //~ print_error(future); 147 | //~ } else { 148 | //~ num_requests++; 149 | //~ } 150 | //~ cass_future_free(future); 151 | //~ } 152 | //~ elapsed = (double)(uv_hrtime() - start) / 1000000000.0; 153 | //~ throughput = (double)num_requests / elapsed; 154 | //~ thread_stats->samples[thread_stats->count++] = throughput; 155 | //~ thread_stats->total_averages += throughput; 156 | //~ printf("%ld: average %f inserts/sec (%d, %f)\n", thread_id, thread_stats->total_averages / thread_stats->count, num_requests, elapsed); 157 | //~ cass_collection_free(collection); 158 | //~ } 159 | //~ void run_insert_queries(void* data) { 160 | //~ int i; 161 | //~ Session* session = (Session*)data; 162 | //~ const PreparedStatement* insert_prepared = NULL; 163 | //~ CassString insert_query = cass_string_init("INSERT INTO songs (id, title, album, artist, tags) VALUES (?, ?, ?, ?, ?);"); 164 | //~ ThreadStats thread_stats; 165 | //~ thread_stats.count = 0; 166 | //~ thread_stats.total_averages = 0.0; 167 | //~ #if USE_PREPARED 168 | //~ if (prepare_query(session, insert_query, &insert_prepared) == CASS_OK) { 169 | //~ #endif 170 | //~ for (i = 0; i < NUM_SAMPLES; ++i) { 171 | //~ insert_into_perf(session, insert_query, insert_prepared, &thread_stats); 172 | //~ } 173 | //~ #if USE_PREPARED 174 | //~ cass_prepared_free(insert_prepared); 175 | //~ } 176 | //~ #endif 177 | //~ print_thread_stats(&thread_stats); 178 | //~ } 179 | //~ void select_from_perf(Session* session, CassString query, const PreparedStatement* prepared, 180 | //~ ThreadStats* thread_stats) { 181 | //~ int i; 182 | //~ double elapsed, throughput; 183 | //~ uint64_t start; 184 | //~ int num_requests = 0; 185 | //~ Future* futures[NUM_CONCURRENT_REQUESTS]; 186 | //~ unsigned long thread_id = uv_thread_self(); 187 | //~ start = uv_hrtime(); 188 | //~ for (i = 0; i < NUM_CONCURRENT_REQUESTS; ++i) { 189 | //~ Statement* statement; 190 | //~ if (prepared != NULL) { 191 | //~ statement = cass_prepared_bind(prepared); 192 | //~ } else { 193 | //~ statement = cass_statement_new(query, 0); 194 | //~ } 195 | //~ futures[i] = cass_session_execute(session, statement); 196 | //~ cass_statement_free(statement); 197 | //~ } 198 | //~ for (i = 0; i < NUM_CONCURRENT_REQUESTS; ++i) { 199 | //~ Future* future = futures[i]; 200 | //~ CassandraError rc = cass_future_error_code(future); 201 | //~ if (rc != CASS_OK) { 202 | //~ print_error(future); 203 | //~ } else { 204 | //~ const CassandraResult* result = cass_future_get_result(future); 205 | //~ assert(cass_result_column_count(result) == 6); 206 | //~ cass_result_free(result); 207 | //~ num_requests++; 208 | //~ } 209 | //~ cass_future_free(future); 210 | //~ } 211 | //~ elapsed = (double)(uv_hrtime() - start) / 1000000000.0; 212 | //~ throughput = (double)num_requests / elapsed; 213 | //~ thread_stats->samples[thread_stats->count++] = throughput; 214 | //~ thread_stats->total_averages += throughput; 215 | //~ printf("%ld: average %f selects/sec (%d, %f)\n", thread_id, thread_stats->total_averages / thread_stats->count, num_requests, elapsed); 216 | //~ } 217 | //~ void run_select_queries(void* data) { 218 | //~ int i; 219 | //~ Session* session = (Session*)data; 220 | //~ const PreparedStatement* select_prepared = NULL; 221 | //~ CassString select_query = cass_string_init("SELECT * FROM songs WHERE id = a98d21b2-1900-11e4-b97b-e5e358e71e0d"); 222 | //~ ThreadStats thread_stats; 223 | //~ thread_stats.count = 0; 224 | //~ thread_stats.total_averages = 0.0; 225 | //~ #if USE_PREPARED 226 | //~ if (prepare_query(session, select_query, &select_prepared) == CASS_OK) { 227 | //~ #endif 228 | //~ for (i = 0; i < NUM_SAMPLES; ++i) { 229 | //~ select_from_perf(session, select_query, select_prepared, &thread_stats); 230 | //~ } 231 | //~ #if USE_PREPARED 232 | //~ cass_prepared_free(select_prepared); 233 | //~ } 234 | //~ #endif 235 | //~ print_thread_stats(&thread_stats); 236 | //~ } 237 | //~ int main() { 238 | //~ int i; 239 | //~ uv_thread_t threads[NUM_THREADS]; 240 | //~ Cluster* cluster = NULL; 241 | //~ Session* session = NULL; 242 | //~ Future* close_future = NULL; 243 | //~ cass_log_set_level(CASS_LOG_INFO); 244 | //~ cluster = create_cluster(); 245 | //~ uuid_gen = cass_uuid_gen_new(); 246 | //~ session = cass_session_new(); 247 | //~ if (connect_session(session, cluster) != CASS_OK) { 248 | //~ cass_cluster_free(cluster); 249 | //~ cass_session_free(session); 250 | //~ return -1; 251 | //~ } 252 | //~ execute_query(session, 253 | //~ "INSERT INTO songs (id, title, album, artist, tags) VALUES " 254 | //~ "(a98d21b2-1900-11e4-b97b-e5e358e71e0d, " 255 | //~ "'La Petite Tonkinoise', 'Bye Bye Blackbird', 'Joséphine Baker', { 'jazz', '2013' });"); 256 | //~ #define DO_SELECTS 257 | //~ for (i = 0; i < NUM_THREADS; ++i) { 258 | //~ #ifdef DO_INSERTS 259 | //~ uv_thread_create(&threads[i], run_insert_queries, (void*)session); 260 | //~ #endif 261 | //~ #ifdef DO_SELECTS 262 | //~ uv_thread_create(&threads[i], run_select_queries, (void*)session); 263 | //~ #endif 264 | //~ } 265 | //~ for (i = 0; i < NUM_THREADS; ++i) { 266 | //~ uv_thread_join(&threads[i]); 267 | //~ } 268 | //~ close_future = cass_session_close(session); 269 | //~ cass_future_wait(close_future); 270 | //~ cass_future_free(close_future); 271 | //~ cass_cluster_free(cluster); 272 | //~ cass_uuid_gen_free(uuid_gen); 273 | //~ return 0; 274 | //~ } 275 | -------------------------------------------------------------------------------- /src/examples/prepared.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | use std::str::FromStr; 6 | 7 | static CREATE_KEYSPACE: &'static str = "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 8 | \'SimpleStrategy\', \'replication_factor\': \'1\' };"; 9 | static CREATE_TABLE: &'static str = "CREATE TABLE IF NOT EXISTS examples.basic (key text, bln boolean, flt float, dbl \ 10 | double, i32 int, i64 bigint, PRIMARY KEY (key));"; 11 | static INSERT_QUERY: &'static str = "INSERT INTO examples.basic (key, bln, flt, dbl, i32, i64) VALUES (?, ?, ?, ?, ?, \ 12 | ?);"; 13 | static SELECT_QUERY: &'static str = "SELECT * FROM examples.basic WHERE key = ?"; 14 | 15 | #[derive(Debug,PartialEq)] 16 | struct Basic { 17 | bln: bool, 18 | flt: f32, 19 | dbl: f64, 20 | i32: i32, 21 | i64: i64, 22 | } 23 | 24 | fn insert_into_basic(session: &mut Session, key: &str, basic: &mut Basic) -> Result<()> { 25 | println!("Creating statement"); 26 | let mut statement = stmt!(INSERT_QUERY); 27 | statement.bind(0, key)?; 28 | statement.bind(1, basic.bln)?; 29 | statement.bind(2, basic.flt)?; 30 | statement.bind(3, basic.dbl)?; 31 | statement.bind(4, basic.i32)?; 32 | statement.bind(5, basic.i64)?; 33 | 34 | println!("Executing insert statement"); 35 | session.execute(&statement).wait()?; 36 | println!("Insert execute OK"); 37 | Ok(()) 38 | } 39 | 40 | 41 | fn select_from_basic(session: &mut Session, prepared: &PreparedStatement, key: &str, basic: &mut Basic) -> Result<()> { 42 | let mut statement = prepared.bind(); 43 | statement.bind_string(0, key)?; 44 | let mut future = session.execute(&statement); 45 | match future.wait() { 46 | Ok(result) => { 47 | println!("{:?}", result); 48 | for row in result.iter() { 49 | basic.bln = row.get_col(1)?; 50 | basic.dbl = row.get_col(2)?; 51 | basic.flt = row.get_col(3)?; 52 | basic.i32 = row.get_col(4)?; 53 | basic.i64 = row.get_col(5)?; 54 | } 55 | Ok(()) 56 | } 57 | Err(err) => panic!("{:?}", err), 58 | } 59 | } 60 | 61 | fn main() { 62 | let mut cluster = Cluster::default(); 63 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 64 | cluster.set_protocol_version(CqlProtocol::THREE).unwrap(); 65 | 66 | match cluster.connect() { 67 | Ok(ref mut session) => { 68 | 69 | let mut input = Basic { 70 | bln: true, 71 | flt: 0.001f32, 72 | dbl: 0.0002f64, 73 | i32: 1, 74 | i64: 2, 75 | }; 76 | let mut output = Basic { 77 | bln: false, 78 | flt: 0f32, 79 | dbl: 0f64, 80 | i32: 0, 81 | i64: 0, 82 | }; 83 | println!("Executing create keyspace"); 84 | session.execute(&stmt!(CREATE_KEYSPACE)).wait().unwrap(); 85 | println!("Creating table"); 86 | session.execute(&stmt!(CREATE_TABLE)).wait().unwrap(); 87 | 88 | println!("Basic insertions"); 89 | insert_into_basic(session, "prepared_test", &mut input).unwrap(); 90 | println!("Preparing"); 91 | match session.prepare(SELECT_QUERY).unwrap().wait() { 92 | Ok(prepared) => { 93 | select_from_basic(session, &prepared, "prepared_test", &mut output).unwrap(); 94 | println!("input: {:?}\nouput: {:?}", input, output); 95 | assert_eq!(input, output); 96 | } 97 | Err(err) => panic!(err), 98 | } 99 | } 100 | err => println!("{:?}", err), 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/examples/schema_meta.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | 4 | 5 | use cassandra::*; 6 | use errors::*; 7 | use std::str::FromStr; 8 | 9 | 10 | fn print_function(session: &Session, keyspace: &str, function: &str, arguments: Vec<&str>) -> Result<()> { 11 | let schema_meta = session.get_schema_meta(); 12 | let keyspace_meta: KeyspaceMeta = schema_meta.get_keyspace_by_name(keyspace); 13 | 14 | let function_meta = keyspace_meta.get_function_by_name(function, arguments).unwrap(); 15 | print_function_meta(function_meta, 0); 16 | Ok(()) 17 | } 18 | 19 | fn print_function_meta(meta: FunctionMeta, indent: i32) { 20 | print_indent(indent); 21 | let name = meta.get_name(); 22 | println!("Function \"name\": {}", name); 23 | 24 | print_meta_fields(meta.fields_iter(), indent + 1); 25 | println!(""); 26 | } 27 | 28 | // fn print_schema_map(map: MapIterator) { 29 | // let mut is_first = true; 30 | // 31 | // print!("{{ "); 32 | // for pair in map { 33 | // if !is_first { 34 | // print!(", ") 35 | // } 36 | // print_schema_value(pair.0); 37 | // print!(" : "); 38 | // print_schema_value(pair.1); 39 | // is_first = false; 40 | // } 41 | // print!(" }}"); 42 | // } 43 | 44 | // fn print_schema_set(set: SetIterator) { 45 | // let mut is_first = true; 46 | // print!("{{ "); 47 | // for item in set { 48 | // if !is_first { 49 | // print!(", ") 50 | // } 51 | // print_schema_value(item); 52 | // is_first = false; 53 | // } 54 | // print!(" }}"); 55 | // } 56 | 57 | fn print_aggregate_meta(meta: AggregateMeta, indent: i32) { 58 | print_indent(indent); 59 | println!("Aggregate \"{}\":", meta.get_name()); 60 | print_meta_fields(meta.fields_iter(), indent + 1); 61 | println!(""); 62 | } 63 | 64 | fn print_meta_fields(iterator: FieldIterator, indent: i32) { 65 | for item in iterator { 66 | print_indent(indent); 67 | println!("{}: ", item.name); 68 | print_schema_value(item.value); 69 | println!(""); 70 | 71 | } 72 | } 73 | 74 | fn print_schema_value(value: Value) { 75 | // FIXME 76 | let value = match value.get_type() { 77 | // CASS_VALUE_TYPE_INT => value.get_i32().unwrap().to_string(), 78 | // CASS_VALUE_TYPE_BOOL => if value.get_bool().unwrap() { "true".to_owned() } else { "false".to_owned() }, 79 | // CASS_VALUE_TYPE_DOUBLE => value.get_dbl().unwrap().to_string(), 80 | // 81 | // CASS_VALUE_TYPE_TEXT | CASS_VALUE_TYPE_ASCII | CASS_VALUE_TYPE_VARCHAR => 82 | // value.get_string().unwrap().to_string(), 83 | // CASS_VALUE_TYPE_UUID => value.get_uuid().unwrap().to_string(), 84 | // CASS_VALUE_TYPE_LIST => { 85 | // print_schema_set(value.get_set().unwrap()); 86 | // "".to_owned() 87 | // } 88 | // CASS_VALUE_TYPE_MAP => { 89 | // print_schema_map(value.get_map().unwrap()); 90 | // "".to_owned() 91 | // } 92 | // CASS_VALUE_TYPE_BLOB => { 93 | // print_schema_bytes(value.get_bytes().unwrap()); 94 | // "".to_owned() 95 | // } 96 | _ => "".to_owned(), 97 | }; 98 | print!("{}", value); 99 | 100 | } 101 | 102 | // fn print_schema_bytes(bytes: &[u8]) { 103 | // print!("0x"); 104 | // for byte in bytes { 105 | // print!("{}", byte); 106 | // } 107 | // } 108 | 109 | fn main() { 110 | let result = cass(); 111 | println!("{:?}", result); 112 | } 113 | 114 | fn cass() -> Result<()> { 115 | let mut cluster = Cluster::default(); 116 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 117 | cluster.set_load_balance_round_robin(); 118 | 119 | let create_ks = stmt!("CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 120 | \'SimpleStrategy\', \'replication_factor\': \'1\' };"); 121 | let create_table = stmt!("CREATE TABLE IF NOT EXISTS examples.schema_meta (key text, value bigint, PRIMARY KEY \ 122 | (key));"); 123 | 124 | let create_func1 = stmt!("CREATE FUNCTION IF NOT EXISTS examples.avg_state(state tuple, val int) \ 125 | CALLED ON NULL INPUT RETURNS tuple LANGUAGE java AS 'if (val != null) { \ 126 | state.setInt(0, state.getInt(0) + 1); state.setLong(1, state.getLong(1) + \ 127 | val.intValue()); } return state;';"); 128 | let create_func2 = stmt!("CREATE FUNCTION IF NOT EXISTS examples.avg_final (state tuple) CALLED ON \ 129 | NULL INPUT RETURNS double LANGUAGE java AS 'double r = 0; if (state.getInt(0) == 0) \ 130 | return null; r = state.getLong(1); r /= state.getInt(0); return Double.valueOf(r);';"); 131 | 132 | let create_aggregate = stmt!("CREATE AGGREGATE examples.average(int) SFUNC avg_state STYPE tuple \ 133 | FINALFUNC avg_final INITCOND(0, 0);"); 134 | 135 | 136 | match cluster.connect() { 137 | Ok(ref mut session) => { 138 | session.execute(&create_ks).wait()?; 139 | print_keyspace(session, "examples"); 140 | session.execute(&create_table).wait()?; 141 | session.execute(&create_func1).wait()?; 142 | session.execute(&create_func2).wait()?; 143 | session.execute(&create_aggregate).wait()?; 144 | let schema = &session.get_schema_meta(); 145 | let keyspace = schema.get_keyspace_by_name("examples"); 146 | let mut table = keyspace.table_by_name("schema_meta").unwrap(); 147 | print_table_meta(&mut table, 0); 148 | print_function(session, 149 | "examples", 150 | "avg_state", 151 | vec!["tuple", "int"])?; 152 | print_function(session, "examples", "avg_final", vec!["tuple"])?; 153 | print_aggregate(session, "examples", "average", vec!["int"])?; 154 | Ok(()) 155 | } 156 | _ => panic!(), 157 | } 158 | } 159 | 160 | 161 | fn print_aggregate(session: &Session, keyspace: &str, aggregate: &str, arguments: Vec<&str>) -> Result<()> { 162 | let schema_meta = session.get_schema_meta(); 163 | let keyspace_meta = schema_meta.get_keyspace_by_name(keyspace); 164 | 165 | let aggregate_meta = keyspace_meta.aggregate_by_name(aggregate, arguments).unwrap(); 166 | print_aggregate_meta(aggregate_meta, 0); 167 | Ok(()) 168 | // } else { 169 | // println!("Unable to find \"{}\" aggregate in the schema metadata", aggregate); 170 | // } 171 | // } else { 172 | // println!("Unable to find \"{}\" keyspace in the schema metadata", keyspace); 173 | // } 174 | 175 | // cass_schema_meta_free(schema_meta); 176 | } 177 | 178 | fn print_table_meta(meta: &mut TableMeta, indent: i32) { 179 | print_indent(indent); 180 | let name = meta.get_name(); 181 | println!("Table \"{}\":\n", name); 182 | 183 | print_meta_fields(meta.field_iter(), indent + 1); 184 | println!(""); 185 | 186 | for mut column in meta.columns_iter() { 187 | print_column_meta(&mut column, indent + 1); 188 | } 189 | println!(""); 190 | } 191 | 192 | fn print_column_meta(meta: &mut ColumnMeta, indent: i32) { 193 | print_indent(indent); 194 | let name = meta.name(); 195 | println!("Column \"{}\":", name); 196 | print_meta_fields(meta.field_iter(), indent + 1); 197 | println!(""); 198 | } 199 | 200 | fn print_indent(indent: i32) { 201 | for _ in 0..indent { 202 | print!("\t"); 203 | } 204 | } 205 | 206 | fn print_keyspace(session: &Session, keyspace: &str) { 207 | let schema_meta = session.get_schema_meta(); 208 | let mut keyspace_meta = schema_meta.get_keyspace_by_name(keyspace); 209 | print_keyspace_meta(&mut keyspace_meta, 0); 210 | } 211 | 212 | fn print_keyspace_meta(keyspace_meta: &mut KeyspaceMeta, indent: i32) { 213 | print_indent(indent); 214 | let name = keyspace_meta.name(); 215 | println!("Keyspace \"{}\":\n", name); 216 | 217 | print_meta_fields(keyspace_meta.fields_iter(), indent + 1); 218 | println!(""); 219 | 220 | 221 | for mut table_meta in keyspace_meta.table_iter() { 222 | print_table_meta(&mut table_meta, indent + 1); 223 | } 224 | println!(""); 225 | } 226 | -------------------------------------------------------------------------------- /src/examples/simple.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use std::str::FromStr; 5 | 6 | 7 | fn main() { 8 | let query = stmt!("SELECT keyspace_name FROM system_schema.keyspaces;"); 9 | let col_name = "keyspace_name"; 10 | 11 | let contact_points = ContactPoints::from_str("127.0.0.1").unwrap(); 12 | 13 | let mut cluster = Cluster::default(); 14 | cluster.set_contact_points(contact_points).unwrap(); 15 | cluster.set_load_balance_round_robin(); 16 | 17 | match cluster.connect() { 18 | Ok(ref mut session) => { 19 | let result = session.execute(&query).wait().unwrap(); 20 | println!("{}", result); 21 | for row in result.iter() { 22 | let col: String = row.get_col_by_name(col_name).unwrap(); 23 | println!("ks name = {}", col); 24 | } 25 | } 26 | err => println!("{:?}", err), 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/examples/ssl.rs: -------------------------------------------------------------------------------- 1 | pub fn main() { 2 | panic!("not implemented yet"); 3 | } 4 | -------------------------------------------------------------------------------- /src/examples/udt.rs: -------------------------------------------------------------------------------- 1 | extern crate cassandra; 2 | 3 | use cassandra::*; 4 | 5 | fn main() { 6 | 7 | let mut cluster = Cluster::new(); 8 | cluster.set_contact_points("127.0.0.1").unwrap(); 9 | 10 | match cluster.connect() { 11 | Ok(ref mut session) => { 12 | let schema = session.get_schema(); 13 | session.execute( 14 | "CREATE KEYSPACE examples WITH replication = \ 15 | { 'class': 'SimpleStrategy', 'replication_factor': '3' }", 16 | 0 17 | ); 18 | 19 | session.execute( 20 | "CREATE TYPE examples.phone_numbers (phone1 int, phone2 int)", 21 | 0 22 | ); 23 | 24 | session.execute( 25 | "CREATE TYPE examples.address \ 26 | (street text, city text, zip int, phone set>)" 27 | ,0 28 | ); 29 | 30 | session.execute( 31 | "CREATE TABLE examples.udt (id timeuuid, address frozen
, PRIMARY KEY(id))", 32 | 0 33 | ); 34 | 35 | insert_into_udt(&session, schema).unwrap(); 36 | select_from_udt(&session).unwrap(); 37 | session.close().wait().unwrap(); 38 | } 39 | err => println!("{:?}", err), 40 | } 41 | } 42 | 43 | fn select_from_udt(session: &Session) -> Result<(), CassandraError> { 44 | let query = "SELECT * FROM examples.udt"; 45 | let statement = Statement::new(query, 0); 46 | let mut future = session.execute_statement(&statement); 47 | match future.wait() { 48 | Err(err) => panic!("Error: {:?}", err), 49 | Ok(result) => { 50 | for row in result.iter() { 51 | let id_value = row.get_column_by_name("id"); 52 | let address_value = row.get_column_by_name("address"); 53 | let fields_iter = try!(address_value.use_type_iter()); 54 | let id_str = try!(id_value.get_uuid()).to_string(); 55 | println!("id {}", id_str); 56 | for field in fields_iter { 57 | println!("{}", field.0); 58 | match field.1.get_type() { 59 | ValueType::VARCHAR => println!("{}", try!(field.1.get_string())), 60 | ValueType::INT => println!("{}", try!(field.1.get_int32())), 61 | ValueType::SET => 62 | for phone_numbers in try!(field.1.as_set_iterator()) { 63 | for phone_number in try!(phone_numbers.as_user_type_iterator()) { 64 | let phone_number_value = phone_number.1; 65 | println!("{}", phone_number_value); 66 | } 67 | }, 68 | other => panic!("Unsupported type: {:?}", other), 69 | } 70 | } 71 | } 72 | Ok(()) 73 | 74 | } 75 | } 76 | } 77 | 78 | fn insert_into_udt(session: &Session) -> Result<(), CassandraError> { 79 | let query = "INSERT INTO examples.udt (id, address) VALUES (?, ?)"; 80 | let mut statement = Statement::new(query, 2); 81 | let uuid_gen = UuidGen::new(); 82 | let udt_address = schema.get_udt("examples", "address"); 83 | let udt_phone = cass_keyspace_meta_user_type_by_name(&schema, "examples", "phone_numbers"); 84 | let id = uuid_gen.get_time(); 85 | let id_str = id.to_string(); 86 | let mut address = UserType::new(udt_address); 87 | let mut phone = Set::new(2); 88 | let mut phone_numbers = UserType::new(udt_phone); 89 | phone_numbers.set_int32_by_name("phone1", 0 + 1).unwrap(); 90 | phone_numbers.set_int32_by_name("phone2", 0 + 2).unwrap(); 91 | phone.append_user_type(phone_numbers).unwrap(); 92 | address.set_string_by_name("street", &id_str).unwrap(); 93 | address.set_int32_by_name("zip", id.0.time_and_version as i32).unwrap(); 94 | address.set_collection_by_name("phone", phone).unwrap(); 95 | 96 | statement.bind(0, id).unwrap(); 97 | statement.bind_user_type(1, address).unwrap(); 98 | let mut future = session.execute_statement(&statement); 99 | match future.wait() { 100 | Ok(_) => Ok(()), 101 | Err(err) => panic!("Error: {:?}", err), 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/examples/uuids.rs: -------------------------------------------------------------------------------- 1 | #[macro_use(stmt)] 2 | extern crate cassandra; 3 | use cassandra::*; 4 | use errors::*; 5 | 6 | use std::str::FromStr; 7 | 8 | static INSERT_QUERY: &'static str = "INSERT INTO examples.log (key, time, entry) VALUES (?, ?, ?);"; 9 | static SELECT_QUERY: &'static str = "SELECT * FROM examples.log WHERE key = ?"; 10 | static CREATE_KEYSPACE: &'static str = "CREATE KEYSPACE IF NOT EXISTS examples WITH replication = { \'class\': \ 11 | \'SimpleStrategy\', \'replication_factor\': \'3\' };"; 12 | static CREATE_TABLE: &'static str = "CREATE TABLE IF NOT EXISTS examples.log (key text, time timeuuid, entry text, \ 13 | PRIMARY KEY (key, time));"; 14 | 15 | fn insert_into_log(session: &mut Session, key: &str, time: Uuid, entry: &str) -> Result { 16 | let mut statement = stmt!(INSERT_QUERY); 17 | statement.bind(0, key)?; 18 | statement.bind(1, time)?; 19 | statement.bind(2, entry)?; 20 | let mut future = session.execute(&statement); 21 | future.wait() 22 | } 23 | 24 | fn select_from_log(session: &mut Session, key: &str) -> Result { 25 | let mut statement = stmt!(SELECT_QUERY); 26 | statement.bind(0, key)?; 27 | let mut future = session.execute(&statement); 28 | let results = future.wait()?; 29 | Ok(results) 30 | } 31 | 32 | fn main() { 33 | let uuid_gen = UuidGen::default(); 34 | let mut cluster = Cluster::default(); 35 | cluster.set_contact_points(ContactPoints::from_str("127.0.0.1").unwrap()).unwrap(); 36 | match cluster.connect() { 37 | Ok(ref mut session) => { 38 | session.execute(&stmt!(CREATE_KEYSPACE)).wait().unwrap(); 39 | session.execute(&stmt!(CREATE_TABLE)).wait().unwrap(); 40 | println!("uuid_gen = {}", uuid_gen.gen_time()); 41 | insert_into_log(session, "test", uuid_gen.gen_time(), "Log entry #1").unwrap(); 42 | insert_into_log(session, "test", uuid_gen.gen_time(), "Log entry #2").unwrap(); 43 | insert_into_log(session, "test", uuid_gen.gen_time(), "Log entry #3").unwrap(); 44 | insert_into_log(session, "test", uuid_gen.gen_time(), "Log entry #4").unwrap(); 45 | let results = select_from_log(session, "test").unwrap(); 46 | println!("{}", results); 47 | } 48 | err => println!("{:?}", err), 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This is a wrapper around the DataStax C++ driver for Cassandra. It aims to be 100% safe with minimal overhead added 2 | #![deny(missing_docs)] 3 | #![allow(unknown_lints)] 4 | #![allow(doc_markdown)] 5 | // `error_chain!` can recurse deeply 6 | #![recursion_limit = "1024"] 7 | 8 | extern crate libc; 9 | #[macro_use] 10 | extern crate log; 11 | extern crate decimal; 12 | extern crate chrono; 13 | extern crate time; 14 | extern crate ip; 15 | extern crate uuid; 16 | 17 | 18 | pub use cassandra::batch::{Batch, BatchType, CustomPayload}; 19 | pub use cassandra::cluster::{Cluster, ContactPoints, CqlProtocol}; //FIXME this should not be exported 20 | pub use cassandra::collection::{CassCollection, List, Map, Set}; 21 | pub use cassandra::column::Column; 22 | pub use cassandra::consistency::Consistency; 23 | pub use cassandra::data_type::DataType; 24 | // pub use cassandra::write_type::*; 25 | pub use cassandra::field::Field; 26 | pub use cassandra::future::{CloseFuture, Future, FutureCallback, PreparedFuture, ResultFuture, SessionFuture}; 27 | pub use cassandra::inet::Inet; 28 | // pub use cassandra::util::*; 29 | // pub use cassandra::metrics::*; 30 | pub use cassandra::iterator::{AggregateIterator, ColumnIterator, FieldIterator, FunctionIterator, KeyspaceIterator, 31 | MapIterator, SetIterator, TableIterator, UserTypeIterator}; 32 | pub use cassandra::log::{LogLevel, set_callback, set_level}; 33 | pub use cassandra::policy::retry::RetryPolicy; 34 | pub use cassandra::prepared::PreparedStatement; 35 | pub use cassandra::result::CassResult; 36 | pub use cassandra::row::AsRustType; 37 | pub use cassandra::row::Row; 38 | pub use cassandra::schema::aggregate_meta::AggregateMeta; 39 | pub use cassandra::schema::column_meta::ColumnMeta; 40 | pub use cassandra::schema::function_meta::FunctionMeta; 41 | pub use cassandra::schema::keyspace_meta::KeyspaceMeta; 42 | pub use cassandra::schema::schema_meta::SchemaMeta; 43 | pub use cassandra::schema::table_meta::TableMeta; 44 | pub use cassandra::session::Session; 45 | pub use cassandra::ssl::Ssl; 46 | pub use cassandra::statement::BindRustType; 47 | pub use cassandra::statement::Statement; 48 | // pub use cassandra::custom_payload::CustomPayload; 49 | pub use cassandra::time::TimestampGen; 50 | pub use cassandra::tuple::Tuple; 51 | pub use cassandra::user_type::UserType; 52 | pub use cassandra::uuid::{Uuid, UuidGen}; 53 | pub use cassandra::value::{Value, ValueType}; 54 | // pub use cassandra::inet::{Inet}; 55 | pub use cassandra_sys::CASS_BATCH_TYPE_LOGGED; 56 | pub use cassandra_sys::CassBatchType; 57 | 58 | extern crate cassandra_sys; 59 | 60 | 61 | // Import the macro. Don't forget to add `error-chain` in your 62 | // `Cargo.toml`! 63 | #[macro_use] 64 | extern crate error_chain; 65 | 66 | 67 | pub use cassandra::error::*; 68 | 69 | /// A still clumsy use of error-chain. needs work 70 | pub mod errors { 71 | error_chain!{} 72 | } 73 | 74 | // #[macro_use] 75 | mod cassandra { 76 | pub mod consistency; 77 | pub mod field; 78 | pub mod inet; 79 | pub mod uuid; 80 | pub mod cluster; 81 | pub mod session; 82 | pub mod statement; 83 | pub mod batch; 84 | pub mod future; 85 | pub mod prepared; 86 | pub mod result; 87 | pub mod iterator; 88 | pub mod row; 89 | pub mod value; 90 | pub mod collection; 91 | pub mod ssl; 92 | pub mod schema; 93 | pub mod log; 94 | pub mod error; 95 | pub mod helpers; 96 | pub mod column; 97 | pub mod user_type; 98 | pub mod data_type; 99 | pub mod tuple; 100 | pub mod policy; 101 | pub mod custom_payload; 102 | pub mod time; 103 | pub mod util; 104 | pub mod metrics; 105 | pub mod write_type; 106 | } 107 | 108 | 109 | // #[phase(plugin)] extern crate bindgen; 110 | // #[allow(dead_code, uppercase_variables, non_camel_case_types)] 111 | // mod mysql_bindings { 112 | // bindgen!("/usr/include/mysql/mysql.h", match="mysql.h", link="mysql"); 113 | // } 114 | --------------------------------------------------------------------------------