1 | /* -*- c-basic-offset: 2 -*- */ |
2 | /* |
3 | Copyright(C) 2015 Brazil |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License version 2.1 as published by the Free Software Foundation. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with this library; if not, write to the Free Software |
16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
17 | */ |
18 | |
19 | #include "ts_expr_builder.h" |
20 | |
21 | #include <string.h> |
22 | |
23 | #include "../grn_ctx.h" |
24 | #include "../grn_db.h" |
25 | |
26 | #include "ts_log.h" |
27 | #include "ts_util.h" |
28 | |
29 | /*------------------------------------------------------------- |
30 | * grn_ts_expr_bridge. |
31 | */ |
32 | |
33 | /* grn_ts_expr_bridge_init() initializes a bridge. */ |
34 | static void |
35 | grn_ts_expr_bridge_init(grn_ctx *ctx, grn_ts_expr_bridge *bridge) |
36 | { |
37 | memset(bridge, 0, sizeof(*bridge)); |
38 | bridge->src_table = NULL; |
39 | bridge->dest_table = NULL; |
40 | } |
41 | |
42 | /* grn_ts_expr_bridge_fin() finalizes a bridge. */ |
43 | static void |
44 | grn_ts_expr_bridge_fin(grn_ctx *ctx, grn_ts_expr_bridge *bridge) |
45 | { |
46 | if (bridge->dest_table) { |
47 | grn_obj_unlink(ctx, bridge->dest_table); |
48 | } |
49 | /* Note: bridge->src_table does not increment a reference count. */ |
50 | } |
51 | |
52 | /*------------------------------------------------------------- |
53 | * grn_ts_expr_builder. |
54 | */ |
55 | |
56 | /* grn_ts_expr_builder_init() initializes an expression builder. */ |
57 | static void |
58 | grn_ts_expr_builder_init(grn_ctx *ctx, grn_ts_expr_builder *builder) |
59 | { |
60 | memset(builder, 0, sizeof(*builder)); |
61 | builder->table = NULL; |
62 | builder->curr_table = NULL; |
63 | builder->nodes = NULL; |
64 | builder->bridges = NULL; |
65 | } |
66 | |
67 | /* grn_ts_expr_builder_fin() finalizes an expression builder. */ |
68 | static void |
69 | grn_ts_expr_builder_fin(grn_ctx *ctx, grn_ts_expr_builder *builder) |
70 | { |
71 | size_t i; |
72 | if (builder->bridges) { |
73 | for (i = 0; i < builder->n_bridges; i++) { |
74 | grn_ts_expr_bridge_fin(ctx, &builder->bridges[i]); |
75 | } |
76 | GRN_FREE(builder->bridges); |
77 | } |
78 | if (builder->nodes) { |
79 | for (i = 0; i < builder->n_nodes; i++) { |
80 | if (builder->nodes[i]) { |
81 | grn_ts_expr_node_close(ctx, builder->nodes[i]); |
82 | } |
83 | } |
84 | GRN_FREE(builder->nodes); |
85 | } |
86 | /* Note: builder->curr_table does not increment a reference count. */ |
87 | if (builder->table) { |
88 | grn_obj_unlink(ctx, builder->table); |
89 | } |
90 | } |
91 | |
92 | grn_rc |
93 | grn_ts_expr_builder_open(grn_ctx *ctx, grn_obj *table, |
94 | grn_ts_expr_builder **builder) |
95 | { |
96 | grn_rc rc; |
97 | grn_ts_expr_builder *new_builder; |
98 | if (!ctx) { |
99 | return GRN_INVALID_ARGUMENT; |
100 | } |
101 | if (!table || !grn_ts_obj_is_table(ctx, table) || !builder) { |
102 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
103 | } |
104 | new_builder = GRN_MALLOCN(grn_ts_expr_builder, 1); |
105 | if (!new_builder) { |
106 | GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, |
107 | "GRN_MALLOCN failed: %" GRN_FMT_SIZE, |
108 | sizeof(grn_ts_expr_builder)); |
109 | } |
110 | rc = grn_ts_obj_increment_ref_count(ctx, table); |
111 | if (rc != GRN_SUCCESS) { |
112 | GRN_FREE(new_builder); |
113 | return rc; |
114 | } |
115 | grn_ts_expr_builder_init(ctx, new_builder); |
116 | new_builder->table = table; |
117 | new_builder->curr_table = table; |
118 | *builder = new_builder; |
119 | return GRN_SUCCESS; |
120 | } |
121 | |
122 | grn_rc |
123 | grn_ts_expr_builder_close(grn_ctx *ctx, grn_ts_expr_builder *builder) |
124 | { |
125 | if (!ctx) { |
126 | return GRN_INVALID_ARGUMENT; |
127 | } |
128 | if (!builder) { |
129 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
130 | } |
131 | grn_ts_expr_builder_fin(ctx, builder); |
132 | GRN_FREE(builder); |
133 | return GRN_SUCCESS; |
134 | } |
135 | |
136 | grn_rc |
137 | grn_ts_expr_builder_complete(grn_ctx *ctx, grn_ts_expr_builder *builder, |
138 | grn_ts_expr **expr) |
139 | { |
140 | grn_rc rc; |
141 | grn_ts_expr *new_expr; |
142 | if (!ctx) { |
143 | return GRN_INVALID_ARGUMENT; |
144 | } |
145 | if (!builder || (builder->n_nodes != 1) || builder->n_bridges || !expr) { |
146 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
147 | } |
148 | rc = grn_ts_expr_node_deref(ctx, &builder->nodes[0]); |
149 | if (rc != GRN_SUCCESS) { |
150 | return rc; |
151 | } |
152 | rc = grn_ts_expr_open(ctx, builder->table, builder->nodes[0], &new_expr); |
153 | if (rc != GRN_SUCCESS) { |
154 | return rc; |
155 | } |
156 | builder->n_nodes = 0; |
157 | *expr = new_expr; |
158 | return GRN_SUCCESS; |
159 | } |
160 | |
161 | grn_rc |
162 | grn_ts_expr_builder_clear(grn_ctx *ctx, grn_ts_expr_builder *builder) |
163 | { |
164 | size_t i; |
165 | if (!ctx) { |
166 | return GRN_INVALID_ARGUMENT; |
167 | } |
168 | if (!builder) { |
169 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
170 | } |
171 | if (builder->bridges) { |
172 | for (i = 0; i < builder->n_bridges; i++) { |
173 | grn_ts_expr_bridge_fin(ctx, &builder->bridges[i]); |
174 | } |
175 | builder->n_bridges = 0; |
176 | } |
177 | if (builder->nodes) { |
178 | for (i = 0; i < builder->n_nodes; i++) { |
179 | if (builder->nodes[i]) { |
180 | grn_ts_expr_node_close(ctx, builder->nodes[i]); |
181 | } |
182 | } |
183 | builder->n_nodes = 0; |
184 | } |
185 | builder->curr_table = builder->table; |
186 | return GRN_SUCCESS; |
187 | } |
188 | |
189 | /* |
190 | * grn_ts_expr_builder_push_node() pushes a node. |
191 | * The given node will be closed on failure. |
192 | */ |
193 | static grn_rc |
194 | grn_ts_expr_builder_push_node(grn_ctx *ctx, grn_ts_expr_builder *builder, |
195 | grn_ts_expr_node *node) |
196 | { |
197 | if (builder->n_nodes == builder->max_n_nodes) { |
198 | size_t n_bytes, new_max_n_nodes; |
199 | grn_ts_expr_node **new_nodes; |
200 | new_max_n_nodes = builder->n_nodes ? (builder->n_nodes * 2) : 1; |
201 | n_bytes = sizeof(grn_ts_expr_node *) * new_max_n_nodes; |
202 | new_nodes = (grn_ts_expr_node **)GRN_REALLOC(builder->nodes, n_bytes); |
203 | if (!new_nodes) { |
204 | grn_ts_expr_node_close(ctx, node); |
205 | GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, |
206 | "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes); |
207 | } |
208 | builder->nodes = new_nodes; |
209 | builder->max_n_nodes = new_max_n_nodes; |
210 | } |
211 | builder->nodes[builder->n_nodes++] = node; |
212 | return GRN_SUCCESS; |
213 | } |
214 | |
215 | grn_rc |
216 | grn_ts_expr_builder_push_name(grn_ctx *ctx, grn_ts_expr_builder *builder, |
217 | grn_ts_str name) |
218 | { |
219 | grn_obj *column; |
220 | if (!ctx) { |
221 | return GRN_INVALID_ARGUMENT; |
222 | } |
223 | if (!builder || !grn_ts_str_is_name(name)) { |
224 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
225 | } |
226 | if (grn_ts_str_is_id_name(name)) { |
227 | return grn_ts_expr_builder_push_id(ctx, builder); |
228 | } |
229 | if (grn_ts_str_is_score_name(name)) { |
230 | return grn_ts_expr_builder_push_score(ctx, builder); |
231 | } |
232 | if (grn_ts_str_is_key_name(name)) { |
233 | return grn_ts_expr_builder_push_key(ctx, builder); |
234 | } |
235 | if (grn_ts_str_is_value_name(name)) { |
236 | return grn_ts_expr_builder_push_value(ctx, builder); |
237 | } |
238 | /* grn_obj_column() returns a column or accessor. */ |
239 | column = grn_obj_column(ctx, builder->curr_table, name.ptr, name.size); |
240 | if (!column) { |
241 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "object not found: \"%.*s\"" , |
242 | (int)name.size, name.ptr); |
243 | } |
244 | return grn_ts_expr_builder_push_obj(ctx, builder, column); |
245 | } |
246 | |
247 | #define GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(TYPE, KIND, kind)\ |
248 | case GRN_DB_ ## TYPE: {\ |
249 | value.as_ ## kind = (grn_ts_ ## kind)GRN_ ## TYPE ## _VALUE(obj);\ |
250 | return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\ |
251 | obj->header.domain, value);\ |
252 | } |
253 | /* grn_ts_expr_push_builder_bulk() pushes a scalar const. */ |
254 | static grn_rc |
255 | grn_ts_expr_builder_push_bulk(grn_ctx *ctx, grn_ts_expr_builder *builder, |
256 | grn_obj *obj) |
257 | { |
258 | grn_ts_any value; |
259 | switch (obj->header.domain) { |
260 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(BOOL, BOOL, bool) |
261 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT8, INT, int) |
262 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT16, INT, int) |
263 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT32, INT, int) |
264 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT64, INT, int) |
265 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT8, INT, int) |
266 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT16, INT, int) |
267 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT32, INT, int) |
268 | /* The behavior is undefined if a value is greater than 2^63 - 1. */ |
269 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT64, INT, int) |
270 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(FLOAT, FLOAT, float) |
271 | GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(TIME, TIME, time) |
272 | case GRN_DB_SHORT_TEXT: |
273 | case GRN_DB_TEXT: |
274 | case GRN_DB_LONG_TEXT: { |
275 | value.as_text.ptr = GRN_TEXT_VALUE(obj); |
276 | value.as_text.size = GRN_TEXT_LEN(obj); |
277 | return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_TEXT, |
278 | obj->header.domain, value); |
279 | } |
280 | case GRN_DB_TOKYO_GEO_POINT: |
281 | case GRN_DB_WGS84_GEO_POINT: { |
282 | GRN_GEO_POINT_VALUE(obj, value.as_geo.latitude, value.as_geo.longitude); |
283 | return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_GEO, |
284 | obj->header.domain, value); |
285 | } |
286 | default: { |
287 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "not bulk" ); |
288 | } |
289 | } |
290 | } |
291 | #undef GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE |
292 | |
293 | #define GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(TYPE, KIND, kind)\ |
294 | case GRN_DB_ ## TYPE: {\ |
295 | value.as_ ## kind ## _vector.ptr = (grn_ts_ ## kind *)GRN_BULK_HEAD(obj);\ |
296 | value.as_ ## kind ## _vector.size = grn_uvector_size(ctx, obj);\ |
297 | return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\ |
298 | obj->header.domain, value);\ |
299 | } |
300 | #define GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(TYPE, KIND, kind)\ |
301 | case GRN_DB_ ## TYPE: {\ |
302 | size_t i;\ |
303 | grn_rc rc;\ |
304 | grn_ts_ ## kind *buf;\ |
305 | grn_ts_ ## kind ## _vector vector = { NULL, grn_uvector_size(ctx, obj) };\ |
306 | if (!vector.size) {\ |
307 | value.as_ ## kind ## _vector = vector;\ |
308 | return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\ |
309 | obj->header.domain, value);\ |
310 | }\ |
311 | buf = GRN_MALLOCN(grn_ts_ ## kind, vector.size);\ |
312 | if (!buf) {\ |
313 | GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,\ |
314 | "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",\ |
315 | sizeof(grn_ts_ ## kind));\ |
316 | }\ |
317 | for (i = 0; i < vector.size; i++) {\ |
318 | buf[i] = GRN_ ## TYPE ##_VALUE_AT(obj, i);\ |
319 | }\ |
320 | vector.ptr = buf;\ |
321 | value.as_ ## kind ## _vector = vector;\ |
322 | rc = grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\ |
323 | obj->header.domain, value);\ |
324 | GRN_FREE(buf);\ |
325 | return rc;\ |
326 | } |
327 | /* grn_ts_expr_builder_push_uvector() pushes an array of fixed-size values. */ |
328 | static grn_rc |
329 | grn_ts_expr_builder_push_uvector(grn_ctx *ctx, grn_ts_expr_builder *builder, |
330 | grn_obj *obj) |
331 | { |
332 | grn_ts_any value; |
333 | switch (obj->header.domain) { |
334 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(BOOL, BOOL, bool) |
335 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT8, INT, int) |
336 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT16, INT, int) |
337 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT32, INT, int) |
338 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(INT64, INT, int) |
339 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT8, INT, int) |
340 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT16, INT, int) |
341 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT32, INT, int) |
342 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(UINT64, INT, int) |
343 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(TIME, TIME, time) |
344 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(TOKYO_GEO_POINT, GEO, geo) |
345 | GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(WGS84_GEO_POINT, GEO, geo) |
346 | default: { |
347 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data type: %d" , |
348 | obj->header.domain); |
349 | } |
350 | } |
351 | } |
352 | #undef GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST |
353 | #undef GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE |
354 | |
355 | /* grn_ts_expr_builder_push_vector() pushes a Text vector. */ |
356 | static grn_rc |
357 | grn_ts_expr_builder_push_vector(grn_ctx *ctx, grn_ts_expr_builder *builder, |
358 | grn_obj *obj) |
359 | { |
360 | switch (obj->header.domain) { |
361 | case GRN_DB_SHORT_TEXT: |
362 | case GRN_DB_TEXT: |
363 | case GRN_DB_LONG_TEXT: { |
364 | size_t i; |
365 | grn_rc rc; |
366 | grn_ts_any value; |
367 | grn_ts_text *buf; |
368 | grn_ts_text_vector vector = { NULL, grn_vector_size(ctx, obj) }; |
369 | if (!vector.size) { |
370 | value.as_text_vector = vector; |
371 | return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_TEXT_VECTOR, |
372 | obj->header.domain, value); |
373 | } |
374 | buf = GRN_MALLOCN(grn_ts_text, vector.size); |
375 | if (!buf) { |
376 | GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, |
377 | "GRN_MALLOCN failed: " |
378 | "%" GRN_FMT_SIZE " x %" GRN_FMT_SIZE, |
379 | sizeof(grn_ts_text), vector.size); |
380 | } |
381 | for (i = 0; i < vector.size; i++) { |
382 | buf[i].size = grn_vector_get_element(ctx, obj, i, &buf[i].ptr, |
383 | NULL, NULL); |
384 | } |
385 | vector.ptr = buf; |
386 | value.as_text_vector = vector; |
387 | rc = grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_TEXT_VECTOR, |
388 | obj->header.domain, value); |
389 | GRN_FREE(buf); |
390 | return rc; |
391 | } |
392 | default: { |
393 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data type: %d" , |
394 | obj->header.domain); |
395 | } |
396 | } |
397 | } |
398 | |
399 | static grn_rc |
400 | grn_ts_expr_builder_push_single_accessor(grn_ctx *ctx, |
401 | grn_ts_expr_builder *builder, |
402 | grn_accessor *accessor) |
403 | { |
404 | switch (accessor->action) { |
405 | case GRN_ACCESSOR_GET_ID: { |
406 | return grn_ts_expr_builder_push_id(ctx, builder); |
407 | } |
408 | case GRN_ACCESSOR_GET_SCORE: { |
409 | return grn_ts_expr_builder_push_score(ctx, builder); |
410 | } |
411 | case GRN_ACCESSOR_GET_KEY: { |
412 | if (accessor->obj != builder->curr_table) { |
413 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table conflict" ); |
414 | } |
415 | return grn_ts_expr_builder_push_key(ctx, builder); |
416 | } |
417 | case GRN_ACCESSOR_GET_VALUE: { |
418 | if (accessor->obj != builder->curr_table) { |
419 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table conflict" ); |
420 | } |
421 | return grn_ts_expr_builder_push_value(ctx, builder); |
422 | } |
423 | case GRN_ACCESSOR_GET_COLUMN_VALUE: { |
424 | return grn_ts_expr_builder_push_column(ctx, builder, accessor->obj); |
425 | } |
426 | default: { |
427 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid accessor action: %d" , |
428 | accessor->action); |
429 | } |
430 | } |
431 | } |
432 | |
433 | static grn_rc |
434 | grn_ts_expr_builder_push_accessor(grn_ctx *ctx, grn_ts_expr_builder *builder, |
435 | grn_accessor *accessor) |
436 | { |
437 | grn_rc rc = grn_ts_expr_builder_push_single_accessor(ctx, builder, accessor); |
438 | if (rc != GRN_SUCCESS) { |
439 | return rc; |
440 | } |
441 | for (accessor = accessor->next; accessor; accessor = accessor->next) { |
442 | rc = grn_ts_expr_builder_begin_subexpr(ctx, builder); |
443 | if (rc != GRN_SUCCESS) { |
444 | return rc; |
445 | } |
446 | rc = grn_ts_expr_builder_push_single_accessor(ctx, builder, accessor); |
447 | if (rc != GRN_SUCCESS) { |
448 | return rc; |
449 | } |
450 | rc = grn_ts_expr_builder_end_subexpr(ctx, builder); |
451 | if (rc != GRN_SUCCESS) { |
452 | return rc; |
453 | } |
454 | } |
455 | return GRN_SUCCESS; |
456 | } |
457 | |
458 | grn_rc |
459 | grn_ts_expr_builder_push_obj(grn_ctx *ctx, grn_ts_expr_builder *builder, |
460 | grn_obj *obj) |
461 | { |
462 | if (!ctx) { |
463 | return GRN_INVALID_ARGUMENT; |
464 | } |
465 | if (!builder || !obj) { |
466 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
467 | } |
468 | switch (obj->header.type) { |
469 | case GRN_BULK: { |
470 | return grn_ts_expr_builder_push_bulk(ctx, builder, obj); |
471 | } |
472 | case GRN_UVECTOR: { |
473 | return grn_ts_expr_builder_push_uvector(ctx, builder, obj); |
474 | } |
475 | case GRN_VECTOR: { |
476 | return grn_ts_expr_builder_push_vector(ctx, builder, obj); |
477 | } |
478 | case GRN_ACCESSOR: { |
479 | return grn_ts_expr_builder_push_accessor(ctx, builder, |
480 | (grn_accessor *)obj); |
481 | } |
482 | case GRN_COLUMN_FIX_SIZE: |
483 | case GRN_COLUMN_VAR_SIZE: { |
484 | return grn_ts_expr_builder_push_column(ctx, builder, obj); |
485 | } |
486 | default: { |
487 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid object type: %d" , |
488 | obj->header.type); |
489 | } |
490 | } |
491 | } |
492 | |
493 | grn_rc |
494 | grn_ts_expr_builder_push_id(grn_ctx *ctx, grn_ts_expr_builder *builder) |
495 | { |
496 | grn_rc rc; |
497 | grn_ts_expr_node *node; |
498 | if (!ctx) { |
499 | return GRN_INVALID_ARGUMENT; |
500 | } |
501 | if (!builder) { |
502 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
503 | } |
504 | rc = grn_ts_expr_id_node_open(ctx, &node); |
505 | if (rc == GRN_SUCCESS) { |
506 | rc = grn_ts_expr_builder_push_node(ctx, builder, node); |
507 | } |
508 | return rc; |
509 | } |
510 | |
511 | grn_rc |
512 | grn_ts_expr_builder_push_score(grn_ctx *ctx, grn_ts_expr_builder *builder) |
513 | { |
514 | grn_rc rc; |
515 | grn_ts_expr_node *node; |
516 | if (!ctx) { |
517 | return GRN_INVALID_ARGUMENT; |
518 | } |
519 | if (!builder) { |
520 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
521 | } |
522 | rc = grn_ts_expr_score_node_open(ctx, &node); |
523 | if (rc == GRN_SUCCESS) { |
524 | rc = grn_ts_expr_builder_push_node(ctx, builder, node); |
525 | } |
526 | return rc; |
527 | } |
528 | |
529 | grn_rc |
530 | grn_ts_expr_builder_push_key(grn_ctx *ctx, grn_ts_expr_builder *builder) |
531 | { |
532 | grn_rc rc; |
533 | grn_ts_expr_node *node; |
534 | if (!ctx) { |
535 | return GRN_INVALID_ARGUMENT; |
536 | } |
537 | if (!builder) { |
538 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
539 | } |
540 | rc = grn_ts_expr_key_node_open(ctx, builder->curr_table, &node); |
541 | if (rc == GRN_SUCCESS) { |
542 | rc = grn_ts_expr_builder_push_node(ctx, builder, node); |
543 | } |
544 | return rc; |
545 | } |
546 | |
547 | grn_rc |
548 | grn_ts_expr_builder_push_value(grn_ctx *ctx, grn_ts_expr_builder *builder) |
549 | { |
550 | grn_rc rc; |
551 | grn_ts_expr_node *node; |
552 | if (!ctx) { |
553 | return GRN_INVALID_ARGUMENT; |
554 | } |
555 | if (!builder) { |
556 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
557 | } |
558 | rc = grn_ts_expr_value_node_open(ctx, builder->curr_table, &node); |
559 | if (rc == GRN_SUCCESS) { |
560 | rc = grn_ts_expr_builder_push_node(ctx, builder, node); |
561 | } |
562 | return rc; |
563 | } |
564 | |
565 | grn_rc |
566 | grn_ts_expr_builder_push_const(grn_ctx *ctx, grn_ts_expr_builder *builder, |
567 | grn_ts_data_kind kind, grn_ts_data_type type, |
568 | grn_ts_any value) |
569 | { |
570 | grn_rc rc; |
571 | grn_ts_expr_node *node; |
572 | if (!ctx) { |
573 | return GRN_INVALID_ARGUMENT; |
574 | } |
575 | if (!builder) { |
576 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
577 | } |
578 | rc = grn_ts_expr_const_node_open(ctx, kind, type, value, &node); |
579 | if (rc == GRN_SUCCESS) { |
580 | rc = grn_ts_expr_builder_push_node(ctx, builder, node); |
581 | } |
582 | return rc; |
583 | } |
584 | |
585 | grn_rc |
586 | grn_ts_expr_builder_push_column(grn_ctx *ctx, grn_ts_expr_builder *builder, |
587 | grn_obj *column) |
588 | { |
589 | grn_rc rc; |
590 | grn_ts_expr_node *node; |
591 | if (!ctx) { |
592 | return GRN_INVALID_ARGUMENT; |
593 | } |
594 | if (!builder || !column || !grn_ts_obj_is_column(ctx, column) || |
595 | (DB_OBJ(builder->curr_table)->id != column->header.domain)) { |
596 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
597 | } |
598 | rc = grn_ts_expr_column_node_open(ctx, column, &node); |
599 | if (rc == GRN_SUCCESS) { |
600 | rc = grn_ts_expr_builder_push_node(ctx, builder, node); |
601 | } |
602 | return rc; |
603 | } |
604 | |
605 | /* |
606 | * grn_ts_expr_builder_get_max_n_args() returns the number of nodes in the |
607 | * current subexpression. |
608 | */ |
609 | static size_t |
610 | grn_ts_expr_builder_get_max_n_args(grn_ctx *ctx, grn_ts_expr_builder *builder) |
611 | { |
612 | size_t max_n_args = builder->n_nodes; |
613 | if (builder->n_bridges) { |
614 | max_n_args -= builder->bridges[builder->n_bridges - 1].n_nodes; |
615 | } |
616 | return max_n_args; |
617 | } |
618 | |
619 | grn_rc |
620 | grn_ts_expr_builder_push_op(grn_ctx *ctx, grn_ts_expr_builder *builder, |
621 | grn_ts_op_type op_type) |
622 | { |
623 | grn_rc rc; |
624 | grn_ts_expr_node **args, *node; |
625 | size_t n_args, max_n_args; |
626 | if (!ctx) { |
627 | return GRN_INVALID_ARGUMENT; |
628 | } |
629 | if (!builder) { |
630 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
631 | } |
632 | n_args = grn_ts_op_get_n_args(op_type); |
633 | if (!n_args) { |
634 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, |
635 | "invalid #arguments: %" GRN_FMT_SIZE, |
636 | n_args); |
637 | } |
638 | max_n_args = grn_ts_expr_builder_get_max_n_args(ctx, builder); |
639 | if (n_args > max_n_args) { |
640 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, |
641 | "invalid #arguments: %" GRN_FMT_SIZE ", %" GRN_FMT_SIZE, |
642 | n_args, builder->n_nodes); |
643 | } |
644 | /* Arguments are the top n_args nodes in the stack. */ |
645 | args = &builder->nodes[builder->n_nodes - n_args]; |
646 | builder->n_nodes -= n_args; |
647 | rc = grn_ts_expr_op_node_open(ctx, op_type, args, n_args, &node); |
648 | if (rc == GRN_SUCCESS) { |
649 | builder->nodes[builder->n_nodes++] = node; |
650 | } |
651 | return rc; |
652 | } |
653 | |
654 | /* grn_ts_expr_builder_push_bridge() pushes a bridge. */ |
655 | static grn_rc |
656 | grn_ts_expr_builder_push_bridge(grn_ctx *ctx, grn_ts_expr_builder *builder, |
657 | grn_ts_expr_bridge *bridge) |
658 | { |
659 | if (builder->n_bridges == builder->max_n_bridges) { |
660 | size_t n_bytes, new_max_n_bridges; |
661 | grn_ts_expr_bridge *new_bridges; |
662 | new_max_n_bridges = builder->n_bridges ? (builder->n_bridges * 2) : 1; |
663 | n_bytes = sizeof(grn_ts_expr_bridge) * new_max_n_bridges; |
664 | new_bridges = (grn_ts_expr_bridge *)GRN_REALLOC(builder->bridges, n_bytes); |
665 | if (!new_bridges) { |
666 | grn_ts_expr_bridge_fin(ctx, bridge); |
667 | GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE, |
668 | "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes); |
669 | } |
670 | builder->bridges = new_bridges; |
671 | builder->max_n_bridges = new_max_n_bridges; |
672 | } |
673 | builder->bridges[builder->n_bridges++] = *bridge; |
674 | builder->curr_table = bridge->dest_table; |
675 | return GRN_SUCCESS; |
676 | } |
677 | |
678 | /* grn_ts_expr_builder_pop_bridge() pops a bridge. */ |
679 | static void |
680 | grn_ts_expr_builder_pop_bridge(grn_ctx *ctx, grn_ts_expr_builder *builder) |
681 | { |
682 | grn_ts_expr_bridge *bridge = &builder->bridges[builder->n_bridges - 1]; |
683 | builder->curr_table = bridge->src_table; |
684 | grn_ts_expr_bridge_fin(ctx, bridge); |
685 | builder->n_bridges--; |
686 | } |
687 | |
688 | grn_rc |
689 | grn_ts_expr_builder_begin_subexpr(grn_ctx *ctx, grn_ts_expr_builder *builder) |
690 | { |
691 | grn_rc rc; |
692 | size_t max_n_args; |
693 | grn_obj *obj; |
694 | grn_ts_expr_node *node; |
695 | grn_ts_expr_bridge bridge; |
696 | if (!ctx) { |
697 | return GRN_INVALID_ARGUMENT; |
698 | } |
699 | if (!builder) { |
700 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
701 | } |
702 | max_n_args = grn_ts_expr_builder_get_max_n_args(ctx, builder); |
703 | if (!max_n_args) { |
704 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
705 | } |
706 | /* Check whehter or not the latest node refers to a table. */ |
707 | node = builder->nodes[builder->n_nodes - 1]; |
708 | if ((node->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) { |
709 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d" , |
710 | node->data_kind); |
711 | } |
712 | obj = grn_ctx_at(ctx, node->data_type); |
713 | if (!obj) { |
714 | GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d" , |
715 | node->data_type); |
716 | } |
717 | if (!grn_ts_obj_is_table(ctx, obj)) { |
718 | grn_obj_unlink(ctx, obj); |
719 | GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d" , node->data_type); |
720 | } |
721 | /* Creates a bridge to a subexpression. */ |
722 | grn_ts_expr_bridge_init(ctx, &bridge); |
723 | bridge.src_table = builder->curr_table; |
724 | bridge.dest_table = obj; |
725 | bridge.n_nodes = builder->n_nodes; |
726 | rc = grn_ts_expr_builder_push_bridge(ctx, builder, &bridge); |
727 | if (rc != GRN_SUCCESS) { |
728 | grn_obj_unlink(ctx, obj); |
729 | return rc; |
730 | } |
731 | return GRN_SUCCESS; |
732 | } |
733 | |
734 | grn_rc |
735 | grn_ts_expr_builder_end_subexpr(grn_ctx *ctx, grn_ts_expr_builder *builder) |
736 | { |
737 | grn_rc rc; |
738 | grn_ts_expr_node **args, *node; |
739 | if (!ctx || !builder || (builder->n_nodes < 2) || !builder->n_bridges) { |
740 | return GRN_INVALID_ARGUMENT; |
741 | } |
742 | /* Check whehter or not the subexpression is complete.*/ |
743 | if (grn_ts_expr_builder_get_max_n_args(ctx, builder) != 1) { |
744 | GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument" ); |
745 | } |
746 | /* Creates a bridge node. */ |
747 | args = &builder->nodes[builder->n_nodes - 2]; |
748 | rc = grn_ts_expr_bridge_node_open(ctx, args[0], args[1], &node); |
749 | if (rc != GRN_SUCCESS) { |
750 | return rc; |
751 | } |
752 | /* Note: The following grn_ts_expr_push_node() must not fail. */ |
753 | builder->n_nodes -= 2; |
754 | grn_ts_expr_builder_push_node(ctx, builder, node); |
755 | grn_ts_expr_builder_pop_bridge(ctx, builder); |
756 | return GRN_SUCCESS; |
757 | } |
758 | |