1 /**
2  *     Copyright 2016-2017 Couchbase, 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 /**
18  * A FTS query that matches terms (without further analysis). Usually for debugging purposes, prefer using MatchQuery.
19  */
20 #include "couchbase.h"
21 
22 typedef struct {
23     PCBC_ZEND_OBJECT_PRE
24     double boost;
25     char *field;
26     char *term;
27     int prefix_length;
28     int fuzziness;
29     PCBC_ZEND_OBJECT_POST
30 } pcbc_term_search_query_t;
31 
32 #if PHP_VERSION_ID >= 70000
pcbc_term_search_query_fetch_object(zend_object * obj)33 static inline pcbc_term_search_query_t *pcbc_term_search_query_fetch_object(zend_object *obj)
34 {
35     return (pcbc_term_search_query_t *)((char *)obj - XtOffsetOf(pcbc_term_search_query_t, std));
36 }
37 #define Z_TERM_SEARCH_QUERY_OBJ(zo) (pcbc_term_search_query_fetch_object(zo))
38 #define Z_TERM_SEARCH_QUERY_OBJ_P(zv) (pcbc_term_search_query_fetch_object(Z_OBJ_P(zv)))
39 #else
40 #define Z_TERM_SEARCH_QUERY_OBJ(zo) ((pcbc_term_search_query_t *)zo)
41 #define Z_TERM_SEARCH_QUERY_OBJ_P(zv) ((pcbc_term_search_query_t *)zend_object_store_get_object(zv TSRMLS_CC))
42 #endif
43 
44 #define LOGARGS(lvl) LCB_LOG_##lvl, NULL, "pcbc/term_search_query", __FILE__, __LINE__
45 
46 zend_class_entry *pcbc_term_search_query_ce;
47 
48 /* {{{ proto void TermSearchQuery::__construct() */
PHP_METHOD(TermSearchQuery,__construct)49 PHP_METHOD(TermSearchQuery, __construct)
50 {
51     throw_pcbc_exception("Accessing private constructor.", LCB_EINVAL);
52 }
53 /* }}} */
54 
55 /* {{{ proto \Couchbase\TermSearchQuery TermSearchQuery::field(string $field)
56  */
PHP_METHOD(TermSearchQuery,field)57 PHP_METHOD(TermSearchQuery, field)
58 {
59     pcbc_term_search_query_t *obj;
60     char *field = NULL;
61     int rv;
62     pcbc_str_arg_size field_len;
63 
64     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &field, &field_len);
65     if (rv == FAILURE) {
66         RETURN_NULL();
67     }
68 
69     obj = Z_TERM_SEARCH_QUERY_OBJ_P(getThis());
70     if (obj->field) {
71         efree(obj->field);
72     }
73     obj->field = estrndup(field, field_len);
74 
75     RETURN_ZVAL(getThis(), 1, 0);
76 } /* }}} */
77 
78 /* {{{ proto \Couchbase\TermSearchQuery TermSearchQuery::prefixLength(int $prefixLength)
79  */
PHP_METHOD(TermSearchQuery,prefixLength)80 PHP_METHOD(TermSearchQuery, prefixLength)
81 {
82     pcbc_term_search_query_t *obj;
83     long prefix_length = 0;
84     int rv;
85 
86     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &prefix_length);
87     if (rv == FAILURE) {
88         RETURN_NULL();
89     }
90 
91     obj = Z_TERM_SEARCH_QUERY_OBJ_P(getThis());
92     obj->prefix_length = prefix_length;
93 
94     RETURN_ZVAL(getThis(), 1, 0);
95 } /* }}} */
96 
97 /* {{{ proto \Couchbase\TermSearchQuery TermSearchQuery::fuzziness(int $fuzziness)
98  */
PHP_METHOD(TermSearchQuery,fuzziness)99 PHP_METHOD(TermSearchQuery, fuzziness)
100 {
101     pcbc_term_search_query_t *obj;
102     long fuzziness = 0;
103     int rv;
104 
105     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &fuzziness);
106     if (rv == FAILURE) {
107         RETURN_NULL();
108     }
109 
110     obj = Z_TERM_SEARCH_QUERY_OBJ_P(getThis());
111     obj->fuzziness = fuzziness;
112 
113     RETURN_ZVAL(getThis(), 1, 0);
114 } /* }}} */
115 
116 /* {{{ proto \Couchbase\TermSearchQuery TermSearchQuery::boost(double $boost)
117  */
PHP_METHOD(TermSearchQuery,boost)118 PHP_METHOD(TermSearchQuery, boost)
119 {
120     pcbc_term_search_query_t *obj;
121     double boost = 0;
122     int rv;
123 
124     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &boost);
125     if (rv == FAILURE) {
126         RETURN_NULL();
127     }
128 
129     obj = Z_TERM_SEARCH_QUERY_OBJ_P(getThis());
130     obj->boost = boost;
131 
132     RETURN_ZVAL(getThis(), 1, 0);
133 } /* }}} */
134 
135 /* {{{ proto array TermSearchQuery::jsonSerialize()
136  */
PHP_METHOD(TermSearchQuery,jsonSerialize)137 PHP_METHOD(TermSearchQuery, jsonSerialize)
138 {
139     pcbc_term_search_query_t *obj;
140     int rv;
141 
142     rv = zend_parse_parameters_none();
143     if (rv == FAILURE) {
144         RETURN_NULL();
145     }
146 
147     obj = Z_TERM_SEARCH_QUERY_OBJ_P(getThis());
148     array_init(return_value);
149     ADD_ASSOC_STRING(return_value, "term", obj->term);
150     if (obj->field) {
151         ADD_ASSOC_STRING(return_value, "field", obj->field);
152     }
153     if (obj->prefix_length >= 0) {
154         ADD_ASSOC_LONG_EX(return_value, "prefix_length", obj->prefix_length);
155     }
156     if (obj->fuzziness >= 0) {
157         ADD_ASSOC_LONG_EX(return_value, "fuzziness", obj->fuzziness);
158     }
159     if (obj->boost >= 0) {
160         ADD_ASSOC_DOUBLE_EX(return_value, "boost", obj->boost);
161     }
162 } /* }}} */
163 
164 ZEND_BEGIN_ARG_INFO_EX(ai_TermSearchQuery_none, 0, 0, 0)
165 ZEND_END_ARG_INFO()
166 
167 ZEND_BEGIN_ARG_INFO_EX(ai_TermSearchQuery_field, 0, 0, 1)
168 ZEND_ARG_INFO(0, field)
169 ZEND_END_ARG_INFO()
170 
171 ZEND_BEGIN_ARG_INFO_EX(ai_TermSearchQuery_prefixLength, 0, 0, 1)
172 ZEND_ARG_INFO(0, prefixLength)
173 ZEND_END_ARG_INFO()
174 
175 ZEND_BEGIN_ARG_INFO_EX(ai_TermSearchQuery_fuzziness, 0, 0, 1)
176 ZEND_ARG_INFO(0, fuzziness)
177 ZEND_END_ARG_INFO()
178 
179 ZEND_BEGIN_ARG_INFO_EX(ai_TermSearchQuery_boost, 0, 0, 1)
180 ZEND_ARG_INFO(0, boost)
181 ZEND_END_ARG_INFO()
182 
183 // clang-format off
184 zend_function_entry term_search_query_methods[] = {
185     PHP_ME(TermSearchQuery, __construct, ai_TermSearchQuery_none, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL | ZEND_ACC_CTOR)
186     PHP_ME(TermSearchQuery, jsonSerialize, ai_TermSearchQuery_none, ZEND_ACC_PUBLIC)
187     PHP_ME(TermSearchQuery, boost, ai_TermSearchQuery_boost, ZEND_ACC_PUBLIC)
188     PHP_ME(TermSearchQuery, field, ai_TermSearchQuery_field, ZEND_ACC_PUBLIC)
189     PHP_ME(TermSearchQuery, prefixLength, ai_TermSearchQuery_prefixLength, ZEND_ACC_PUBLIC)
190     PHP_ME(TermSearchQuery, fuzziness, ai_TermSearchQuery_fuzziness, ZEND_ACC_PUBLIC)
191     PHP_FE_END
192 };
193 // clang-format on
194 
pcbc_term_search_query_init(zval * return_value,char * term,int term_len TSRMLS_DC)195 void pcbc_term_search_query_init(zval *return_value, char *term, int term_len TSRMLS_DC)
196 {
197     pcbc_term_search_query_t *obj;
198 
199     object_init_ex(return_value, pcbc_term_search_query_ce);
200     obj = Z_TERM_SEARCH_QUERY_OBJ_P(return_value);
201     obj->boost = -1;
202     obj->term = estrndup(term, term_len);
203     obj->field = NULL;
204     obj->prefix_length = -1;
205     obj->fuzziness = -1;
206 }
207 
208 zend_object_handlers term_search_query_handlers;
209 
term_search_query_free_object(pcbc_free_object_arg * object TSRMLS_DC)210 static void term_search_query_free_object(pcbc_free_object_arg *object TSRMLS_DC) /* {{{ */
211 {
212     pcbc_term_search_query_t *obj = Z_TERM_SEARCH_QUERY_OBJ(object);
213 
214     if (obj->term != NULL) {
215         efree(obj->term);
216     }
217     if (obj->field != NULL) {
218         efree(obj->field);
219     }
220 
221     zend_object_std_dtor(&obj->std TSRMLS_CC);
222 #if PHP_VERSION_ID < 70000
223     efree(obj);
224 #endif
225 } /* }}} */
226 
term_search_query_create_object(zend_class_entry * class_type TSRMLS_DC)227 static pcbc_create_object_retval term_search_query_create_object(zend_class_entry *class_type TSRMLS_DC)
228 {
229     pcbc_term_search_query_t *obj = NULL;
230 
231     obj = PCBC_ALLOC_OBJECT_T(pcbc_term_search_query_t, class_type);
232 
233     zend_object_std_init(&obj->std, class_type TSRMLS_CC);
234     object_properties_init(&obj->std, class_type);
235 
236 #if PHP_VERSION_ID >= 70000
237     obj->std.handlers = &term_search_query_handlers;
238     return &obj->std;
239 #else
240     {
241         zend_object_value ret;
242         ret.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object,
243                                             term_search_query_free_object, NULL TSRMLS_CC);
244         ret.handlers = &term_search_query_handlers;
245         return ret;
246     }
247 #endif
248 }
249 
pcbc_term_search_query_get_debug_info(zval * object,int * is_temp TSRMLS_DC)250 static HashTable *pcbc_term_search_query_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
251 {
252     pcbc_term_search_query_t *obj = NULL;
253 #if PHP_VERSION_ID >= 70000
254     zval retval;
255 #else
256     zval retval = zval_used_for_init;
257 #endif
258 
259     *is_temp = 1;
260     obj = Z_TERM_SEARCH_QUERY_OBJ_P(object);
261 
262     array_init(&retval);
263     ADD_ASSOC_STRING(&retval, "term", obj->term);
264     if (obj->field) {
265         ADD_ASSOC_STRING(&retval, "field", obj->field);
266     }
267     if (obj->prefix_length >= 0) {
268         ADD_ASSOC_LONG_EX(&retval, "prefix_length", obj->prefix_length);
269     }
270     if (obj->fuzziness >= 0) {
271         ADD_ASSOC_LONG_EX(&retval, "fuzziness", obj->fuzziness);
272     }
273     if (obj->boost >= 0) {
274         ADD_ASSOC_DOUBLE_EX(&retval, "boost", obj->boost);
275     }
276     return Z_ARRVAL(retval);
277 } /* }}} */
278 
PHP_MINIT_FUNCTION(TermSearchQuery)279 PHP_MINIT_FUNCTION(TermSearchQuery)
280 {
281     zend_class_entry ce;
282 
283     INIT_NS_CLASS_ENTRY(ce, "Couchbase", "TermSearchQuery", term_search_query_methods);
284     pcbc_term_search_query_ce = zend_register_internal_class(&ce TSRMLS_CC);
285     pcbc_term_search_query_ce->create_object = term_search_query_create_object;
286     PCBC_CE_DISABLE_SERIALIZATION(pcbc_term_search_query_ce);
287 
288     zend_class_implements(pcbc_term_search_query_ce TSRMLS_CC, 1, pcbc_json_serializable_ce);
289     zend_class_implements(pcbc_term_search_query_ce TSRMLS_CC, 1, pcbc_search_query_part_ce);
290 
291     memcpy(&term_search_query_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
292     term_search_query_handlers.get_debug_info = pcbc_term_search_query_get_debug_info;
293 #if PHP_VERSION_ID >= 70000
294     term_search_query_handlers.free_obj = term_search_query_free_object;
295     term_search_query_handlers.offset = XtOffsetOf(pcbc_term_search_query_t, std);
296 #endif
297 
298     zend_register_class_alias("\\CouchbaseTermSearchQuery", pcbc_term_search_query_ce);
299     return SUCCESS;
300 }
301