1 /**
2 * Copyright 2015-2017 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 "php_driver.h"
18 #include "php_driver_globals.h"
19 #include "php_driver_types.h"
20 #include "util/types.h"
21 #if PHP_MAJOR_VERSION >= 7
22 #include <zend_smart_str.h>
23 #else
24 #include <ext/standard/php_smart_str.h>
25 #endif
26 #include "src/Bigint.h"
27 #include "src/Smallint.h"
28 #include "src/Tinyint.h"
29 #include "src/Blob.h"
30 #include "src/Decimal.h"
31 #include "src/Duration.h"
32 #include "src/Float.h"
33 #include "src/Inet.h"
34 #include "src/Timestamp.h"
35 #include "src/Date.h"
36 #include "src/Time.h"
37 #include "src/Timeuuid.h"
38 #include "src/Uuid.h"
39 #include "src/Varint.h"
40 #include "src/Type/Tuple.h"
41 #include "src/Type/UserType.h"
42
43 struct node_s {
44 struct node_s *parent;
45 const char *name;
46 size_t name_length;
47 struct node_s *first_child;
48 struct node_s *last_child;
49 struct node_s *next_sibling;
50 struct node_s *prev_sibling;
51 };
52 static int
hex_value(int c)53 hex_value(int c)
54 {
55 if (c >= '0' && c <= '9') {
56 return c - '0';
57 } else if (c >= 'A' && c <= 'F') {
58 return c - 'A' + 10;
59 } else if (c >= 'a' && c <= 'f') {
60 return c - 'a' + 10;
61 }
62 return -1;
63 }
64
65 static char*
php_driver_from_hex(const char * hex,size_t hex_length)66 php_driver_from_hex(const char* hex, size_t hex_length)
67 {
68 size_t i, c = 0;
69 size_t size = hex_length / 2;
70 char *result;
71 if ((hex_length & 1) == 1) { /* Invalid if not divisible by 2 */
72 return NULL;
73 }
74 result = emalloc(size + 1);
75 for (i = 0; i < size; ++i) {
76 int half0 = hex_value(hex[i * 2]);
77 int half1 = hex_value(hex[i * 2 + 1]);
78 if (half0 < 0 || half1 < 0) {
79 efree(result);
80 return NULL;
81 }
82 result[c++] = (char)(((uint8_t)half0 << 4) | (uint8_t)half1);
83 }
84 result[size] = '\0';
85 return result;
86 }
87
88 static php5to7_zval
89 php_driver_create_type(struct node_s *node TSRMLS_DC);
90
91 static php5to7_zval
php_driver_tuple_from_data_type(const CassDataType * data_type TSRMLS_DC)92 php_driver_tuple_from_data_type(const CassDataType *data_type TSRMLS_DC) {
93 php5to7_zval ztype;
94 php_driver_type *type;
95 size_t i, count;
96
97 count = cass_data_sub_type_count(data_type);
98 ztype = php_driver_type_tuple(TSRMLS_C);
99 type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
100 for (i = 0; i < count; ++i) {
101 php5to7_zval sub_type =
102 php_driver_type_from_data_type(
103 cass_data_type_sub_data_type(data_type, i) TSRMLS_CC);
104 php_driver_type_tuple_add(type,
105 PHP5TO7_ZVAL_MAYBE_P(sub_type)
106 TSRMLS_CC);
107 }
108
109 return ztype;
110 }
111
112 static php5to7_zval
php_driver_tuple_from_node(struct node_s * node TSRMLS_DC)113 php_driver_tuple_from_node(struct node_s *node TSRMLS_DC) {
114 php5to7_zval ztype;
115 php_driver_type *type;
116 struct node_s *current;
117
118 ztype = php_driver_type_tuple(TSRMLS_C);
119 type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
120
121 for (current = node->first_child;
122 current != NULL;
123 current = current->next_sibling) {
124 php5to7_zval sub_type = php_driver_create_type(current TSRMLS_CC);
125 php_driver_type_tuple_add(type,
126 PHP5TO7_ZVAL_MAYBE_P(sub_type)
127 TSRMLS_CC);
128 }
129
130 return ztype;
131 }
132
133 static php5to7_zval
php_driver_user_type_from_data_type(const CassDataType * data_type TSRMLS_DC)134 php_driver_user_type_from_data_type(const CassDataType *data_type TSRMLS_DC)
135 {
136 php5to7_zval ztype;
137 php_driver_type *type;
138 const char *type_name, *keyspace;
139 size_t type_name_len, keyspace_len;
140 size_t i, count;
141
142 count = cass_data_sub_type_count(data_type);
143 ztype = php_driver_type_user_type(TSRMLS_C);
144 type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
145
146 cass_data_type_type_name(data_type, &type_name, &type_name_len);
147 type->data.udt.type_name = estrndup(type_name, type_name_len);
148 cass_data_type_keyspace(data_type, &keyspace, &keyspace_len);
149 type->data.udt.keyspace = estrndup(keyspace, keyspace_len);
150
151 for (i = 0; i < count; ++i) {
152 const char *name;
153 size_t name_length;
154 php5to7_zval sub_type =
155 php_driver_type_from_data_type(
156 cass_data_type_sub_data_type(data_type, i) TSRMLS_CC);
157 cass_data_type_sub_type_name(data_type, i, &name, &name_length);
158 php_driver_type_user_type_add(type,
159 name, name_length,
160 PHP5TO7_ZVAL_MAYBE_P(sub_type) TSRMLS_CC);
161 }
162
163 return ztype;
164 }
165
166
167 static php5to7_zval
php_driver_user_type_from_node(struct node_s * node TSRMLS_DC)168 php_driver_user_type_from_node(struct node_s *node TSRMLS_DC)
169 {
170 php5to7_zval ztype;
171 php_driver_type *type;
172 struct node_s *current = node->first_child;
173
174 ztype = php_driver_type_user_type(TSRMLS_C);
175 type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
176
177 if (current) {
178 type->data.udt.keyspace = estrndup(current->name,
179 current->name_length);
180 current = current->next_sibling;
181 }
182
183 if (current) {
184 type->data.udt.type_name = php_driver_from_hex(current->name,
185 current->name_length);
186 current = current->next_sibling;
187 }
188
189 for (; current; current = current->next_sibling) {
190 php5to7_zval sub_type;
191 char *name = php_driver_from_hex(current->name,
192 current->name_length);
193 current = current->next_sibling;
194 if (!current) {
195 efree(name);
196 break;
197 }
198 sub_type = php_driver_create_type(current TSRMLS_CC);
199 php_driver_type_user_type_add(type,
200 name, strlen(name),
201 PHP5TO7_ZVAL_MAYBE_P(sub_type) TSRMLS_CC);
202 efree(name);
203 }
204
205 return ztype;
206 }
207
208 php5to7_zval
php_driver_type_from_data_type(const CassDataType * data_type TSRMLS_DC)209 php_driver_type_from_data_type(const CassDataType *data_type TSRMLS_DC)
210 {
211 php5to7_zval ztype;
212 php5to7_zval key_type;
213 php5to7_zval value_type;
214 const char *class_name;
215 size_t class_name_length;
216 CassValueType type = cass_data_type_type(data_type);
217
218 PHP5TO7_ZVAL_UNDEF(ztype);
219
220 switch (type) {
221 #define XX_SCALAR(name, value) \
222 case value: \
223 ztype = php_driver_type_scalar(value TSRMLS_CC); \
224 break;
225 PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR)
226 #undef XX_SCALAR
227
228 case CASS_VALUE_TYPE_CUSTOM:
229 cass_data_type_class_name(data_type, &class_name, &class_name_length);
230 ztype = php_driver_type_custom(class_name, class_name_length TSRMLS_CC);
231 break;
232
233 case CASS_VALUE_TYPE_LIST:
234 value_type = php_driver_type_from_data_type(
235 cass_data_type_sub_data_type(data_type, 0) TSRMLS_CC);
236 ztype = php_driver_type_collection(PHP5TO7_ZVAL_MAYBE_P(value_type) TSRMLS_CC);
237 break;
238
239 case CASS_VALUE_TYPE_MAP:
240 key_type = php_driver_type_from_data_type(
241 cass_data_type_sub_data_type(data_type, 0) TSRMLS_CC);
242 value_type = php_driver_type_from_data_type(
243 cass_data_type_sub_data_type(data_type, 1) TSRMLS_CC);
244 ztype = php_driver_type_map(PHP5TO7_ZVAL_MAYBE_P(key_type),
245 PHP5TO7_ZVAL_MAYBE_P(value_type) TSRMLS_CC);
246 break;
247
248 case CASS_VALUE_TYPE_SET:
249 value_type = php_driver_type_from_data_type(
250 cass_data_type_sub_data_type(data_type, 0) TSRMLS_CC);
251 ztype = php_driver_type_set(PHP5TO7_ZVAL_MAYBE_P(value_type) TSRMLS_CC);
252 break;
253
254 case CASS_VALUE_TYPE_TUPLE:
255 ztype = php_driver_tuple_from_data_type(data_type TSRMLS_CC);
256 break;
257
258 case CASS_VALUE_TYPE_UDT:
259 ztype = php_driver_user_type_from_data_type(data_type TSRMLS_CC);
260 break;
261
262 default:
263 break;
264 }
265
266 return ztype;
267 }
268
php_driver_type_validate(zval * object,const char * object_name TSRMLS_DC)269 int php_driver_type_validate(zval *object, const char *object_name TSRMLS_DC)
270 {
271 if (!instanceof_function(Z_OBJCE_P(object), php_driver_type_scalar_ce TSRMLS_CC) &&
272 !instanceof_function(Z_OBJCE_P(object), php_driver_type_collection_ce TSRMLS_CC) &&
273 !instanceof_function(Z_OBJCE_P(object), php_driver_type_map_ce TSRMLS_CC) &&
274 !instanceof_function(Z_OBJCE_P(object), php_driver_type_set_ce TSRMLS_CC) &&
275 !instanceof_function(Z_OBJCE_P(object), php_driver_type_tuple_ce TSRMLS_CC) &&
276 !instanceof_function(Z_OBJCE_P(object), php_driver_type_user_type_ce TSRMLS_CC)) {
277 throw_invalid_argument(object, object_name, "a valid " PHP_DRIVER_NAMESPACE "\\Type" TSRMLS_CC);
278 return 0;
279 }
280 return 1;
281 }
282
283 static inline int
collection_compare(php_driver_type * type1,php_driver_type * type2 TSRMLS_DC)284 collection_compare(php_driver_type *type1, php_driver_type *type2 TSRMLS_DC)
285 {
286 return php_driver_type_compare(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type1->data.collection.value_type)),
287 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type2->data.collection.value_type)) TSRMLS_CC);
288 }
289
290 static inline int
map_compare(php_driver_type * type1,php_driver_type * type2 TSRMLS_DC)291 map_compare(php_driver_type *type1, php_driver_type *type2 TSRMLS_DC)
292 {
293 int result;
294 result = php_driver_type_compare(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type1->data.map.key_type)),
295 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type2->data.map.key_type)) TSRMLS_CC);
296 if (result != 0) return result;
297 result = php_driver_type_compare(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type1->data.map.value_type)),
298 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type2->data.map.value_type)) TSRMLS_CC);
299 if (result != 0) return result;
300 return 0;
301 }
302
303 static inline int
set_compare(php_driver_type * type1,php_driver_type * type2 TSRMLS_DC)304 set_compare(php_driver_type *type1, php_driver_type *type2 TSRMLS_DC)
305 {
306 return php_driver_type_compare(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type1->data.set.value_type)),
307 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type2->data.set.value_type)) TSRMLS_CC);
308 }
309
310 static inline int
tuple_compare(php_driver_type * type1,php_driver_type * type2 TSRMLS_DC)311 tuple_compare(php_driver_type *type1, php_driver_type *type2 TSRMLS_DC) {
312 HashPosition pos1;
313 HashPosition pos2;
314 php5to7_zval *current1;
315 php5to7_zval *current2;
316
317 if (zend_hash_num_elements(&type1->data.tuple.types) != zend_hash_num_elements(&type2->data.tuple.types)) {
318 return zend_hash_num_elements(&type1->data.tuple.types) < zend_hash_num_elements(&type2->data.tuple.types) ? -1 : 1;
319 }
320
321 zend_hash_internal_pointer_reset_ex(&type1->data.tuple.types, &pos1);
322 zend_hash_internal_pointer_reset_ex(&type2->data.tuple.types, &pos2);
323
324 while (PHP5TO7_ZEND_HASH_GET_CURRENT_DATA_EX(&type1->data.tuple.types, current1, &pos1) &&
325 PHP5TO7_ZEND_HASH_GET_CURRENT_DATA_EX(&type2->data.tuple.types, current2, &pos2)) {
326 php_driver_type *sub_type1 =
327 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_DEREF(current1));
328 php_driver_type *sub_type2 =
329 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_DEREF(current2));
330 int result = php_driver_type_compare(sub_type1, sub_type2 TSRMLS_CC);
331 if (result != 0) return result;
332 zend_hash_move_forward_ex(&type1->data.tuple.types, &pos1);
333 zend_hash_move_forward_ex(&type2->data.tuple.types, &pos2);
334 }
335
336 return 0;
337 }
338
339 static inline int
user_type_compare(php_driver_type * type1,php_driver_type * type2 TSRMLS_DC)340 user_type_compare(php_driver_type *type1, php_driver_type *type2 TSRMLS_DC)
341 {
342 HashPosition pos1;
343 HashPosition pos2;
344 php5to7_string key1;
345 php5to7_string key2;
346 php5to7_zval *current1;
347 php5to7_zval *current2;
348
349 if (zend_hash_num_elements(&type1->data.udt.types) != zend_hash_num_elements(&type2->data.udt.types)) {
350 return zend_hash_num_elements(&type1->data.udt.types) < zend_hash_num_elements(&type2->data.udt.types) ? -1 : 1;
351 }
352
353 zend_hash_internal_pointer_reset_ex(&type1->data.udt.types, &pos1);
354 zend_hash_internal_pointer_reset_ex(&type2->data.udt.types, &pos2);
355
356 while (PHP5TO7_ZEND_HASH_GET_CURRENT_KEY_EX(&type1->data.udt.types, &key1, NULL, &pos1) == HASH_KEY_IS_STRING &&
357 PHP5TO7_ZEND_HASH_GET_CURRENT_KEY_EX(&type2->data.udt.types, &key2, NULL, &pos2) == HASH_KEY_IS_STRING &&
358 PHP5TO7_ZEND_HASH_GET_CURRENT_DATA_EX(&type1->data.udt.types, current1, &pos1) &&
359 PHP5TO7_ZEND_HASH_GET_CURRENT_DATA_EX(&type2->data.udt.types, current2, &pos2)) {
360 int result;
361 php_driver_type *sub_type1 =
362 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_DEREF(current1));
363 php_driver_type *sub_type2 =
364 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_DEREF(current2));
365 result = php5to7_string_compare(key1, key2);
366 if (result != 0) return result;
367 result = php_driver_type_compare(sub_type1, sub_type2 TSRMLS_CC);
368 if (result != 0) return result;
369 zend_hash_move_forward_ex(&type1->data.udt.types, &pos1);
370 zend_hash_move_forward_ex(&type2->data.udt.types, &pos2);
371 }
372
373 return 0;
374 }
375
376 static inline int
is_string_type(CassValueType type)377 is_string_type(CassValueType type)
378 {
379 return type == CASS_VALUE_TYPE_VARCHAR || type == CASS_VALUE_TYPE_TEXT;
380 }
381
382 int
php_driver_type_compare(php_driver_type * type1,php_driver_type * type2 TSRMLS_DC)383 php_driver_type_compare(php_driver_type *type1, php_driver_type *type2 TSRMLS_DC)
384 {
385 if (type1->type != type2->type) {
386 if (is_string_type(type1->type) &&
387 is_string_type(type2->type)) { /* varchar and text are aliases */
388 return 0;
389 }
390 return type1->type < type2->type ? -1 : 1;
391 } else {
392 switch (type1->type) {
393 case CASS_VALUE_TYPE_LIST:
394 return collection_compare(type1, type2 TSRMLS_CC);
395
396 case CASS_VALUE_TYPE_MAP:
397 return map_compare(type1, type2 TSRMLS_CC);
398
399 case CASS_VALUE_TYPE_SET:
400 return set_compare(type1, type2 TSRMLS_CC);
401
402 case CASS_VALUE_TYPE_TUPLE:
403 return tuple_compare(type1, type2 TSRMLS_CC);
404
405 case CASS_VALUE_TYPE_UDT:
406 return user_type_compare(type1, type2 TSRMLS_CC);
407
408 default:
409 break;
410 }
411 return 0;
412 }
413 }
414
415 static inline void
collection_string(php_driver_type * type,smart_str * string TSRMLS_DC)416 collection_string(php_driver_type *type, smart_str *string TSRMLS_DC)
417 {
418 smart_str_appendl(string, "list<", 5);
419 php_driver_type_string(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type->data.collection.value_type)), string TSRMLS_CC);
420 smart_str_appendl(string, ">", 1);
421 }
422
423 static inline void
map_string(php_driver_type * type,smart_str * string TSRMLS_DC)424 map_string(php_driver_type *type, smart_str *string TSRMLS_DC)
425 {
426 smart_str_appendl(string, "map<", 4);
427 php_driver_type_string(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type->data.map.key_type)), string TSRMLS_CC);
428 smart_str_appendl(string, ", ", 2);
429 php_driver_type_string(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type->data.map.value_type)), string TSRMLS_CC);
430 smart_str_appendl(string, ">", 1);
431 }
432
433 static inline void
set_string(php_driver_type * type,smart_str * string TSRMLS_DC)434 set_string(php_driver_type *type, smart_str *string TSRMLS_DC)
435 {
436 smart_str_appendl(string, "set<", 4);
437 php_driver_type_string(PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(type->data.set.value_type)), string TSRMLS_CC);
438 smart_str_appendl(string, ">", 1);
439 }
440
441 static inline void
tuple_string(php_driver_type * type,smart_str * string TSRMLS_DC)442 tuple_string(php_driver_type *type, smart_str *string TSRMLS_DC) {
443 php5to7_zval *current;
444 int first = 1;
445
446 smart_str_appendl(string, "tuple<", 6);
447 PHP5TO7_ZEND_HASH_FOREACH_VAL(&type->data.tuple.types, current) {
448 php_driver_type *sub_type =
449 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_DEREF(current));
450 if (!first) smart_str_appendl(string, ", ", 2);
451 first = 0;
452 php_driver_type_string(sub_type, string TSRMLS_CC);
453 } PHP5TO7_ZEND_HASH_FOREACH_END(&type->data.tuple.types);
454 smart_str_appendl(string, ">", 1);
455 }
456
457 static inline void
user_type_string(php_driver_type * type,smart_str * string TSRMLS_DC)458 user_type_string(php_driver_type *type, smart_str *string TSRMLS_DC)
459 {
460 char *name;
461 php5to7_zval *current;
462 int first = 1;
463
464 if (type->data.udt.type_name) {
465 if (type->data.udt.keyspace) {
466 smart_str_appendl(string, type->data.udt.keyspace, strlen(type->data.udt.keyspace));
467 smart_str_appendl(string, ".", 1);
468 }
469 smart_str_appendl(string, type->data.udt.type_name, strlen(type->data.udt.type_name));
470 } else {
471 smart_str_appendl(string, "userType<", 9);
472 PHP5TO7_ZEND_HASH_FOREACH_STR_KEY_VAL(&type->data.udt.types, name, current) {
473 php_driver_type *sub_type =
474 PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_DEREF(current));
475 if (!first) smart_str_appendl(string, ", ", 2);
476 first = 0;
477 smart_str_appendl(string, name, strlen(name));
478 smart_str_appendl(string, ":", 1);
479 php_driver_type_string(sub_type, string TSRMLS_CC);
480 } PHP5TO7_ZEND_HASH_FOREACH_END(&type->data.udt.types);
481 smart_str_appendl(string, ">", 1);
482 }
483 }
484
485 void
php_driver_type_string(php_driver_type * type,smart_str * string TSRMLS_DC)486 php_driver_type_string(php_driver_type *type, smart_str *string TSRMLS_DC)
487 {
488 switch (type->type) {
489 #define XX_SCALAR(name, value) \
490 case value: \
491 smart_str_appendl(string, #name, strlen(#name)); \
492 break;
493 PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR)
494 #undef XX_SCALAR
495
496 case CASS_VALUE_TYPE_LIST:
497 collection_string(type, string TSRMLS_CC);
498 break;
499
500 case CASS_VALUE_TYPE_MAP:
501 map_string(type, string TSRMLS_CC);
502 break;
503
504 case CASS_VALUE_TYPE_SET:
505 set_string(type, string TSRMLS_CC);
506 break;
507
508 case CASS_VALUE_TYPE_TUPLE:
509 tuple_string(type, string TSRMLS_CC);
510 break;
511
512 case CASS_VALUE_TYPE_UDT:
513 user_type_string(type, string TSRMLS_CC);
514 break;
515
516 default:
517 smart_str_appendl(string, "invalid", 7);
518 break;
519 }
520 }
521
522 static php5to7_zval
php_driver_type_scalar_new(CassValueType type TSRMLS_DC)523 php_driver_type_scalar_new(CassValueType type TSRMLS_DC)
524 {
525 php5to7_zval ztype;
526 php_driver_type *scalar;
527
528 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
529 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_scalar_ce);
530 scalar = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
531 scalar->type = type;
532 scalar->data_type = cass_data_type_new(type);
533
534 return ztype;
535 }
536
537
538 const char *
php_driver_scalar_type_name(CassValueType type TSRMLS_DC)539 php_driver_scalar_type_name(CassValueType type TSRMLS_DC)
540 {
541 switch (type) {
542 #define XX_SCALAR(name, value) \
543 case value: \
544 return #name;
545 PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR)
546 #undef XX_SCALAR
547 default:
548 return "invalid";
549 }
550 }
551
552 static void
php_driver_varchar_init(INTERNAL_FUNCTION_PARAMETERS)553 php_driver_varchar_init(INTERNAL_FUNCTION_PARAMETERS)
554 {
555 char *string;
556 php5to7_size string_len;
557
558 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
559 return;
560 }
561
562 PHP5TO7_RETVAL_STRINGL(string, string_len);
563 }
564
565 static void
php_driver_ascii_init(INTERNAL_FUNCTION_PARAMETERS)566 php_driver_ascii_init(INTERNAL_FUNCTION_PARAMETERS)
567 {
568 php_driver_varchar_init(INTERNAL_FUNCTION_PARAM_PASSTHRU);
569 }
570
571 static void
php_driver_boolean_init(INTERNAL_FUNCTION_PARAMETERS)572 php_driver_boolean_init(INTERNAL_FUNCTION_PARAMETERS)
573 {
574 zend_bool value;
575
576 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &value) == FAILURE) {
577 return;
578 }
579
580 RETURN_BOOL(value);
581 }
582
583 static void
php_driver_counter_init(INTERNAL_FUNCTION_PARAMETERS)584 php_driver_counter_init(INTERNAL_FUNCTION_PARAMETERS)
585 {
586 php_driver_bigint_init(INTERNAL_FUNCTION_PARAM_PASSTHRU);
587 }
588
589 static void
php_driver_double_init(INTERNAL_FUNCTION_PARAMETERS)590 php_driver_double_init(INTERNAL_FUNCTION_PARAMETERS)
591 {
592 double value;
593
594 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &value) == FAILURE) {
595 return;
596 }
597
598 RETURN_DOUBLE(value);
599 }
600
601 static void
php_driver_int_init(INTERNAL_FUNCTION_PARAMETERS)602 php_driver_int_init(INTERNAL_FUNCTION_PARAMETERS)
603 {
604 long value;
605
606 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == FAILURE) {
607 return;
608 }
609
610 RETURN_LONG(value);
611 }
612
613 static void
php_driver_text_init(INTERNAL_FUNCTION_PARAMETERS)614 php_driver_text_init(INTERNAL_FUNCTION_PARAMETERS)
615 {
616 php_driver_varchar_init(INTERNAL_FUNCTION_PARAM_PASSTHRU);
617 }
618
619 #define TYPE_INIT_METHOD(t) php_driver_ ## t ## _init
620
621 void
php_driver_scalar_init(INTERNAL_FUNCTION_PARAMETERS)622 php_driver_scalar_init(INTERNAL_FUNCTION_PARAMETERS)
623 {
624 php_driver_type *self = PHP_DRIVER_GET_TYPE(getThis());
625
626 #define XX_SCALAR(name, value) \
627 if (self->type == value) { \
628 TYPE_INIT_METHOD(name)(INTERNAL_FUNCTION_PARAM_PASSTHRU); \
629 }
630 PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR)
631 #undef XX_SCALAR
632 }
633 #undef TYPE_INIT_METHOD
634
635 #define TYPE_CODE(m) type_ ## m
636
637 php5to7_zval
php_driver_type_scalar(CassValueType type TSRMLS_DC)638 php_driver_type_scalar(CassValueType type TSRMLS_DC)
639 {
640 php5to7_zval result;
641 PHP5TO7_ZVAL_UNDEF(result);
642
643 #define XX_SCALAR(name, value) \
644 if (value == type) { \
645 if (PHP5TO7_ZVAL_IS_UNDEF(PHP_DRIVER_G(TYPE_CODE(name)))) { \
646 PHP_DRIVER_G(TYPE_CODE(name)) = php_driver_type_scalar_new(type TSRMLS_CC); \
647 } \
648 Z_ADDREF_P(PHP5TO7_ZVAL_MAYBE_P(PHP_DRIVER_G(TYPE_CODE(name)))); \
649 return PHP_DRIVER_G(TYPE_CODE(name)); \
650 }
651 PHP_DRIVER_SCALAR_TYPES_MAP(XX_SCALAR)
652 #undef XX_SCALAR
653
654 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce,
655 0 TSRMLS_CC, "Invalid type");
656 return result;
657 }
658 #undef TYPE_CODE
659
660 php5to7_zval
php_driver_type_map(zval * key_type,zval * value_type TSRMLS_DC)661 php_driver_type_map(zval *key_type,
662 zval *value_type TSRMLS_DC)
663 {
664 php5to7_zval ztype;
665 php_driver_type *map;
666 php_driver_type *sub_type;
667
668 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
669 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_map_ce);
670 map = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
671
672 if (!PHP5TO7_ZVAL_IS_UNDEF_P(key_type)) {
673 sub_type = PHP_DRIVER_GET_TYPE(key_type);
674 cass_data_type_add_sub_type(map->data_type, sub_type->data_type);
675 }
676
677 if (!PHP5TO7_ZVAL_IS_UNDEF_P(value_type)) {
678 sub_type = PHP_DRIVER_GET_TYPE(value_type);
679 cass_data_type_add_sub_type(map->data_type, sub_type->data_type);
680 }
681
682 #if PHP_MAJOR_VERSION >= 7
683 map->data.map.key_type = *key_type;
684 map->data.map.value_type = *value_type;
685 #else
686 map->data.map.key_type = key_type;
687 map->data.map.value_type = value_type;
688 #endif
689
690 return ztype;
691 }
692
693 php5to7_zval
php_driver_type_map_from_value_types(CassValueType key_type,CassValueType value_type TSRMLS_DC)694 php_driver_type_map_from_value_types(CassValueType key_type,
695 CassValueType value_type TSRMLS_DC)
696 {
697 php5to7_zval ztype;
698 php_driver_type *map;
699 php_driver_type *sub_type;
700
701 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
702 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_map_ce);
703 map = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
704 map->data.map.key_type = php_driver_type_scalar(key_type TSRMLS_CC);
705 map->data.map.value_type = php_driver_type_scalar(value_type TSRMLS_CC);
706
707 sub_type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(map->data.map.key_type));
708 cass_data_type_add_sub_type(map->data_type, sub_type->data_type);
709 sub_type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(map->data.map.value_type));
710 cass_data_type_add_sub_type(map->data_type, sub_type->data_type);
711
712 return ztype;
713 }
714
715 php5to7_zval
php_driver_type_set(zval * value_type TSRMLS_DC)716 php_driver_type_set(zval *value_type TSRMLS_DC)
717 {
718 php5to7_zval ztype;
719 php_driver_type *set;
720 php_driver_type *sub_type;
721
722 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
723 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_set_ce);
724 set = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
725
726 if (!PHP5TO7_ZVAL_IS_UNDEF_P(value_type)) {
727 sub_type = PHP_DRIVER_GET_TYPE(value_type);
728 cass_data_type_add_sub_type(set->data_type, sub_type->data_type);
729 }
730
731 #if PHP_MAJOR_VERSION >= 7
732 set->data.set.value_type = *value_type;
733 #else
734 set->data.set.value_type = value_type;
735 #endif
736
737 return ztype;
738 }
739
740 php5to7_zval
php_driver_type_set_from_value_type(CassValueType type TSRMLS_DC)741 php_driver_type_set_from_value_type(CassValueType type TSRMLS_DC)
742 {
743 php5to7_zval ztype;
744 php_driver_type *set;
745 php_driver_type *sub_type;
746
747 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
748 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_set_ce);
749 set = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
750 set->data.set.value_type = php_driver_type_scalar(type TSRMLS_CC);
751
752 sub_type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(set->data.set.value_type));
753 cass_data_type_add_sub_type(set->data_type, sub_type->data_type);
754
755 return ztype;
756 }
757
758 php5to7_zval
php_driver_type_collection(zval * value_type TSRMLS_DC)759 php_driver_type_collection(zval *value_type TSRMLS_DC)
760 {
761 php5to7_zval ztype;
762 php_driver_type *collection;
763 php_driver_type *sub_type;
764
765 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
766 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_collection_ce);
767 collection = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
768
769 if (!PHP5TO7_ZVAL_IS_UNDEF_P(value_type)) {
770 sub_type = PHP_DRIVER_GET_TYPE(value_type);
771 cass_data_type_add_sub_type(collection->data_type, sub_type->data_type);
772 }
773
774 #if PHP_MAJOR_VERSION >= 7
775 collection->data.collection.value_type = *value_type;
776 #else
777 collection->data.collection.value_type = value_type;
778 #endif
779
780 return ztype;
781 }
782
783 php5to7_zval
php_driver_type_collection_from_value_type(CassValueType type TSRMLS_DC)784 php_driver_type_collection_from_value_type(CassValueType type TSRMLS_DC)
785 {
786 php5to7_zval ztype;
787 php_driver_type *collection;
788 php_driver_type *sub_type;
789
790 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
791 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_collection_ce);
792 collection = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
793 collection->data.collection.value_type = php_driver_type_scalar(type TSRMLS_CC);
794
795 sub_type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(collection->data.collection.value_type));
796 cass_data_type_add_sub_type(collection->data_type, sub_type->data_type);
797
798 return ztype;
799 }
800
801 php5to7_zval
php_driver_type_tuple(TSRMLS_D)802 php_driver_type_tuple(TSRMLS_D)
803 {
804 php5to7_zval ztype;
805
806 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
807 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_tuple_ce);
808
809 return ztype;
810 }
811
812 php5to7_zval
php_driver_type_user_type(TSRMLS_D)813 php_driver_type_user_type(TSRMLS_D)
814 {
815 php5to7_zval ztype;
816 php_driver_type *user_type;
817
818 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
819 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_user_type_ce);
820 user_type = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
821 user_type->data_type = cass_data_type_new(CASS_VALUE_TYPE_UDT);
822
823 return ztype;
824 }
825
826 php5to7_zval
php_driver_type_custom(const char * name,size_t name_length TSRMLS_DC)827 php_driver_type_custom(const char *name, size_t name_length TSRMLS_DC)
828 {
829 php5to7_zval ztype;
830 php_driver_type *custom;
831
832 PHP5TO7_ZVAL_MAYBE_MAKE(ztype);
833 object_init_ex(PHP5TO7_ZVAL_MAYBE_P(ztype), php_driver_type_custom_ce);
834 custom = PHP_DRIVER_GET_TYPE(PHP5TO7_ZVAL_MAYBE_P(ztype));
835 custom->data.custom.class_name = estrndup(name, name_length);
836
837 return ztype;
838 }
839
840 #define EXPECTING_TOKEN(expected) \
841 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC, \
842 "Unexpected %s at position %d in string \"%s\", expected " expected, \
843 describe_token(token), ((int) (str - validator) - 1), validator \
844 ); \
845 return FAILURE;
846
847 enum token_type {
848 TOKEN_ILLEGAL = 0,
849 TOKEN_PAREN_OPEN,
850 TOKEN_PAREN_CLOSE,
851 TOKEN_COMMA,
852 TOKEN_COLON,
853 TOKEN_NAME,
854 TOKEN_END
855 };
856
857 enum parser_state {
858 STATE_CLASS = 0,
859 STATE_AFTER_CLASS,
860 STATE_AFTER_PARENS,
861 STATE_END
862 };
863
864 static const char *
describe_token(enum token_type token)865 describe_token(enum token_type token)
866 {
867 switch (token) {
868 case TOKEN_ILLEGAL: return "illegal character"; break;
869 case TOKEN_PAREN_OPEN: return "opening parenthesis"; break;
870 case TOKEN_PAREN_CLOSE: return "closing parenthesis"; break;
871 case TOKEN_COMMA: return "comma"; break;
872 case TOKEN_COLON: return "colon"; break;
873 case TOKEN_NAME: return "alphanumeric character"; break;
874 case TOKEN_END: return "end of string"; break;
875 default: return "unknown token";
876 }
877 }
878
879 static int
isletter(char ch)880 isletter(char ch)
881 {
882 return isalnum(ch) || ch == '.';
883 }
884
885 static enum token_type
next_token(const char * str,size_t len,const char ** token_str,size_t * token_len,const char ** str_out,size_t * len_out)886 next_token(const char *str, size_t len,
887 const char **token_str, size_t *token_len,
888 const char **str_out, size_t *len_out)
889 {
890 enum token_type type;
891 unsigned int i = 0;
892 char c = str[i];
893
894 if (len == 0) {
895 return TOKEN_END;
896 }
897
898 if (isalnum(c)) {
899 type = TOKEN_NAME;
900 while (i < len) {
901 if (!isletter(str[i])) {
902 break;
903 }
904 i++;
905 }
906 } else {
907 switch (c) {
908 case '\0':
909 type = TOKEN_END;
910 break;
911 case '(':
912 type = TOKEN_PAREN_OPEN;
913 i++;
914 break;
915 case ')':
916 type = TOKEN_PAREN_CLOSE;
917 i++;
918 break;
919 case ',':
920 type = TOKEN_COMMA;
921 i++;
922 break;
923 case ':':
924 type = TOKEN_COLON;
925 i++;
926 break;
927 default:
928 type = TOKEN_ILLEGAL;
929 }
930 }
931
932 *token_str = &(str[0]);
933 *token_len = i;
934 *str_out = &(str[i]);
935 *len_out = len - i;
936
937 return type;
938 }
939
940 static struct node_s *
php_driver_parse_node_new()941 php_driver_parse_node_new()
942 {
943 struct node_s *node;
944 node = emalloc(sizeof(struct node_s));
945 node->parent = NULL;
946 node->name = NULL;
947 node->name_length = 0;
948 node->first_child = NULL;
949 node->last_child = NULL;
950 node->next_sibling = NULL;
951 node->prev_sibling = NULL;
952
953 return node;
954 }
955
956 static void
php_driver_parse_node_free(struct node_s * node)957 php_driver_parse_node_free(struct node_s *node)
958 {
959 if (node->first_child) {
960 php_driver_parse_node_free(node->first_child);
961 node->first_child = NULL;
962 }
963 node->last_child = NULL;
964
965 if (node->next_sibling) {
966 php_driver_parse_node_free(node->next_sibling);
967 node->next_sibling = NULL;
968 }
969
970 efree(node);
971 }
972
973 static int
php_driver_parse_class_name(const char * validator,size_t validator_len,struct node_s ** result TSRMLS_DC)974 php_driver_parse_class_name(const char *validator,
975 size_t validator_len,
976 struct node_s **result TSRMLS_DC)
977 {
978 const char *str;
979 size_t len;
980 const char *token_str;
981 size_t token_len;
982 enum parser_state state;
983 enum token_type token;
984 struct node_s *root;
985 struct node_s *node;
986 struct node_s *child;
987
988 token_str = NULL;
989 token_len = 0;
990 state = STATE_CLASS;
991 str = validator;
992 len = validator_len;
993 root = php_driver_parse_node_new();
994 node = root;
995
996 while (1) {
997 token = next_token(str, len, &token_str, &token_len, &str, &len);
998
999 if (token == TOKEN_ILLEGAL) {
1000 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
1001 "Illegal character \"%c\" at position %d in \"%s\"",
1002 *token_str, ((int) (str - validator) - 1), validator);
1003 php_driver_parse_node_free(root);
1004 return FAILURE;
1005 }
1006
1007 if (state == STATE_AFTER_PARENS) {
1008 if (token == TOKEN_COMMA) {
1009 if (node->parent == NULL) {
1010 EXPECTING_TOKEN("end of string");
1011 }
1012 state = STATE_CLASS;
1013
1014 child = php_driver_parse_node_new();
1015 child->parent = node->parent;
1016 child->prev_sibling = node;
1017 node->next_sibling = child;
1018 node->parent->last_child = child;
1019
1020 node = child;
1021 continue;
1022 } else if (token == TOKEN_PAREN_CLOSE) {
1023 if (node->parent == NULL) {
1024 EXPECTING_TOKEN("end of string");
1025 }
1026
1027 node = node->parent;
1028 continue;
1029 } else if (token == TOKEN_END) {
1030 break;
1031 } else {
1032 EXPECTING_TOKEN("a comma, a closing parenthesis or an end of string");
1033 }
1034 }
1035
1036 if (state == STATE_AFTER_CLASS) {
1037 if (token == TOKEN_PAREN_OPEN) {
1038 state = STATE_CLASS;
1039
1040 child = php_driver_parse_node_new();
1041 child->parent = node;
1042
1043 if (node->first_child == NULL) {
1044 node->first_child = child;
1045 }
1046
1047 if (node->last_child) {
1048 node->last_child->next_sibling = child;
1049 }
1050
1051 child->prev_sibling = node->last_child;
1052 node->last_child = child;
1053
1054 node = child;
1055 continue;
1056 } else if (token == TOKEN_COMMA || token == TOKEN_COLON) {
1057 state = STATE_CLASS;
1058
1059 child = php_driver_parse_node_new();
1060 child->parent = node->parent;
1061 child->prev_sibling = node;
1062 node->next_sibling = child;
1063 node->parent->last_child = child;
1064
1065 node = child;
1066 continue;
1067 } else if (token == TOKEN_PAREN_CLOSE) {
1068 state = STATE_AFTER_PARENS;
1069
1070 node = node->parent;
1071 continue;
1072 } else if (token == TOKEN_END) {
1073 break;
1074 } else {
1075 php_driver_parse_node_free(root);
1076 EXPECTING_TOKEN("opening/closing parenthesis or comma");
1077 }
1078 }
1079
1080 if (state == STATE_CLASS) {
1081 if (token != TOKEN_NAME) {
1082 php_driver_parse_node_free(root);
1083 EXPECTING_TOKEN("fully qualified class name");
1084 }
1085 state = STATE_AFTER_CLASS;
1086
1087 node->name = token_str;
1088 node->name_length = token_len;
1089 }
1090 }
1091
1092 *result = root;
1093 return SUCCESS;
1094 }
1095
1096 static CassValueType
php_driver_lookup_type(struct node_s * node TSRMLS_DC)1097 php_driver_lookup_type(struct node_s *node TSRMLS_DC)
1098 {
1099 if (strncmp("org.apache.cassandra.db.marshal.AsciiType", node->name, node->name_length) == 0) {
1100 return CASS_VALUE_TYPE_ASCII;
1101 }
1102
1103 if (strncmp("org.apache.cassandra.db.marshal.LongType", node->name, node->name_length) == 0) {
1104 return CASS_VALUE_TYPE_BIGINT;
1105 }
1106
1107 if (strncmp("org.apache.cassandra.db.marshal.ShortType", node->name, node->name_length) == 0) {
1108 return CASS_VALUE_TYPE_SMALL_INT;
1109 }
1110
1111 if (strncmp("org.apache.cassandra.db.marshal.ByteType", node->name, node->name_length) == 0) {
1112 return CASS_VALUE_TYPE_TINY_INT;
1113 }
1114
1115 if (strncmp("org.apache.cassandra.db.marshal.BytesType", node->name, node->name_length) == 0) {
1116 return CASS_VALUE_TYPE_BLOB;
1117 }
1118
1119 if (strncmp("org.apache.cassandra.db.marshal.BooleanType", node->name, node->name_length) == 0) {
1120 return CASS_VALUE_TYPE_BOOLEAN;
1121 }
1122
1123 if (strncmp("org.apache.cassandra.db.marshal.CounterColumnType", node->name, node->name_length) == 0) {
1124 return CASS_VALUE_TYPE_COUNTER;
1125 }
1126
1127 if (strncmp("org.apache.cassandra.db.marshal.DecimalType", node->name, node->name_length) == 0) {
1128 return CASS_VALUE_TYPE_DECIMAL;
1129 }
1130
1131 if (strncmp("org.apache.cassandra.db.marshal.DurationType", node->name, node->name_length) == 0) {
1132 return CASS_VALUE_TYPE_DURATION;
1133 }
1134
1135 if (strncmp("org.apache.cassandra.db.marshal.DoubleType", node->name, node->name_length) == 0) {
1136 return CASS_VALUE_TYPE_DOUBLE;
1137 }
1138
1139 if (strncmp("org.apache.cassandra.db.marshal.FloatType", node->name, node->name_length) == 0) {
1140 return CASS_VALUE_TYPE_FLOAT;
1141 }
1142
1143 if (strncmp("org.apache.cassandra.db.marshal.InetAddressType", node->name, node->name_length) == 0) {
1144 return CASS_VALUE_TYPE_INET;
1145 }
1146
1147 if (strncmp("org.apache.cassandra.db.marshal.Int32Type", node->name, node->name_length) == 0) {
1148 return CASS_VALUE_TYPE_INT;
1149 }
1150
1151 if (strncmp("org.apache.cassandra.db.marshal.UTF8Type", node->name, node->name_length) == 0) {
1152 return CASS_VALUE_TYPE_VARCHAR;
1153 }
1154
1155 if (strncmp("org.apache.cassandra.db.marshal.TimestampType", node->name, node->name_length) == 0 ||
1156 strncmp("org.apache.cassandra.db.marshal.DateType", node->name, node->name_length) == 0) {
1157 return CASS_VALUE_TYPE_TIMESTAMP;
1158 }
1159
1160 if (strncmp("org.apache.cassandra.db.marshal.SimpleDateType", node->name, node->name_length) == 0) {
1161 return CASS_VALUE_TYPE_DATE;
1162 }
1163
1164 if (strncmp("org.apache.cassandra.db.marshal.TimeType", node->name, node->name_length) == 0) {
1165 return CASS_VALUE_TYPE_TIME;
1166 }
1167
1168 if (strncmp("org.apache.cassandra.db.marshal.UUIDType", node->name, node->name_length) == 0) {
1169 return CASS_VALUE_TYPE_UUID;
1170 }
1171
1172 if (strncmp("org.apache.cassandra.db.marshal.IntegerType", node->name, node->name_length) == 0) {
1173 return CASS_VALUE_TYPE_VARINT;
1174 }
1175
1176 if (strncmp("org.apache.cassandra.db.marshal.TimeUUIDType", node->name, node->name_length) == 0) {
1177 return CASS_VALUE_TYPE_TIMEUUID;
1178 }
1179
1180 if (strncmp("org.apache.cassandra.db.marshal.MapType", node->name, node->name_length) == 0) {
1181 return CASS_VALUE_TYPE_MAP;
1182 }
1183
1184 if (strncmp("org.apache.cassandra.db.marshal.SetType", node->name, node->name_length) == 0) {
1185 return CASS_VALUE_TYPE_SET;
1186 }
1187
1188 if (strncmp("org.apache.cassandra.db.marshal.ListType", node->name, node->name_length) == 0) {
1189 return CASS_VALUE_TYPE_LIST;
1190 }
1191
1192 if (strncmp("org.apache.cassandra.db.marshal.TupleType", node->name, node->name_length) == 0) {
1193 return CASS_VALUE_TYPE_TUPLE;
1194 }
1195
1196 if (strncmp("org.apache.cassandra.db.marshal.UserType", node->name, node->name_length) == 0) {
1197 return CASS_VALUE_TYPE_UDT;
1198 }
1199
1200 return CASS_VALUE_TYPE_CUSTOM;
1201 }
1202
1203 static void
php_driver_node_dump_to(struct node_s * node,smart_str * text)1204 php_driver_node_dump_to(struct node_s *node, smart_str *text)
1205 {
1206 smart_str_appendl(text, node->name, node->name_length);
1207
1208 if (node->first_child) {
1209 smart_str_appendl(text, "(", 1);
1210 php_driver_node_dump_to(node->first_child, text);
1211 smart_str_appendl(text, ")", 1);
1212 }
1213
1214 if (node->next_sibling) {
1215 smart_str_appendl(text, ", ", 2);
1216 php_driver_node_dump_to(node->next_sibling, text);
1217 }
1218 }
1219
1220 static php5to7_zval
php_driver_create_type(struct node_s * node TSRMLS_DC)1221 php_driver_create_type(struct node_s *node TSRMLS_DC)
1222 {
1223 CassValueType type = CASS_VALUE_TYPE_UNKNOWN;
1224
1225 /* Skip wrapper types */
1226 while (node &&
1227 (strncmp("org.apache.cassandra.db.marshal.FrozenType", node->name, node->name_length) == 0 ||
1228 strncmp("org.apache.cassandra.db.marshal.ReversedType", node->name, node->name_length) == 0 ||
1229 strncmp("org.apache.cassandra.db.marshal.CompositeType", node->name, node->name_length) == 0)) {
1230 node = node->first_child;
1231 }
1232
1233 if (node) {
1234 type = php_driver_lookup_type(node TSRMLS_CC);
1235 }
1236
1237 if (type == CASS_VALUE_TYPE_UNKNOWN) {
1238 php5to7_zval undef;
1239 PHP5TO7_ZVAL_UNDEF(undef);
1240 return undef;
1241 }
1242
1243 if (type == CASS_VALUE_TYPE_CUSTOM) {
1244 php5to7_zval ztype;
1245 smart_str class_name = PHP5TO7_SMART_STR_INIT;
1246 php_driver_node_dump_to(node, &class_name);
1247 ztype = php_driver_type_custom(PHP5TO7_SMART_STR_VAL(class_name),
1248 PHP5TO7_SMART_STR_LEN(class_name) TSRMLS_CC);
1249 smart_str_free(&class_name);
1250 return ztype;
1251 } else if (type == CASS_VALUE_TYPE_MAP) {
1252 php5to7_zval key_type;
1253 php5to7_zval value_type;
1254
1255 if (node->first_child) {
1256 key_type = php_driver_create_type(node->first_child TSRMLS_CC);
1257 value_type = php_driver_create_type(node->first_child->next_sibling TSRMLS_CC);
1258 } else {
1259 PHP5TO7_ZVAL_UNDEF(key_type);
1260 PHP5TO7_ZVAL_UNDEF(value_type);
1261 }
1262 return php_driver_type_map(PHP5TO7_ZVAL_MAYBE_P(key_type),
1263 PHP5TO7_ZVAL_MAYBE_P(value_type) TSRMLS_CC);
1264 } else if (type == CASS_VALUE_TYPE_LIST) {
1265 php5to7_zval value_type;
1266 if (node->first_child) {
1267 value_type = php_driver_create_type(node->first_child TSRMLS_CC);
1268 } else {
1269 PHP5TO7_ZVAL_UNDEF(value_type);
1270 }
1271 return php_driver_type_collection(PHP5TO7_ZVAL_MAYBE_P(value_type) TSRMLS_CC);
1272 } else if (type == CASS_VALUE_TYPE_SET) {
1273 php5to7_zval value_type;
1274 if (node->first_child) {
1275 value_type = php_driver_create_type(node->first_child TSRMLS_CC);
1276 } else {
1277 PHP5TO7_ZVAL_UNDEF(value_type);
1278 }
1279 return php_driver_type_set(PHP5TO7_ZVAL_MAYBE_P(value_type) TSRMLS_CC);
1280 } else if (type == CASS_VALUE_TYPE_TUPLE) {
1281 return php_driver_tuple_from_node(node TSRMLS_CC);
1282 } else if (type == CASS_VALUE_TYPE_UDT) {
1283 return php_driver_user_type_from_node(node TSRMLS_CC);
1284 }
1285
1286 return php_driver_type_scalar(type TSRMLS_CC);
1287 }
1288
1289 int
php_driver_parse_column_type(const char * validator,size_t validator_len,int * reversed_out,int * frozen_out,php5to7_zval * type_out TSRMLS_DC)1290 php_driver_parse_column_type(const char *validator,
1291 size_t validator_len,
1292 int *reversed_out,
1293 int *frozen_out,
1294 php5to7_zval *type_out TSRMLS_DC)
1295 {
1296 struct node_s *root;
1297 struct node_s *node = NULL;
1298 cass_bool_t reversed = 0;
1299 cass_bool_t frozen = 0;
1300
1301 if (php_driver_parse_class_name(validator, validator_len, &root TSRMLS_CC) == FAILURE) {
1302 return FAILURE;
1303 }
1304
1305 node = root;
1306
1307 while (node) {
1308 if (strncmp("org.apache.cassandra.db.marshal.ReversedType", node->name, node->name_length) == 0) {
1309 reversed = 1;
1310 node = node->first_child;
1311 continue;
1312 }
1313
1314 if (strncmp("org.apache.cassandra.db.marshal.FrozenType", node->name, node->name_length) == 0) {
1315 frozen = 1;
1316 node = node->first_child;
1317 continue;
1318 }
1319
1320 if (strncmp("org.apache.cassandra.db.marshal.CompositeType", node->name, node->name_length) == 0) {
1321 node = node->first_child;
1322 continue;
1323 }
1324
1325 break;
1326 }
1327
1328 if (node == NULL) {
1329 php_driver_parse_node_free(root);
1330 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
1331 "Invalid type");
1332 return FAILURE;
1333 }
1334
1335 *reversed_out = reversed;
1336 *frozen_out = frozen;
1337 *type_out = php_driver_create_type(node TSRMLS_CC);
1338
1339 php_driver_parse_node_free(root);
1340
1341 return SUCCESS;
1342 }
1343