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_types.h"
19 #include "util/types.h"
20 #include "src/UserTypeValue.h"
21 #include "util/collections.h"
22
23 #if PHP_MAJOR_VERSION >= 7
24 #include <zend_smart_str.h>
25 #else
26 #include <ext/standard/php_smart_str.h>
27 #endif
28
29 zend_class_entry *php_driver_type_user_type_ce = NULL;
30
php_driver_type_user_type_add(php_driver_type * type,const char * name,size_t name_length,zval * zsub_type TSRMLS_DC)31 int php_driver_type_user_type_add(php_driver_type *type,
32 const char *name, size_t name_length,
33 zval *zsub_type TSRMLS_DC)
34 {
35 php_driver_type *sub_type = PHP_DRIVER_GET_TYPE(zsub_type);
36 if (cass_data_type_add_sub_type_by_name_n(type->data_type,
37 name, name_length,
38 sub_type->data_type) != CASS_OK) {
39 return 0;
40 }
41 PHP5TO7_ZEND_HASH_ADD(&type->data.udt.types,
42 name, name_length + 1,
43 zsub_type, sizeof(zval *));
44 return 1;
45 }
46
PHP_METHOD(TypeUserType,__construct)47 PHP_METHOD(TypeUserType, __construct)
48 {
49 zend_throw_exception_ex(php_driver_logic_exception_ce, 0 TSRMLS_CC,
50 "Instantiation of a " PHP_DRIVER_NAMESPACE "\\Type\\UserType type is not supported."
51 );
52 return;
53 }
54
PHP_METHOD(TypeUserType,withName)55 PHP_METHOD(TypeUserType, withName)
56 {
57 char *name;
58 php5to7_size name_len;
59 php_driver_type *self;
60 php_driver_type *user_type;
61
62 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
63 return;
64 }
65
66 self = PHP_DRIVER_GET_TYPE(getThis());
67
68 object_init_ex(return_value, php_driver_type_user_type_ce);
69 user_type = PHP_DRIVER_GET_TYPE(return_value);
70 user_type->data_type = cass_data_type_new_from_existing(self->data_type);
71
72 user_type->data.udt.type_name = estrndup(name, name_len);
73
74 if (self->data.udt.keyspace) {
75 user_type->data.udt.keyspace = estrdup(self->data.udt.keyspace);
76 }
77
78 PHP5TO7_ZEND_HASH_ZVAL_COPY(&user_type->data.udt.types, &self->data.udt.types);
79 }
80
PHP_METHOD(TypeUserType,name)81 PHP_METHOD(TypeUserType, name)
82 {
83 php_driver_type *self;
84
85 if (zend_parse_parameters_none() == FAILURE) {
86 return;
87 }
88
89 self = PHP_DRIVER_GET_TYPE(getThis());
90
91 if (!self->data.udt.type_name)
92 RETURN_NULL();
93
94 PHP5TO7_RETVAL_STRING(self->data.udt.type_name);
95 }
96
PHP_METHOD(TypeUserType,withKeyspace)97 PHP_METHOD(TypeUserType, withKeyspace)
98 {
99 char *keyspace;
100 php5to7_size keyspace_len;
101 php_driver_type *self;
102 php_driver_type *user_type;
103
104 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &keyspace, &keyspace_len) == FAILURE) {
105 return;
106 }
107
108 self = PHP_DRIVER_GET_TYPE(getThis());
109
110 object_init_ex(return_value, php_driver_type_user_type_ce);
111 user_type = PHP_DRIVER_GET_TYPE(return_value);
112 user_type->data_type = cass_data_type_new_from_existing(self->data_type);
113
114 if (self->data.udt.type_name) {
115 user_type->data.udt.type_name = estrdup(self->data.udt.type_name);
116 }
117
118 user_type->data.udt.keyspace = estrndup(keyspace, keyspace_len);
119
120 PHP5TO7_ZEND_HASH_ZVAL_COPY(&user_type->data.udt.types, &self->data.udt.types);
121 }
122
PHP_METHOD(TypeUserType,keyspace)123 PHP_METHOD(TypeUserType, keyspace)
124 {
125 php_driver_type *self;
126
127 if (zend_parse_parameters_none() == FAILURE) {
128 return;
129 }
130
131 self = PHP_DRIVER_GET_TYPE(getThis());
132
133 if (!self->data.udt.keyspace)
134 RETURN_NULL();
135
136 PHP5TO7_RETVAL_STRING(self->data.udt.keyspace);
137 }
138
PHP_METHOD(TypeUserType,types)139 PHP_METHOD(TypeUserType, types)
140 {
141 php_driver_type *self;
142
143 if (zend_parse_parameters_none() == FAILURE) {
144 return;
145 }
146
147 self = PHP_DRIVER_GET_TYPE(getThis());
148
149 array_init(return_value);
150 PHP5TO7_ZEND_HASH_ZVAL_COPY(Z_ARRVAL_P(return_value), &self->data.udt.types);
151 }
152
PHP_METHOD(TypeUserType,__toString)153 PHP_METHOD(TypeUserType, __toString)
154 {
155 php_driver_type *self;
156 smart_str string = PHP5TO7_SMART_STR_INIT;
157
158 if (zend_parse_parameters_none() == FAILURE) {
159 return;
160 }
161
162 self = PHP_DRIVER_GET_TYPE(getThis());
163
164 php_driver_type_string(self, &string TSRMLS_CC);
165 smart_str_0(&string);
166
167 PHP5TO7_RETVAL_STRING(PHP5TO7_SMART_STR_VAL(string));
168 smart_str_free(&string);
169 }
170
PHP_METHOD(TypeUserType,create)171 PHP_METHOD(TypeUserType, create)
172 {
173 php_driver_type *self;
174 php_driver_user_type_value *user_type_value;
175 php5to7_zval_args args = NULL;
176 int argc = 0, i;
177
178 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*",
179 &args, &argc) == FAILURE) {
180 return;
181 }
182
183 self = PHP_DRIVER_GET_TYPE(getThis());
184
185 object_init_ex(return_value, php_driver_user_type_value_ce);
186 user_type_value = PHP_DRIVER_GET_USER_TYPE_VALUE(return_value);
187
188 PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(user_type_value->type), getThis());
189
190 if (argc > 0) {
191 if (argc % 2 == 1) {
192 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
193 "Not enough name/value pairs, user_types can only be created " \
194 "from an even number of name/value pairs, where each odd " \
195 "argument is a name and each even argument is a value, " \
196 "e.g user_type(name, value, name, value, name, value)");
197 PHP5TO7_MAYBE_EFREE(args);
198 return;
199 }
200
201 for (i = 0; i < argc; i += 2) {
202 zval *name = PHP5TO7_ZVAL_ARG(args[i]);
203 zval *value = PHP5TO7_ZVAL_ARG(args[i + 1]);
204 php5to7_zval *sub_type;
205 if (Z_TYPE_P(name) != IS_STRING) {
206 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce, 0 TSRMLS_CC,
207 "Argument %d is not a string", i + 1);
208 PHP5TO7_MAYBE_EFREE(args);
209 return;
210 }
211 if (!PHP5TO7_ZEND_HASH_FIND(&self->data.udt.types,
212 Z_STRVAL_P(name), Z_STRLEN_P(name) + 1,
213 sub_type)) {
214 zend_throw_exception_ex(php_driver_invalid_argument_exception_ce,
215 0 TSRMLS_CC,
216 "Invalid name '%s'", Z_STRVAL_P(name));
217 PHP5TO7_MAYBE_EFREE(args);
218 return;
219 }
220 if (!php_driver_validate_object(value,
221 PHP5TO7_ZVAL_MAYBE_DEREF(sub_type) TSRMLS_CC)) {
222 PHP5TO7_MAYBE_EFREE(args);
223 return;
224 }
225 php_driver_user_type_value_set(user_type_value,
226 Z_STRVAL_P(name), Z_STRLEN_P(name),
227 value TSRMLS_CC);
228 }
229
230 PHP5TO7_MAYBE_EFREE(args);
231 }
232 }
233
234 ZEND_BEGIN_ARG_INFO_EX(arginfo_none, 0, ZEND_RETURN_VALUE, 0)
235 ZEND_END_ARG_INFO()
236
237 ZEND_BEGIN_ARG_INFO_EX(arginfo_value, 0, ZEND_RETURN_VALUE, 0)
238 ZEND_ARG_INFO(0, value)
239 ZEND_END_ARG_INFO()
240
241 ZEND_BEGIN_ARG_INFO_EX(arginfo_name, 0, ZEND_RETURN_VALUE, 1)
242 ZEND_ARG_INFO(0, name)
243 ZEND_END_ARG_INFO()
244
245 ZEND_BEGIN_ARG_INFO_EX(arginfo_keyspace, 0, ZEND_RETURN_VALUE, 1)
246 ZEND_ARG_INFO(0, keyspace)
247 ZEND_END_ARG_INFO()
248
249 static zend_function_entry php_driver_type_user_type_methods[] = {
250 PHP_ME(TypeUserType, __construct, arginfo_none, ZEND_ACC_PRIVATE)
251 PHP_ME(TypeUserType, withName, arginfo_name, ZEND_ACC_PUBLIC)
252 PHP_ME(TypeUserType, name, arginfo_none, ZEND_ACC_PUBLIC)
253 PHP_ME(TypeUserType, withKeyspace, arginfo_keyspace, ZEND_ACC_PUBLIC)
254 PHP_ME(TypeUserType, keyspace, arginfo_none, ZEND_ACC_PUBLIC)
255 PHP_ME(TypeUserType, __toString, arginfo_none, ZEND_ACC_PUBLIC)
256 PHP_ME(TypeUserType, types, arginfo_none, ZEND_ACC_PUBLIC)
257 PHP_ME(TypeUserType, create, arginfo_value, ZEND_ACC_PUBLIC)
258 PHP_FE_END
259 };
260
261 static zend_object_handlers php_driver_type_user_type_handlers;
262
263 static HashTable *
php_driver_type_user_type_gc(zval * object,php5to7_zval_gc table,int * n TSRMLS_DC)264 php_driver_type_user_type_gc(zval *object, php5to7_zval_gc table, int *n TSRMLS_DC)
265 {
266 *table = NULL;
267 *n = 0;
268 return zend_std_get_properties(object TSRMLS_CC);
269 }
270
271 static HashTable *
php_driver_type_user_type_properties(zval * object TSRMLS_DC)272 php_driver_type_user_type_properties(zval *object TSRMLS_DC)
273 {
274 php5to7_zval types;
275
276 php_driver_type *self = PHP_DRIVER_GET_TYPE(object);
277 HashTable *props = zend_std_get_properties(object TSRMLS_CC);
278
279 PHP5TO7_ZVAL_MAYBE_MAKE(types);
280 array_init(PHP5TO7_ZVAL_MAYBE_P(types));
281 PHP5TO7_ZEND_HASH_ZVAL_COPY(PHP5TO7_Z_ARRVAL_MAYBE_P(types), &self->data.udt.types);
282 PHP5TO7_ZEND_HASH_UPDATE(props,
283 "types", sizeof("types"),
284 PHP5TO7_ZVAL_MAYBE_P(types), sizeof(zval));
285
286 return props;
287 }
288
289 static int
php_driver_type_user_type_compare(zval * obj1,zval * obj2 TSRMLS_DC)290 php_driver_type_user_type_compare(zval *obj1, zval *obj2 TSRMLS_DC)
291 {
292 php_driver_type* type1 = PHP_DRIVER_GET_TYPE(obj1);
293 php_driver_type* type2 = PHP_DRIVER_GET_TYPE(obj2);
294
295 return php_driver_type_compare(type1, type2 TSRMLS_CC);
296 }
297
298 static void
php_driver_type_user_type_free(php5to7_zend_object_free * object TSRMLS_DC)299 php_driver_type_user_type_free(php5to7_zend_object_free *object TSRMLS_DC)
300 {
301 php_driver_type *self = PHP5TO7_ZEND_OBJECT_GET(type, object);
302
303 if (self->data_type) cass_data_type_free(self->data_type);
304 if (self->data.udt.keyspace) efree(self->data.udt.keyspace);
305 if (self->data.udt.type_name) efree(self->data.udt.type_name);
306 zend_hash_destroy(&self->data.udt.types);
307
308 zend_object_std_dtor(&self->zval TSRMLS_CC);
309 PHP5TO7_MAYBE_EFREE(self);
310 }
311
312 static php5to7_zend_object
php_driver_type_user_type_new(zend_class_entry * ce TSRMLS_DC)313 php_driver_type_user_type_new(zend_class_entry *ce TSRMLS_DC)
314 {
315 php_driver_type *self = PHP5TO7_ZEND_OBJECT_ECALLOC(type, ce);
316
317 self->type = CASS_VALUE_TYPE_UDT;
318 self->data_type = NULL;
319 self->data.udt.keyspace = self->data.udt.type_name = NULL;
320 zend_hash_init(&self->data.udt.types, 0, NULL, ZVAL_PTR_DTOR, 0);
321
322 PHP5TO7_ZEND_OBJECT_INIT_EX(type, type_user_type, self, ce);
323 }
324
php_driver_define_TypeUserType(TSRMLS_D)325 void php_driver_define_TypeUserType(TSRMLS_D)
326 {
327 zend_class_entry ce;
328
329 INIT_CLASS_ENTRY(ce, PHP_DRIVER_NAMESPACE "\\Type\\UserType", php_driver_type_user_type_methods);
330 php_driver_type_user_type_ce = php5to7_zend_register_internal_class_ex(&ce, php_driver_type_ce);
331 memcpy(&php_driver_type_user_type_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
332 php_driver_type_user_type_handlers.get_properties = php_driver_type_user_type_properties;
333 #if PHP_VERSION_ID >= 50400
334 php_driver_type_user_type_handlers.get_gc = php_driver_type_user_type_gc;
335 #endif
336 php_driver_type_user_type_handlers.compare_objects = php_driver_type_user_type_compare;
337 php_driver_type_user_type_ce->ce_flags |= PHP5TO7_ZEND_ACC_FINAL;
338 php_driver_type_user_type_ce->create_object = php_driver_type_user_type_new;
339 }
340