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/consistency.h"
20 #include "util/math.h"
21 
22 zend_class_entry *php_driver_execution_options_ce = NULL;
23 
init_execution_options(php_driver_execution_options * self)24 static void init_execution_options(php_driver_execution_options *self)
25 {
26   self->consistency = -1;
27   self->serial_consistency = -1;
28   self->page_size = -1;
29   self->paging_state_token = NULL;
30   self->paging_state_token_size = 0;
31   self->timestamp = INT64_MIN;
32   PHP5TO7_ZVAL_UNDEF(self->arguments);
33   PHP5TO7_ZVAL_UNDEF(self->timeout);
34   PHP5TO7_ZVAL_UNDEF(self->retry_policy);
35 }
36 
build_from_array(php_driver_execution_options * self,zval * options,int copy TSRMLS_DC)37 static int build_from_array(php_driver_execution_options *self, zval *options, int copy TSRMLS_DC)
38 {
39   php5to7_zval *consistency = NULL;
40   php5to7_zval *serial_consistency = NULL;
41   php5to7_zval *page_size = NULL;
42   php5to7_zval *paging_state_token = NULL;
43   php5to7_zval *timeout = NULL;
44   php5to7_zval *arguments = NULL;
45   php5to7_zval *retry_policy = NULL;
46   php5to7_zval *timestamp = NULL;
47 
48   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "consistency", sizeof("consistency"), consistency)) {
49     if (php_driver_get_consistency(PHP5TO7_ZVAL_MAYBE_DEREF(consistency), &self->consistency TSRMLS_CC) == FAILURE) {
50       return FAILURE;
51     }
52   }
53 
54   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "serial_consistency", sizeof("serial_consistency"), serial_consistency)) {
55     if (php_driver_get_serial_consistency(PHP5TO7_ZVAL_MAYBE_DEREF(serial_consistency), &self->serial_consistency TSRMLS_CC) == FAILURE) {
56       return FAILURE;
57     }
58   }
59 
60   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "page_size", sizeof("page_size"), page_size)) {
61     if (Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(page_size)) != IS_LONG || Z_LVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(page_size)) <= 0) {
62       throw_invalid_argument(PHP5TO7_ZVAL_MAYBE_DEREF(page_size), "page_size", "greater than zero" TSRMLS_CC);
63       return FAILURE;
64     }
65     self->page_size = Z_LVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(page_size));
66   }
67 
68   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "paging_state_token", sizeof("paging_state_token"), paging_state_token)) {
69     if (Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(paging_state_token)) != IS_STRING) {
70       throw_invalid_argument(PHP5TO7_ZVAL_MAYBE_DEREF(paging_state_token), "paging_state_token", "a string" TSRMLS_CC);
71       return FAILURE;
72     }
73     if (copy) {
74       self->paging_state_token = estrndup(Z_STRVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(paging_state_token)),
75                                           Z_STRLEN_P(PHP5TO7_ZVAL_MAYBE_DEREF(paging_state_token)));
76     } else {
77       self->paging_state_token = Z_STRVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(paging_state_token));
78     }
79     self->paging_state_token_size = Z_STRLEN_P(PHP5TO7_ZVAL_MAYBE_DEREF(paging_state_token));
80   }
81 
82   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "timeout", sizeof("timeout"), timeout)) {
83     if (!(Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(timeout)) == IS_LONG   && Z_LVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(timeout)) > 0) &&
84         !(Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(timeout)) == IS_DOUBLE && Z_DVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(timeout)) > 0) &&
85         !(Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(timeout)) == IS_NULL)) {
86       throw_invalid_argument(PHP5TO7_ZVAL_MAYBE_DEREF(timeout), "timeout", "a number of seconds greater than zero or null" TSRMLS_CC);
87       return FAILURE;
88     }
89 
90     if (copy) {
91       PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(self->timeout), PHP5TO7_ZVAL_MAYBE_DEREF(timeout));
92     } else {
93       self->timeout = *timeout;
94     }
95   }
96 
97   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "arguments", sizeof("arguments"), arguments)) {
98     if (Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(arguments)) != IS_ARRAY) {
99       throw_invalid_argument(PHP5TO7_ZVAL_MAYBE_DEREF(arguments), "arguments", "an array" TSRMLS_CC);
100       return FAILURE;
101     }
102 
103     if (copy) {
104       PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(self->arguments), PHP5TO7_ZVAL_MAYBE_DEREF(arguments));
105     } else {
106       self->arguments = *arguments;
107     }
108   }
109 
110   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "retry_policy", sizeof("retry_policy"), retry_policy)) {
111     if (Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(retry_policy)) != IS_OBJECT &&
112         !instanceof_function(Z_OBJCE_P(PHP5TO7_ZVAL_MAYBE_DEREF(retry_policy)),
113                              php_driver_retry_policy_ce TSRMLS_CC)) {
114       throw_invalid_argument(PHP5TO7_ZVAL_MAYBE_DEREF(retry_policy),
115                              "retry_policy",
116                              "an instance of " PHP_DRIVER_NAMESPACE "\\RetryPolicy" TSRMLS_CC);
117       return FAILURE;
118     }
119 
120     if (copy) {
121       PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(self->retry_policy), PHP5TO7_ZVAL_MAYBE_DEREF(retry_policy));
122     } else {
123       self->retry_policy = *retry_policy;
124     }
125   }
126 
127   if (PHP5TO7_ZEND_HASH_FIND(Z_ARRVAL_P(options), "timestamp", sizeof("timestamp"), timestamp)) {
128     if (Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(timestamp)) == IS_LONG) {
129       self->timestamp = Z_LVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(timestamp));
130     } else if (Z_TYPE_P(PHP5TO7_ZVAL_MAYBE_DEREF(timestamp)) == IS_STRING) {
131       if (!php_driver_parse_bigint(Z_STRVAL_P(PHP5TO7_ZVAL_MAYBE_DEREF(timestamp)),
132                                    Z_STRLEN_P(PHP5TO7_ZVAL_MAYBE_DEREF(timestamp)),
133                                    &self->timestamp TSRMLS_CC)) {
134         return FAILURE;
135       }
136     } else {
137       throw_invalid_argument(PHP5TO7_ZVAL_MAYBE_DEREF(timestamp), "timestamp", "an integer or integer string" TSRMLS_CC);
138       return FAILURE;
139     }
140   }
141   return SUCCESS;
142 }
143 
php_driver_execution_options_build_local_from_array(php_driver_execution_options * self,zval * options TSRMLS_DC)144 int php_driver_execution_options_build_local_from_array(php_driver_execution_options *self, zval *options TSRMLS_DC)
145 {
146   init_execution_options(self);
147   return build_from_array(self, options, 0 TSRMLS_CC);
148 }
149 
PHP_METHOD(ExecutionOptions,__construct)150 PHP_METHOD(ExecutionOptions, __construct)
151 {
152   zval *options = NULL;
153   php_driver_execution_options *self = NULL;
154 
155   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &options) == FAILURE) {
156     return;
157   }
158 
159   if (!options) return;
160 
161   if (Z_TYPE_P(options) != IS_ARRAY) {
162     INVALID_ARGUMENT(options, "an array");
163   }
164 
165   self = PHP_DRIVER_GET_EXECUTION_OPTIONS(getThis());
166 
167   build_from_array(self, options, 1 TSRMLS_CC);
168 }
169 
PHP_METHOD(ExecutionOptions,__get)170 PHP_METHOD(ExecutionOptions, __get)
171 {
172   char *name;
173   php5to7_size name_len;
174 
175   php_driver_execution_options *self = NULL;
176 
177   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
178     return;
179   }
180 
181   self = PHP_DRIVER_GET_EXECUTION_OPTIONS(getThis());
182 
183   if (name_len == 11 && strncmp("consistency", name, name_len) == 0) {
184     if (self->consistency == -1) {
185       RETURN_NULL();
186     }
187     RETURN_LONG(self->consistency);
188   } else if (name_len == 17 && strncmp("serialConsistency", name, name_len) == 0) {
189     if (self->serial_consistency == -1) {
190       RETURN_NULL();
191     }
192     RETURN_LONG(self->serial_consistency);
193   } else if (name_len == 8 && strncmp("pageSize", name, name_len) == 0) {
194     if (self->page_size == -1) {
195       RETURN_NULL();
196     }
197     RETURN_LONG(self->page_size);
198   } else if (name_len == 16 && strncmp("pagingStateToken", name, name_len) == 0) {
199     if (!self->paging_state_token) {
200       RETURN_NULL();
201     }
202     PHP5TO7_RETURN_STRINGL(self->paging_state_token,
203                            self->paging_state_token_size);
204   } else if (name_len == 7 && strncmp("timeout", name, name_len) == 0) {
205     if (PHP5TO7_ZVAL_IS_UNDEF(self->timeout)) {
206       RETURN_NULL();
207     }
208     RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(self->timeout), 1, 0);
209   } else if (name_len == 9 && strncmp("arguments", name, name_len) == 0) {
210     if (PHP5TO7_ZVAL_IS_UNDEF(self->arguments)) {
211       RETURN_NULL();
212     }
213     RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(self->arguments), 1, 0);
214   } else if (name_len == 11 && strncmp("retryPolicy", name, name_len) == 0) {
215     if (PHP5TO7_ZVAL_IS_UNDEF(self->retry_policy)) {
216       RETURN_NULL();
217     }
218     RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(self->retry_policy), 1, 0);
219   } else if (name_len == 9 && strncmp("timestamp", name, name_len) == 0) {
220     char *string;
221     if (self->timestamp == INT64_MIN) {
222       RETURN_NULL();
223     }
224 #ifdef WIN32
225     spprintf(&string, 0, "%I64d", (long long int) self->timestamp);
226 #else
227     spprintf(&string, 0, "%lld", (long long int) self->timestamp);
228 #endif
229     PHP5TO7_RETVAL_STRING(string);
230     efree(string);
231   }
232 }
233 
234 ZEND_BEGIN_ARG_INFO_EX(arginfo__construct, 0, ZEND_RETURN_VALUE, 0)
235   ZEND_ARG_ARRAY_INFO(0, options, 1)
236 ZEND_END_ARG_INFO()
237 
238 ZEND_BEGIN_ARG_INFO_EX(arginfo___get, 0, ZEND_RETURN_VALUE, 1)
239   ZEND_ARG_INFO(0, name)
240 ZEND_END_ARG_INFO()
241 
242 static zend_function_entry php_driver_execution_options_methods[] = {
243   PHP_ME(ExecutionOptions, __construct, arginfo__construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR | ZEND_ACC_DEPRECATED)
244   PHP_ME(ExecutionOptions, __get, arginfo___get, ZEND_ACC_PUBLIC)
245   PHP_FE_END
246 };
247 
248 static zend_object_handlers php_driver_execution_options_handlers;
249 
250 static HashTable *
php_driver_execution_options_properties(zval * object TSRMLS_DC)251 php_driver_execution_options_properties(zval *object TSRMLS_DC)
252 {
253   HashTable *props = zend_std_get_properties(object TSRMLS_CC);
254 
255   return props;
256 }
257 
258 static int
php_driver_execution_options_compare(zval * obj1,zval * obj2 TSRMLS_DC)259 php_driver_execution_options_compare(zval *obj1, zval *obj2 TSRMLS_DC)
260 {
261   if (Z_OBJCE_P(obj1) != Z_OBJCE_P(obj2))
262     return 1; /* different classes */
263 
264   return Z_OBJ_HANDLE_P(obj1) != Z_OBJ_HANDLE_P(obj1);
265 }
266 
267 static void
php_driver_execution_options_free(php5to7_zend_object_free * object TSRMLS_DC)268 php_driver_execution_options_free(php5to7_zend_object_free *object TSRMLS_DC)
269 {
270   php_driver_execution_options *self =
271       PHP5TO7_ZEND_OBJECT_GET(execution_options, object);
272 
273   if (self->paging_state_token) {
274     efree(self->paging_state_token);
275   }
276   PHP5TO7_ZVAL_MAYBE_DESTROY(self->arguments);
277   PHP5TO7_ZVAL_MAYBE_DESTROY(self->timeout);
278   PHP5TO7_ZVAL_MAYBE_DESTROY(self->retry_policy);
279 
280   zend_object_std_dtor(&self->zval TSRMLS_CC);
281   PHP5TO7_MAYBE_EFREE(self);
282 }
283 
284 static php5to7_zend_object
php_driver_execution_options_new(zend_class_entry * ce TSRMLS_DC)285 php_driver_execution_options_new(zend_class_entry *ce TSRMLS_DC)
286 {
287   php_driver_execution_options *self =
288       PHP5TO7_ZEND_OBJECT_ECALLOC(execution_options, ce);
289 
290   init_execution_options(self);
291 
292   PHP5TO7_ZEND_OBJECT_INIT(execution_options, self, ce);
293 }
294 
php_driver_define_ExecutionOptions(TSRMLS_D)295 void php_driver_define_ExecutionOptions(TSRMLS_D)
296 {
297   zend_class_entry ce;
298 
299   INIT_CLASS_ENTRY(ce, PHP_DRIVER_NAMESPACE "\\ExecutionOptions", php_driver_execution_options_methods);
300   php_driver_execution_options_ce = zend_register_internal_class(&ce TSRMLS_CC);
301   php_driver_execution_options_ce->ce_flags     |= PHP5TO7_ZEND_ACC_FINAL;
302   php_driver_execution_options_ce->create_object = php_driver_execution_options_new;
303 
304   memcpy(&php_driver_execution_options_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
305   php_driver_execution_options_handlers.get_properties  = php_driver_execution_options_properties;
306   php_driver_execution_options_handlers.compare_objects = php_driver_execution_options_compare;
307   php_driver_execution_options_handlers.clone_obj = NULL;
308 }
309