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. */
34static void
35grn_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. */
43static void
44grn_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. */
57static void
58grn_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. */
68static void
69grn_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
92grn_rc
93grn_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
122grn_rc
123grn_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
136grn_rc
137grn_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
161grn_rc
162grn_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 */
193static grn_rc
194grn_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
215grn_rc
216grn_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. */
254static grn_rc
255grn_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. */
328static grn_rc
329grn_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. */
356static grn_rc
357grn_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
399static grn_rc
400grn_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
433static grn_rc
434grn_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
458grn_rc
459grn_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
493grn_rc
494grn_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
511grn_rc
512grn_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
529grn_rc
530grn_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
547grn_rc
548grn_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
565grn_rc
566grn_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
585grn_rc
586grn_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 */
609static size_t
610grn_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
619grn_rc
620grn_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. */
655static grn_rc
656grn_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. */
679static void
680grn_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
688grn_rc
689grn_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
734grn_rc
735grn_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