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