1 /*
2   Copyright (c) DataStax, Inc.
3 
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7 
8   http://www.apache.org/licenses/LICENSE-2.0
9 
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15 */
16 
17 #include "data_type.hpp"
18 
19 #include "collection.hpp"
20 #include "external.hpp"
21 #include "tuple.hpp"
22 #include "types.hpp"
23 #include "user_type_value.hpp"
24 #include "utils.hpp"
25 
26 #include <string.h>
27 
28 using namespace datastax;
29 using namespace datastax::internal::core;
30 
31 extern "C" {
32 
cass_data_type_new(CassValueType type)33 CassDataType* cass_data_type_new(CassValueType type) {
34   DataType* data_type = NULL;
35   switch (type) {
36     case CASS_VALUE_TYPE_LIST:
37     case CASS_VALUE_TYPE_SET:
38     case CASS_VALUE_TYPE_TUPLE:
39     case CASS_VALUE_TYPE_MAP:
40       data_type = new CollectionType(type, false);
41       data_type->inc_ref();
42       break;
43 
44     case CASS_VALUE_TYPE_UDT:
45       data_type = new UserType(false);
46       data_type->inc_ref();
47       break;
48 
49     case CASS_VALUE_TYPE_CUSTOM:
50       data_type = new CustomType();
51       data_type->inc_ref();
52       break;
53 
54     case CASS_VALUE_TYPE_UNKNOWN:
55       // Invalid
56       break;
57 
58     default:
59       if (type < CASS_VALUE_TYPE_LAST_ENTRY) {
60         data_type = new DataType(type);
61         data_type->inc_ref();
62       }
63       break;
64   }
65   return CassDataType::to(data_type);
66 }
67 
cass_data_type_new_from_existing(const CassDataType * data_type)68 CassDataType* cass_data_type_new_from_existing(const CassDataType* data_type) {
69   DataType::Ptr copy = data_type->copy();
70   copy->inc_ref();
71   return CassDataType::to(copy.get());
72 }
73 
cass_data_type_new_tuple(size_t item_count)74 CassDataType* cass_data_type_new_tuple(size_t item_count) {
75   DataType* data_type = new CollectionType(CASS_VALUE_TYPE_TUPLE, item_count, false);
76   data_type->inc_ref();
77   return CassDataType::to(data_type);
78 }
79 
cass_data_type_new_udt(size_t field_count)80 CassDataType* cass_data_type_new_udt(size_t field_count) {
81   DataType* data_type = new UserType(field_count, false);
82   data_type->inc_ref();
83   return CassDataType::to(data_type);
84 }
85 
cass_data_type_sub_data_type(const CassDataType * data_type,size_t index)86 const CassDataType* cass_data_type_sub_data_type(const CassDataType* data_type, size_t index) {
87   const DataType* sub_type = NULL;
88   if (data_type->is_collection() || data_type->is_tuple()) {
89     const CompositeType* composite_type = static_cast<const CompositeType*>(data_type->from());
90     if (index < composite_type->types().size()) {
91       sub_type = composite_type->types()[index].get();
92     }
93   } else if (data_type->is_user_type()) {
94     const UserType* user_type = static_cast<const UserType*>(data_type->from());
95     if (index < user_type->fields().size()) {
96       sub_type = user_type->fields()[index].type.get();
97     }
98   }
99   return CassDataType::to(sub_type);
100 }
101 
cass_data_type_sub_data_type_by_name(const CassDataType * data_type,const char * name)102 const CassDataType* cass_data_type_sub_data_type_by_name(const CassDataType* data_type,
103                                                          const char* name) {
104   return cass_data_type_sub_data_type_by_name_n(data_type, name, SAFE_STRLEN(name));
105 }
106 
cass_data_type_sub_data_type_by_name_n(const CassDataType * data_type,const char * name,size_t name_length)107 const CassDataType* cass_data_type_sub_data_type_by_name_n(const CassDataType* data_type,
108                                                            const char* name, size_t name_length) {
109   if (!data_type->is_user_type()) {
110     return NULL;
111   }
112 
113   const UserType* user_type = static_cast<const UserType*>(data_type->from());
114 
115   IndexVec indices;
116   if (user_type->get_indices(StringRef(name, name_length), &indices) == 0) {
117     return NULL;
118   }
119 
120   return CassDataType::to(user_type->fields()[indices.front()].type.get());
121 }
122 
cass_data_type_type(const CassDataType * data_type)123 CassValueType cass_data_type_type(const CassDataType* data_type) { return data_type->value_type(); }
124 
cass_data_type_is_frozen(const CassDataType * data_type)125 cass_bool_t cass_data_type_is_frozen(const CassDataType* data_type) {
126   return data_type->is_frozen() ? cass_true : cass_false;
127 }
128 
cass_data_type_type_name(const CassDataType * data_type,const char ** name,size_t * name_length)129 CassError cass_data_type_type_name(const CassDataType* data_type, const char** name,
130                                    size_t* name_length) {
131   if (!data_type->is_user_type()) {
132     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
133   }
134 
135   const UserType* user_type = static_cast<const UserType*>(data_type->from());
136 
137   *name = user_type->type_name().data();
138   *name_length = user_type->type_name().size();
139 
140   return CASS_OK;
141 }
142 
cass_data_type_set_type_name(CassDataType * data_type,const char * type_name)143 CassError cass_data_type_set_type_name(CassDataType* data_type, const char* type_name) {
144   return cass_data_type_set_type_name_n(data_type, type_name, SAFE_STRLEN(type_name));
145 }
146 
cass_data_type_set_type_name_n(CassDataType * data_type,const char * type_name,size_t type_name_length)147 CassError cass_data_type_set_type_name_n(CassDataType* data_type, const char* type_name,
148                                          size_t type_name_length) {
149   if (!data_type->is_user_type()) {
150     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
151   }
152 
153   UserType* user_type = static_cast<UserType*>(data_type->from());
154 
155   user_type->set_type_name(String(type_name, type_name_length));
156 
157   return CASS_OK;
158 }
159 
cass_data_type_keyspace(const CassDataType * data_type,const char ** keyspace,size_t * keyspace_length)160 CassError cass_data_type_keyspace(const CassDataType* data_type, const char** keyspace,
161                                   size_t* keyspace_length) {
162   if (!data_type->is_user_type()) {
163     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
164   }
165 
166   const UserType* user_type = static_cast<const UserType*>(data_type->from());
167 
168   *keyspace = user_type->keyspace().data();
169   *keyspace_length = user_type->keyspace().size();
170 
171   return CASS_OK;
172 }
173 
cass_data_type_set_keyspace(CassDataType * data_type,const char * keyspace)174 CassError cass_data_type_set_keyspace(CassDataType* data_type, const char* keyspace) {
175   return cass_data_type_set_keyspace_n(data_type, keyspace, SAFE_STRLEN(keyspace));
176 }
177 
cass_data_type_set_keyspace_n(CassDataType * data_type,const char * keyspace,size_t keyspace_length)178 CassError cass_data_type_set_keyspace_n(CassDataType* data_type, const char* keyspace,
179                                         size_t keyspace_length) {
180   if (!data_type->is_user_type()) {
181     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
182   }
183 
184   UserType* user_type = static_cast<UserType*>(data_type->from());
185 
186   user_type->set_keyspace(String(keyspace, keyspace_length));
187 
188   return CASS_OK;
189 }
190 
cass_data_type_class_name(const CassDataType * data_type,const char ** class_name,size_t * class_name_length)191 CassError cass_data_type_class_name(const CassDataType* data_type, const char** class_name,
192                                     size_t* class_name_length) {
193   if (!data_type->is_custom()) {
194     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
195   }
196 
197   const CustomType* custom_type = static_cast<const CustomType*>(data_type->from());
198 
199   *class_name = custom_type->class_name().data();
200   *class_name_length = custom_type->class_name().size();
201 
202   return CASS_OK;
203 }
204 
cass_data_type_set_class_name(CassDataType * data_type,const char * class_name)205 CassError cass_data_type_set_class_name(CassDataType* data_type, const char* class_name) {
206   return cass_data_type_set_class_name_n(data_type, class_name, SAFE_STRLEN(class_name));
207 }
208 
cass_data_type_set_class_name_n(CassDataType * data_type,const char * class_name,size_t class_name_length)209 CassError cass_data_type_set_class_name_n(CassDataType* data_type, const char* class_name,
210                                           size_t class_name_length) {
211   if (!data_type->is_custom()) {
212     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
213   }
214 
215   CustomType* custom_type = static_cast<CustomType*>(data_type->from());
216 
217   custom_type->set_class_name(String(class_name, class_name_length));
218 
219   return CASS_OK;
220 }
221 
cass_data_sub_type_count(const CassDataType * data_type)222 size_t cass_data_sub_type_count(const CassDataType* data_type) {
223   return cass_data_type_sub_type_count(data_type);
224 }
225 
cass_data_type_sub_type_count(const CassDataType * data_type)226 size_t cass_data_type_sub_type_count(const CassDataType* data_type) {
227   if (data_type->is_collection() || data_type->is_tuple()) {
228     const CompositeType* composite_type = static_cast<const CompositeType*>(data_type->from());
229     return composite_type->types().size();
230   } else if (data_type->is_user_type()) {
231     const UserType* user_type = static_cast<const UserType*>(data_type->from());
232     return user_type->fields().size();
233   }
234   return 0;
235 }
236 
cass_data_type_sub_type_name(const CassDataType * data_type,size_t index,const char ** name,size_t * name_length)237 CassError cass_data_type_sub_type_name(const CassDataType* data_type, size_t index,
238                                        const char** name, size_t* name_length) {
239   if (!data_type->is_user_type()) {
240     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
241   }
242 
243   const UserType* user_type = static_cast<const UserType*>(data_type->from());
244 
245   if (index >= user_type->fields().size()) {
246     return CASS_ERROR_LIB_INDEX_OUT_OF_BOUNDS;
247   }
248 
249   StringRef field_name = user_type->fields()[index].name;
250 
251   *name = field_name.data();
252   *name_length = field_name.size();
253 
254   return CASS_OK;
255 }
256 
cass_data_type_add_sub_type(CassDataType * data_type,const CassDataType * sub_data_type)257 CassError cass_data_type_add_sub_type(CassDataType* data_type, const CassDataType* sub_data_type) {
258   if (!data_type->is_collection() && !data_type->is_tuple()) {
259     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
260   }
261 
262   CompositeType* composite_type = static_cast<CompositeType*>(data_type->from());
263 
264   switch (composite_type->value_type()) {
265     case CASS_VALUE_TYPE_LIST:
266     case CASS_VALUE_TYPE_SET:
267       if (composite_type->types().size() >= 1) {
268         return CASS_ERROR_LIB_BAD_PARAMS;
269       }
270       composite_type->types().push_back(DataType::ConstPtr(sub_data_type));
271       break;
272 
273     case CASS_VALUE_TYPE_MAP:
274       if (composite_type->types().size() >= 2) {
275         return CASS_ERROR_LIB_BAD_PARAMS;
276       }
277       composite_type->types().push_back(DataType::ConstPtr(sub_data_type));
278       break;
279 
280     case CASS_VALUE_TYPE_TUPLE:
281       composite_type->types().push_back(DataType::ConstPtr(sub_data_type));
282       break;
283 
284     default:
285       assert(false);
286       break;
287   }
288 
289   return CASS_OK;
290 }
291 
cass_data_type_add_sub_type_by_name(CassDataType * data_type,const char * name,const CassDataType * sub_data_type)292 CassError cass_data_type_add_sub_type_by_name(CassDataType* data_type, const char* name,
293                                               const CassDataType* sub_data_type) {
294   return cass_data_type_add_sub_type_by_name_n(data_type, name, SAFE_STRLEN(name), sub_data_type);
295 }
296 
cass_data_type_add_sub_type_by_name_n(CassDataType * data_type,const char * name,size_t name_length,const CassDataType * sub_data_type)297 CassError cass_data_type_add_sub_type_by_name_n(CassDataType* data_type, const char* name,
298                                                 size_t name_length,
299                                                 const CassDataType* sub_data_type) {
300   if (!data_type->is_user_type()) {
301     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
302   }
303 
304   UserType* user_type = static_cast<UserType*>(data_type->from());
305 
306   user_type->add_field(String(name, name_length), DataType::ConstPtr(sub_data_type));
307 
308   return CASS_OK;
309 }
310 
cass_data_type_add_sub_value_type(CassDataType * data_type,CassValueType sub_value_type)311 CassError cass_data_type_add_sub_value_type(CassDataType* data_type, CassValueType sub_value_type) {
312   DataType::ConstPtr sub_data_type(new DataType(sub_value_type));
313   return cass_data_type_add_sub_type(data_type, CassDataType::to(sub_data_type.get()));
314 }
315 
cass_data_type_add_sub_value_type_by_name(CassDataType * data_type,const char * name,CassValueType sub_value_type)316 CassError cass_data_type_add_sub_value_type_by_name(CassDataType* data_type, const char* name,
317                                                     CassValueType sub_value_type) {
318   DataType::ConstPtr sub_data_type(new DataType(sub_value_type));
319   return cass_data_type_add_sub_type_by_name(data_type, name,
320                                              CassDataType::to(sub_data_type.get()));
321 }
322 
cass_data_type_add_sub_value_type_by_name_n(CassDataType * data_type,const char * name,size_t name_length,CassValueType sub_value_type)323 CassError cass_data_type_add_sub_value_type_by_name_n(CassDataType* data_type, const char* name,
324                                                       size_t name_length,
325                                                       CassValueType sub_value_type) {
326   DataType::ConstPtr sub_data_type(new DataType(sub_value_type));
327   return cass_data_type_add_sub_type_by_name_n(data_type, name, name_length,
328                                                CassDataType::to(sub_data_type.get()));
329 }
330 
cass_data_type_free(CassDataType * data_type)331 void cass_data_type_free(CassDataType* data_type) { data_type->dec_ref(); }
332 
333 } // extern "C"
334 
335 const DataType::ConstPtr DataType::NIL;
336 
create_by_class(StringRef name)337 DataType::ConstPtr DataType::create_by_class(StringRef name) {
338   CassValueType value_type = ValueTypes::by_class(name);
339   if (value_type == CASS_VALUE_TYPE_UNKNOWN) {
340     return DataType::NIL;
341   }
342   return ConstPtr(new DataType(value_type));
343 }
344 
create_by_cql(StringRef name)345 DataType::ConstPtr DataType::create_by_cql(StringRef name) {
346   CassValueType value_type = ValueTypes::by_cql(name);
347   if (value_type == CASS_VALUE_TYPE_UNKNOWN) {
348     return DataType::NIL;
349   }
350   return ConstPtr(new DataType(value_type));
351 }
352 
353 ValueTypes::HashMap ValueTypes::value_types_by_class_;
354 ValueTypes::HashMap ValueTypes::value_types_by_cql_;
355 
356 static ValueTypes __value_types__; // Initializer
357 
ValueTypes()358 ValueTypes::ValueTypes() {
359   value_types_by_class_.set_empty_key("");
360   value_types_by_cql_.set_empty_key("");
361 
362 #define XX_VALUE_TYPE(name, type, cql, klass)                     \
363   if (sizeof(klass) - 1 > 0) value_types_by_class_[klass] = name; \
364   if (sizeof(cql) - 1 > 0) value_types_by_cql_[cql] = name;
365 
366   CASS_VALUE_TYPE_MAPPING(XX_VALUE_TYPE)
367 #undef XX_VALUE_TYPE
368 }
369 
by_class(StringRef name)370 CassValueType ValueTypes::by_class(StringRef name) {
371   HashMap::const_iterator i = value_types_by_class_.find(name);
372   if (i == value_types_by_class_.end()) {
373     return CASS_VALUE_TYPE_UNKNOWN;
374   }
375   return i->second;
376 }
377 
by_cql(StringRef name)378 CassValueType ValueTypes::by_cql(StringRef name) {
379   HashMap::const_iterator i = value_types_by_cql_.find(name);
380   if (i == value_types_by_cql_.end()) {
381     return CASS_VALUE_TYPE_UNKNOWN;
382   }
383   return i->second;
384 }
385 
by_value_type(uint16_t value_type)386 const DataType::ConstPtr& SimpleDataTypeCache::by_value_type(uint16_t value_type) {
387   if (value_type == CASS_VALUE_TYPE_UNKNOWN || value_type == CASS_VALUE_TYPE_CUSTOM ||
388       value_type == CASS_VALUE_TYPE_LIST || value_type == CASS_VALUE_TYPE_MAP ||
389       value_type == CASS_VALUE_TYPE_SET || value_type == CASS_VALUE_TYPE_UDT ||
390       value_type == CASS_VALUE_TYPE_TUPLE || value_type >= CASS_VALUE_TYPE_LAST_ENTRY) {
391     return DataType::NIL;
392   }
393   DataType::ConstPtr& data_type = cache_[value_type];
394   if (!data_type) {
395     data_type = DataType::ConstPtr(new DataType(static_cast<CassValueType>(value_type)));
396   }
397   return data_type;
398 }
399 
operator ()(const Collection * value,const DataType::ConstPtr & data_type) const400 bool IsValidDataType<const Collection*>::operator()(const Collection* value,
401                                                     const DataType::ConstPtr& data_type) const {
402   return value->data_type()->equals(data_type);
403 }
404 
operator ()(const Tuple * value,const DataType::ConstPtr & data_type) const405 bool IsValidDataType<const Tuple*>::operator()(const Tuple* value,
406                                                const DataType::ConstPtr& data_type) const {
407   return value->data_type()->equals(data_type);
408 }
409 
operator ()(const UserTypeValue * value,const DataType::ConstPtr & data_type) const410 bool IsValidDataType<const UserTypeValue*>::operator()(const UserTypeValue* value,
411                                                        const DataType::ConstPtr& data_type) const {
412   return value->data_type()->equals(data_type);
413 }
414