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 on Couchbase document IDs. Useful to restrict the search space to a list of keys (by using
19 * this in a compound query).
20 */
21 #include "couchbase.h"
22
23 typedef struct {
24 PCBC_ZEND_OBJECT_PRE
25 double boost;
26 char *field;
27 PCBC_ZVAL doc_ids;
28 PCBC_ZEND_OBJECT_POST
29 } pcbc_doc_id_search_query_t;
30
31 #if PHP_VERSION_ID >= 70000
pcbc_doc_id_search_query_fetch_object(zend_object * obj)32 static inline pcbc_doc_id_search_query_t *pcbc_doc_id_search_query_fetch_object(zend_object *obj)
33 {
34 return (pcbc_doc_id_search_query_t *)((char *)obj - XtOffsetOf(pcbc_doc_id_search_query_t, std));
35 }
36 #define Z_DOC_ID_SEARCH_QUERY_OBJ(zo) (pcbc_doc_id_search_query_fetch_object(zo))
37 #define Z_DOC_ID_SEARCH_QUERY_OBJ_P(zv) (pcbc_doc_id_search_query_fetch_object(Z_OBJ_P(zv)))
38 #else
39 #define Z_DOC_ID_SEARCH_QUERY_OBJ(zo) ((pcbc_doc_id_search_query_t *)zo)
40 #define Z_DOC_ID_SEARCH_QUERY_OBJ_P(zv) ((pcbc_doc_id_search_query_t *)zend_object_store_get_object(zv TSRMLS_CC))
41 #endif
42
43 #define LOGARGS(lvl) LCB_LOG_##lvl, NULL, "pcbc/doc_id_search_query", __FILE__, __LINE__
44
45 zend_class_entry *pcbc_doc_id_search_query_ce;
46
47 /* {{{ proto void DocIdSearchQuery::__construct() */
PHP_METHOD(DocIdSearchQuery,__construct)48 PHP_METHOD(DocIdSearchQuery, __construct)
49 {
50 throw_pcbc_exception("Accessing private constructor.", LCB_EINVAL);
51 }
52 /* }}} */
53
54 /* {{{ proto \Couchbase\DocIdSearchQuery DocIdSearchQuery::field(string $field)
55 */
PHP_METHOD(DocIdSearchQuery,field)56 PHP_METHOD(DocIdSearchQuery, field)
57 {
58 pcbc_doc_id_search_query_t *obj;
59 char *field = NULL;
60 int rv;
61 pcbc_str_arg_size field_len;
62
63 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &field, &field_len);
64 if (rv == FAILURE) {
65 RETURN_NULL();
66 }
67
68 obj = Z_DOC_ID_SEARCH_QUERY_OBJ_P(getThis());
69 if (obj->field) {
70 efree(obj->field);
71 }
72 obj->field = estrndup(field, field_len);
73
74 RETURN_ZVAL(getThis(), 1, 0);
75 } /* }}} */
76
77 /* {{{ proto \Couchbase\DocIdSearchQuery DocIdSearchQuery::boost(double $boost)
78 */
PHP_METHOD(DocIdSearchQuery,boost)79 PHP_METHOD(DocIdSearchQuery, boost)
80 {
81 pcbc_doc_id_search_query_t *obj;
82 double boost = 0;
83 int rv;
84
85 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &boost);
86 if (rv == FAILURE) {
87 RETURN_NULL();
88 }
89
90 obj = Z_DOC_ID_SEARCH_QUERY_OBJ_P(getThis());
91 obj->boost = boost;
92
93 RETURN_ZVAL(getThis(), 1, 0);
94 } /* }}} */
95
96 /* {{{ proto DocIdSearchQuery DocIdSearchQuery::docIds(string ...$documentIds)
97 */
PHP_METHOD(DocIdSearchQuery,docIds)98 PHP_METHOD(DocIdSearchQuery, docIds)
99 {
100 pcbc_doc_id_search_query_t *obj;
101 #if PHP_VERSION_ID >= 70000
102 zval *args = NULL;
103 #else
104 zval ***args = NULL;
105 #endif
106 int num_args = 0;
107 int rv;
108
109 rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args);
110 if (rv == FAILURE) {
111 return;
112 }
113
114 obj = Z_DOC_ID_SEARCH_QUERY_OBJ_P(getThis());
115
116 if (num_args && args) {
117 int i;
118 for (i = 0; i < num_args; ++i) {
119 PCBC_ZVAL *id;
120 #if PHP_VERSION_ID >= 70000
121 id = &args[i];
122 #else
123 id = args[i];
124 #endif
125 if (Z_TYPE_P(PCBC_P(*id)) != IS_STRING) {
126 pcbc_log(LOGARGS(WARN), "id has to be a string (skipping argument #%d)", i);
127 continue;
128 }
129 add_next_index_zval(PCBC_P(obj->doc_ids), PCBC_P(*id));
130 PCBC_ADDREF_P(PCBC_P(*id));
131 }
132 }
133 #if PHP_VERSION_ID < 70000
134 if (args) {
135 efree(args);
136 }
137 #endif
138
139 RETURN_ZVAL(getThis(), 1, 0);
140 } /* }}} */
141
142 /* {{{ proto array DocIdSearchQuery::jsonSerialize()
143 */
PHP_METHOD(DocIdSearchQuery,jsonSerialize)144 PHP_METHOD(DocIdSearchQuery, jsonSerialize)
145 {
146 pcbc_doc_id_search_query_t *obj;
147 int rv;
148
149 rv = zend_parse_parameters_none();
150 if (rv == FAILURE) {
151 RETURN_NULL();
152 }
153
154 obj = Z_DOC_ID_SEARCH_QUERY_OBJ_P(getThis());
155 array_init(return_value);
156 ADD_ASSOC_ZVAL_EX(return_value, "ids", PCBC_P(obj->doc_ids));
157 PCBC_ADDREF_P(PCBC_P(obj->doc_ids));
158 if (obj->field) {
159 ADD_ASSOC_STRING(return_value, "field", obj->field);
160 }
161 if (obj->boost >= 0) {
162 ADD_ASSOC_DOUBLE_EX(return_value, "boost", obj->boost);
163 }
164 } /* }}} */
165
166 ZEND_BEGIN_ARG_INFO_EX(ai_DocIdSearchQuery_none, 0, 0, 0)
167 ZEND_END_ARG_INFO()
168
169 ZEND_BEGIN_ARG_INFO_EX(ai_DocIdSearchQuery_field, 0, 0, 1)
170 ZEND_ARG_INFO(0, field)
171 ZEND_END_ARG_INFO()
172
173 ZEND_BEGIN_ARG_INFO_EX(ai_DocIdSearchQuery_boost, 0, 0, 1)
174 ZEND_ARG_INFO(0, boost)
175 ZEND_END_ARG_INFO()
176
177 ZEND_BEGIN_ARG_INFO_EX(ai_DocIdSearchQuery_docIds, 0, 0, 1)
178 PCBC_ARG_VARIADIC_INFO(0, documentIds)
179 ZEND_END_ARG_INFO()
180
181 // clang-format off
182 zend_function_entry doc_id_search_query_methods[] = {
183 PHP_ME(DocIdSearchQuery, __construct, ai_DocIdSearchQuery_none, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL | ZEND_ACC_CTOR)
184 PHP_ME(DocIdSearchQuery, jsonSerialize, ai_DocIdSearchQuery_none, ZEND_ACC_PUBLIC)
185 PHP_ME(DocIdSearchQuery, boost, ai_DocIdSearchQuery_boost, ZEND_ACC_PUBLIC)
186 PHP_ME(DocIdSearchQuery, field, ai_DocIdSearchQuery_field, ZEND_ACC_PUBLIC)
187 PHP_ME(DocIdSearchQuery, docIds, ai_DocIdSearchQuery_docIds, ZEND_ACC_PUBLIC)
188 PHP_FE_END
189 };
190 // clang-format on
191
pcbc_doc_id_search_query_init(zval * return_value,zval * args,int num_args TSRMLS_DC)192 void pcbc_doc_id_search_query_init(zval *return_value,
193 #if PHP_VERSION_ID >= 70000
194 zval *args,
195 #else
196 zval ***args,
197 #endif
198 int num_args TSRMLS_DC)
199 {
200 pcbc_doc_id_search_query_t *obj;
201
202 object_init_ex(return_value, pcbc_doc_id_search_query_ce);
203 obj = Z_DOC_ID_SEARCH_QUERY_OBJ_P(return_value);
204 obj->boost = -1;
205 obj->field = NULL;
206
207 PCBC_ZVAL_ALLOC(obj->doc_ids);
208 array_init(PCBC_P(obj->doc_ids));
209
210 if (num_args && args) {
211 int i;
212 for (i = 0; i < num_args; ++i) {
213 PCBC_ZVAL *id;
214 #if PHP_VERSION_ID >= 70000
215 id = &args[i];
216 #else
217 id = args[i];
218 #endif
219 if (Z_TYPE_P(PCBC_P(*id)) != IS_STRING) {
220 pcbc_log(LOGARGS(WARN), "id has to be a string (skipping argument #%d)", i);
221 continue;
222 }
223 add_next_index_zval(PCBC_P(obj->doc_ids), PCBC_P(*id));
224 PCBC_ADDREF_P(PCBC_P(*id));
225 }
226 }
227 }
228
229 zend_object_handlers doc_id_search_query_handlers;
230
doc_id_search_query_free_object(pcbc_free_object_arg * object TSRMLS_DC)231 static void doc_id_search_query_free_object(pcbc_free_object_arg *object TSRMLS_DC) /* {{{ */
232 {
233 pcbc_doc_id_search_query_t *obj = Z_DOC_ID_SEARCH_QUERY_OBJ(object);
234
235 if (obj->field != NULL) {
236 efree(obj->field);
237 }
238 zval_ptr_dtor(&obj->doc_ids);
239
240 zend_object_std_dtor(&obj->std TSRMLS_CC);
241 #if PHP_VERSION_ID < 70000
242 efree(obj);
243 #endif
244 } /* }}} */
245
doc_id_search_query_create_object(zend_class_entry * class_type TSRMLS_DC)246 static pcbc_create_object_retval doc_id_search_query_create_object(zend_class_entry *class_type TSRMLS_DC)
247 {
248 pcbc_doc_id_search_query_t *obj = NULL;
249
250 obj = PCBC_ALLOC_OBJECT_T(pcbc_doc_id_search_query_t, class_type);
251
252 zend_object_std_init(&obj->std, class_type TSRMLS_CC);
253 object_properties_init(&obj->std, class_type);
254
255 #if PHP_VERSION_ID >= 70000
256 obj->std.handlers = &doc_id_search_query_handlers;
257 return &obj->std;
258 #else
259 {
260 zend_object_value ret;
261 ret.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object,
262 doc_id_search_query_free_object, NULL TSRMLS_CC);
263 ret.handlers = &doc_id_search_query_handlers;
264 return ret;
265 }
266 #endif
267 }
268
pcbc_doc_id_search_query_get_debug_info(zval * object,int * is_temp TSRMLS_DC)269 static HashTable *pcbc_doc_id_search_query_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
270 {
271 pcbc_doc_id_search_query_t *obj = NULL;
272 #if PHP_VERSION_ID >= 70000
273 zval retval;
274 #else
275 zval retval = zval_used_for_init;
276 #endif
277
278 *is_temp = 1;
279 obj = Z_DOC_ID_SEARCH_QUERY_OBJ_P(object);
280
281 array_init(&retval);
282 ADD_ASSOC_ZVAL_EX(&retval, "ids", PCBC_P(obj->doc_ids));
283 PCBC_ADDREF_P(PCBC_P(obj->doc_ids));
284 if (obj->field) {
285 ADD_ASSOC_STRING(&retval, "field", obj->field);
286 }
287 if (obj->boost >= 0) {
288 ADD_ASSOC_DOUBLE_EX(&retval, "boost", obj->boost);
289 }
290 return Z_ARRVAL(retval);
291 } /* }}} */
292
PHP_MINIT_FUNCTION(DocIdSearchQuery)293 PHP_MINIT_FUNCTION(DocIdSearchQuery)
294 {
295 zend_class_entry ce;
296
297 INIT_NS_CLASS_ENTRY(ce, "Couchbase", "DocIdSearchQuery", doc_id_search_query_methods);
298 pcbc_doc_id_search_query_ce = zend_register_internal_class(&ce TSRMLS_CC);
299 pcbc_doc_id_search_query_ce->create_object = doc_id_search_query_create_object;
300 PCBC_CE_DISABLE_SERIALIZATION(pcbc_doc_id_search_query_ce);
301
302 zend_class_implements(pcbc_doc_id_search_query_ce TSRMLS_CC, 1, pcbc_json_serializable_ce);
303 zend_class_implements(pcbc_doc_id_search_query_ce TSRMLS_CC, 1, pcbc_search_query_part_ce);
304
305 memcpy(&doc_id_search_query_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
306 doc_id_search_query_handlers.get_debug_info = pcbc_doc_id_search_query_get_debug_info;
307 #if PHP_VERSION_ID >= 70000
308 doc_id_search_query_handlers.free_obj = doc_id_search_query_free_object;
309 doc_id_search_query_handlers.offset = XtOffsetOf(pcbc_doc_id_search_query_t, std);
310 #endif
311
312 zend_register_class_alias("\\CouchbaseDocIdSearchQuery", pcbc_doc_id_search_query_ce);
313 return SUCCESS;
314 }
315