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 "value.hpp"
18 
19 #include "collection_iterator.hpp"
20 #include "data_type.hpp"
21 #include "external.hpp"
22 #include "serialization.hpp"
23 
24 #define CHECK_RESULT(result) \
25   if (!(result)) return false;
26 #define CHECK_VALUE(result)                  \
27   do {                                       \
28     if ((result)) {                          \
29       return CASS_OK;                        \
30     } else {                                 \
31       return CASS_ERROR_LIB_NOT_ENOUGH_DATA; \
32     }                                        \
33   } while (0)
34 
35 using namespace datastax;
36 using namespace datastax::internal;
37 using namespace datastax::internal::core;
38 
39 extern "C" {
40 
cass_value_data_type(const CassValue * value)41 const CassDataType* cass_value_data_type(const CassValue* value) {
42   return CassDataType::to(value->data_type().get());
43 }
44 
cass_value_get_int8(const CassValue * value,cass_int8_t * output)45 CassError cass_value_get_int8(const CassValue* value, cass_int8_t* output) {
46   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
47   if (value->value_type() != CASS_VALUE_TYPE_TINY_INT) {
48     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
49   }
50   CHECK_VALUE(value->decoder().as_int8(output));
51 }
52 
cass_value_get_int16(const CassValue * value,cass_int16_t * output)53 CassError cass_value_get_int16(const CassValue* value, cass_int16_t* output) {
54   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
55   if (value->value_type() != CASS_VALUE_TYPE_SMALL_INT) {
56     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
57   }
58   CHECK_VALUE(value->decoder().as_int16(output));
59 }
60 
cass_value_get_int32(const CassValue * value,cass_int32_t * output)61 CassError cass_value_get_int32(const CassValue* value, cass_int32_t* output) {
62   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
63   if (value->value_type() != CASS_VALUE_TYPE_INT) {
64     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
65   }
66   CHECK_VALUE(value->decoder().as_int32(output));
67 }
68 
cass_value_get_uint32(const CassValue * value,cass_uint32_t * output)69 CassError cass_value_get_uint32(const CassValue* value, cass_uint32_t* output) {
70   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
71   if (value->value_type() != CASS_VALUE_TYPE_DATE) {
72     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
73   }
74   CHECK_VALUE(value->decoder().as_uint32(output));
75 }
76 
cass_value_get_int64(const CassValue * value,cass_int64_t * output)77 CassError cass_value_get_int64(const CassValue* value, cass_int64_t* output) {
78   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
79   if (!is_int64_type(value->value_type())) {
80     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
81   }
82   CHECK_VALUE(value->decoder().as_int64(output));
83 }
84 
cass_value_get_float(const CassValue * value,cass_float_t * output)85 CassError cass_value_get_float(const CassValue* value, cass_float_t* output) {
86   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
87   if (value->value_type() != CASS_VALUE_TYPE_FLOAT) {
88     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
89   }
90   CHECK_VALUE(value->decoder().as_float(output));
91 }
92 
cass_value_get_double(const CassValue * value,cass_double_t * output)93 CassError cass_value_get_double(const CassValue* value, cass_double_t* output) {
94   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
95   if (value->value_type() != CASS_VALUE_TYPE_DOUBLE) {
96     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
97   }
98   CHECK_VALUE(value->decoder().as_double(output));
99 }
100 
cass_value_get_bool(const CassValue * value,cass_bool_t * output)101 CassError cass_value_get_bool(const CassValue* value, cass_bool_t* output) {
102   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
103   if (value->value_type() != CASS_VALUE_TYPE_BOOLEAN) {
104     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
105   }
106   bool decode_value = false;
107   if (!value->decoder().as_bool(&decode_value)) {
108     return CASS_ERROR_LIB_NOT_ENOUGH_DATA;
109   }
110   *output = decode_value ? cass_true : cass_false;
111   return CASS_OK;
112 }
113 
cass_value_get_uuid(const CassValue * value,CassUuid * output)114 CassError cass_value_get_uuid(const CassValue* value, CassUuid* output) {
115   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
116   if (!is_uuid_type(value->value_type())) {
117     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
118   }
119   CHECK_VALUE(value->decoder().as_uuid(output));
120 }
121 
cass_value_get_inet(const CassValue * value,CassInet * output)122 CassError cass_value_get_inet(const CassValue* value, CassInet* output) {
123   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
124   if (value->value_type() != CASS_VALUE_TYPE_INET) {
125     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
126   }
127   if (!value->decoder().as_inet(value->size(), output)) {
128     return CASS_ERROR_LIB_INVALID_DATA;
129   }
130   return CASS_OK;
131 }
132 
cass_value_get_string(const CassValue * value,const char ** output,size_t * output_length)133 CassError cass_value_get_string(const CassValue* value, const char** output,
134                                 size_t* output_length) {
135   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
136   StringRef buffer = value->decoder().as_string_ref();
137   *output = buffer.data();
138   *output_length = buffer.size();
139   return CASS_OK;
140 }
141 
cass_value_get_bytes(const CassValue * value,const cass_byte_t ** output,size_t * output_size)142 CassError cass_value_get_bytes(const CassValue* value, const cass_byte_t** output,
143                                size_t* output_size) {
144   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
145   StringRef buffer = value->decoder().as_string_ref();
146   *output = reinterpret_cast<const cass_byte_t*>(buffer.data());
147   *output_size = buffer.size();
148   return CASS_OK;
149 }
150 
cass_value_get_duration(const CassValue * value,cass_int32_t * months,cass_int32_t * days,cass_int64_t * nanos)151 CassError cass_value_get_duration(const CassValue* value, cass_int32_t* months, cass_int32_t* days,
152                                   cass_int64_t* nanos) {
153   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
154   if (!cass_value_is_duration(value)) return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
155   CHECK_VALUE(value->decoder().as_duration(months, days, nanos));
156 }
157 
cass_value_get_decimal(const CassValue * value,const cass_byte_t ** varint,size_t * varint_size,cass_int32_t * scale)158 CassError cass_value_get_decimal(const CassValue* value, const cass_byte_t** varint,
159                                  size_t* varint_size, cass_int32_t* scale) {
160   if (value == NULL || value->is_null()) return CASS_ERROR_LIB_NULL_VALUE;
161   if (value->value_type() != CASS_VALUE_TYPE_DECIMAL) {
162     return CASS_ERROR_LIB_INVALID_VALUE_TYPE;
163   }
164   CHECK_VALUE(value->decoder().as_decimal(varint, varint_size, scale));
165 }
166 
cass_value_type(const CassValue * value)167 CassValueType cass_value_type(const CassValue* value) { return value->value_type(); }
168 
cass_value_is_null(const CassValue * value)169 cass_bool_t cass_value_is_null(const CassValue* value) {
170   return static_cast<cass_bool_t>(value->is_null());
171 }
172 
cass_value_is_collection(const CassValue * value)173 cass_bool_t cass_value_is_collection(const CassValue* value) {
174   return static_cast<cass_bool_t>(value->is_collection());
175 }
176 
cass_value_is_duration(const CassValue * value)177 cass_bool_t cass_value_is_duration(const CassValue* value) {
178   IsValidDataType<CassDuration> is_valid;
179   CassDuration dummy(0, 0, 0);
180   return static_cast<cass_bool_t>(is_valid(dummy, value->data_type()));
181 }
182 
cass_value_item_count(const CassValue * collection)183 size_t cass_value_item_count(const CassValue* collection) { return collection->count(); }
184 
cass_value_primary_sub_type(const CassValue * collection)185 CassValueType cass_value_primary_sub_type(const CassValue* collection) {
186   return collection->primary_value_type();
187 }
188 
cass_value_secondary_sub_type(const CassValue * collection)189 CassValueType cass_value_secondary_sub_type(const CassValue* collection) {
190   return collection->secondary_value_type();
191 }
192 
193 } // extern "C"
194 
Value(const DataType::ConstPtr & data_type,Decoder decoder)195 Value::Value(const DataType::ConstPtr& data_type, Decoder decoder)
196     : data_type_(data_type)
197     , count_(0)
198     , decoder_(decoder)
199     , is_null_(false) {
200   assert(!data_type->is_collection());
201   if (data_type->is_tuple()) {
202     SharedRefPtr<const CompositeType> composite_type(data_type);
203     count_ = composite_type->types().size();
204   } else if (data_type->is_user_type()) {
205     UserType::ConstPtr user_type(data_type);
206     count_ = user_type->fields().size();
207   } else {
208     count_ = 0;
209   }
210 }
211 
as_bool() const212 bool Value::as_bool() const {
213   assert(!is_null() && value_type() == CASS_VALUE_TYPE_BOOLEAN);
214   bool value = false;
215   bool result = decoder_.as_bool(&value);
216   UNUSED_(result);
217   assert(result);
218   return value;
219 }
220 
as_int32() const221 int32_t Value::as_int32() const {
222   assert(!is_null() && value_type() == CASS_VALUE_TYPE_INT);
223   int32_t value = 0;
224   bool result = decoder_.as_int32(&value);
225   UNUSED_(result);
226   assert(result);
227   return value;
228 }
229 
as_uuid() const230 CassUuid Value::as_uuid() const {
231   assert(!is_null() &&
232          (value_type() == CASS_VALUE_TYPE_UUID || value_type() == CASS_VALUE_TYPE_TIMEUUID));
233   CassUuid value = { 0, 0 };
234   bool result = decoder_.as_uuid(&value);
235   UNUSED_(result);
236   assert(result);
237   return value;
238 }
239 
as_stringlist() const240 StringVec Value::as_stringlist() const {
241   assert(!is_null() &&
242          (value_type() == CASS_VALUE_TYPE_LIST || value_type() == CASS_VALUE_TYPE_SET) &&
243          primary_value_type() == CASS_VALUE_TYPE_VARCHAR);
244   StringVec stringlist;
245   CollectionIterator iterator(this);
246   while (iterator.next()) {
247     stringlist.push_back(iterator.value()->to_string());
248   }
249   return stringlist;
250 }
251