1 /*
2   This is free and unencumbered software released into the public domain.
3 
4   Anyone is free to copy, modify, publish, use, compile, sell, or
5   distribute this software, either in source code form or as a compiled
6   binary, for any purpose, commercial or non-commercial, and by any
7   means.
8 
9   In jurisdictions that recognize copyright laws, the author or authors
10   of this software dedicate any and all copyright interest in the
11   software to the public domain. We make this dedication for the benefit
12   of the public at large and to the detriment of our heirs and
13   successors. We intend this dedication to be an overt act of
14   relinquishment in perpetuity of all present and future rights to this
15   software under copyright law.
16 
17   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23   OTHER DEALINGS IN THE SOFTWARE.
24 
25   For more information, please refer to <http://unlicense.org/>
26 */
27 
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include "cassandra.h"
34 
35 CassUuidGen* uuid_gen;
36 const CassSchemaMeta* schema_meta;
37 
print_error(CassFuture * future)38 void print_error(CassFuture* future) {
39   const char* message;
40   size_t message_length;
41   cass_future_error_message(future, &message, &message_length);
42   fprintf(stderr, "Error: %.*s\n", (int)message_length, message);
43 }
44 
create_cluster(const char * hosts)45 CassCluster* create_cluster(const char* hosts) {
46   CassCluster* cluster = cass_cluster_new();
47   cass_cluster_set_contact_points(cluster, hosts);
48   return cluster;
49 }
50 
connect_session(CassSession * session,const CassCluster * cluster)51 CassError connect_session(CassSession* session, const CassCluster* cluster) {
52   CassError rc = CASS_OK;
53   CassFuture* future = cass_session_connect(session, cluster);
54 
55   cass_future_wait(future);
56   rc = cass_future_error_code(future);
57   if (rc != CASS_OK) {
58     print_error(future);
59   }
60   cass_future_free(future);
61 
62   return rc;
63 }
64 
execute_query(CassSession * session,const char * query)65 CassError execute_query(CassSession* session, const char* query) {
66   CassError rc = CASS_OK;
67   CassFuture* future = NULL;
68   CassStatement* statement = cass_statement_new(query, 0);
69 
70   future = cass_session_execute(session, statement);
71   cass_future_wait(future);
72 
73   rc = cass_future_error_code(future);
74   if (rc != CASS_OK) {
75     print_error(future);
76   }
77 
78   cass_future_free(future);
79   cass_statement_free(statement);
80 
81   return rc;
82 }
83 
insert_into_udt(CassSession * session)84 CassError insert_into_udt(CassSession* session) {
85   CassError rc = CASS_OK;
86   CassStatement* statement = NULL;
87   CassFuture* future = NULL;
88 
89   CassUuid id;
90   char id_str[CASS_UUID_STRING_LENGTH];
91   const CassKeyspaceMeta* keyspace_meta = NULL;
92   const CassDataType* udt_address = NULL;
93   const CassDataType* udt_phone = NULL;
94 
95   const char* query = "INSERT INTO examples.udt (id, address) VALUES (?, ?)";
96 
97   statement = cass_statement_new(query, 2);
98 
99   cass_uuid_gen_time(uuid_gen, &id);
100   cass_uuid_string(id, id_str);
101 
102   keyspace_meta = cass_schema_meta_keyspace_by_name(schema_meta, "examples");
103   if (keyspace_meta != NULL) {
104     udt_address = cass_keyspace_meta_user_type_by_name(keyspace_meta, "address");
105     udt_phone = cass_keyspace_meta_user_type_by_name(keyspace_meta, "phone_numbers");
106   }
107 
108   if (udt_address != NULL && udt_phone != NULL) {
109     int i;
110     CassUserType* address = cass_user_type_new_from_data_type(udt_address);
111     CassCollection* phone = cass_collection_new(CASS_COLLECTION_TYPE_SET, 2);
112 
113     for (i = 0; i < 2; ++i) {
114       CassUserType* phone_numbers = cass_user_type_new_from_data_type(udt_phone);
115       cass_user_type_set_int32_by_name(phone_numbers, "phone1", i + 1);
116       cass_user_type_set_int32_by_name(phone_numbers, "phone2", i + 2);
117       cass_collection_append_user_type(phone, phone_numbers);
118       cass_user_type_free(phone_numbers);
119     }
120 
121     cass_user_type_set_string_by_name(address, "street", id_str);
122     cass_user_type_set_string_by_name(address, "city", id_str);
123     cass_user_type_set_int32_by_name(address, "zip", (cass_int32_t)id.time_and_version);
124     cass_user_type_set_collection_by_name(address, "phone", phone);
125 
126     cass_statement_bind_uuid(statement, 0, id);
127     cass_statement_bind_user_type(statement, 1, address);
128 
129     future = cass_session_execute(session, statement);
130     cass_future_wait(future);
131 
132     rc = cass_future_error_code(future);
133     if (rc != CASS_OK) {
134       print_error(future);
135     }
136 
137     cass_future_free(future);
138     cass_user_type_free(address);
139     cass_collection_free(phone);
140   }
141 
142   cass_statement_free(statement);
143 
144   return rc;
145 }
146 
select_from_udt(CassSession * session)147 CassError select_from_udt(CassSession* session) {
148   CassError rc = CASS_OK;
149   CassStatement* statement = NULL;
150   CassFuture* future = NULL;
151 
152   const char* query = "SELECT * FROM examples.udt";
153 
154   statement = cass_statement_new(query, 0);
155 
156   future = cass_session_execute(session, statement);
157   cass_future_wait(future);
158 
159   rc = cass_future_error_code(future);
160   if (rc != CASS_OK) {
161     print_error(future);
162   } else {
163     const CassResult* result = NULL;
164     CassIterator* rows = NULL;
165 
166     result = cass_future_get_result(future);
167     rows = cass_iterator_from_result(result);
168 
169     while (cass_iterator_next(rows)) {
170       CassUuid id;
171       char id_str[CASS_UUID_STRING_LENGTH];
172       const CassRow* row = cass_iterator_get_row(rows);
173       const CassValue* id_value = cass_row_get_column_by_name(row, "id");
174       const CassValue* address_value = cass_row_get_column_by_name(row, "address");
175       CassIterator* fields = cass_iterator_fields_from_user_type(address_value);
176 
177       cass_value_get_uuid(id_value, &id);
178       cass_uuid_string(id, id_str);
179 
180       printf("id %s ", id_str);
181 
182       while (fields != NULL && cass_iterator_next(fields)) {
183         const char* field_name;
184         size_t field_name_length;
185         const CassValue* field_value = NULL;
186         cass_iterator_get_user_type_field_name(fields, &field_name, &field_name_length);
187         field_value = cass_iterator_get_user_type_field_value(fields);
188         printf("%.*s ", (int)field_name_length, field_name);
189 
190         if (!cass_value_is_null(field_value)) {
191           if (cass_value_type(field_value) == CASS_VALUE_TYPE_VARCHAR) {
192             const char* text;
193             size_t text_length;
194             cass_value_get_string(field_value, &text, &text_length);
195             printf("\"%.*s\" ", (int)text_length, text);
196           } else if (cass_value_type(field_value) == CASS_VALUE_TYPE_INT) {
197             cass_int32_t i;
198             cass_value_get_int32(field_value, &i);
199             printf("%d ", i);
200           } else if (cass_value_type(field_value) == CASS_VALUE_TYPE_SET) {
201             CassIterator* phone_numbers = cass_iterator_from_collection(field_value);
202             while (cass_iterator_next(phone_numbers)) {
203               const CassValue* phone_value = cass_iterator_get_value(phone_numbers);
204               CassIterator* phone_fields = cass_iterator_fields_from_user_type(phone_value);
205               assert(cass_value_type(phone_value) == CASS_VALUE_TYPE_UDT);
206               while (cass_iterator_next(phone_fields)) {
207                 const CassValue* phone_number_value =
208                     cass_iterator_get_user_type_field_value(phone_fields);
209                 cass_int32_t i;
210                 cass_value_get_int32(phone_number_value, &i);
211                 printf("%d ", i);
212               }
213             }
214           } else {
215             printf("<invalid> ");
216           }
217         } else {
218           printf("<null> ");
219         }
220       }
221 
222       printf("\n");
223     }
224 
225     cass_result_free(result);
226     cass_iterator_free(rows);
227   }
228 
229   cass_future_free(future);
230   cass_statement_free(statement);
231 
232   return rc;
233 }
234 
main(int argc,char * argv[])235 int main(int argc, char* argv[]) {
236   CassCluster* cluster = NULL;
237   CassSession* session = cass_session_new();
238   char* hosts = "127.0.0.1";
239   if (argc > 1) {
240     hosts = argv[1];
241   }
242   cluster = create_cluster(hosts);
243 
244   uuid_gen = cass_uuid_gen_new();
245 
246   if (connect_session(session, cluster) != CASS_OK) {
247     cass_cluster_free(cluster);
248     cass_session_free(session);
249     return -1;
250   }
251 
252   execute_query(session, "CREATE KEYSPACE examples WITH replication = { \
253                            'class': 'SimpleStrategy', 'replication_factor': '3' }");
254 
255   execute_query(session, "CREATE TYPE examples.phone_numbers (phone1 int, phone2 int)");
256 
257   execute_query(session, "CREATE TYPE examples.address (street text, city text, zip int, phone "
258                          "set<frozen<phone_numbers>>)");
259 
260   execute_query(
261       session, "CREATE TABLE examples.udt (id timeuuid, address frozen<address>, PRIMARY KEY(id))");
262 
263   schema_meta = cass_session_get_schema_meta(session);
264 
265   insert_into_udt(session);
266   select_from_udt(session);
267 
268   cass_cluster_free(cluster);
269   cass_session_free(session);
270 
271   cass_uuid_gen_free(uuid_gen);
272   cass_schema_meta_free(schema_meta);
273 
274   return 0;
275 }
276