1/* -*- c-basic-offset: 2 -*- */
2/* Copyright(C) 2009-2015 Brazil
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License version 2.1 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Lesser General Public License for more details.
12
13 You should have received a copy of the GNU Lesser General Public
14 License along with this library; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16*/
17
18#include "grn.h"
19
20#include <string.h>
21#include "grn_str.h"
22#include "grn_db.h"
23#include "grn_expr_code.h"
24#include "grn_util.h"
25#include "grn_output.h"
26
27#define LEVELS (&ctx->impl->output.levels)
28#define DEPTH (GRN_BULK_VSIZE(LEVELS)>>2)
29#define CURR_LEVEL (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1))) : 0)
30#define INCR_DEPTH(i) GRN_UINT32_PUT(ctx, LEVELS, i)
31#define DECR_DEPTH (DEPTH ? grn_bulk_truncate(ctx, LEVELS, GRN_BULK_VSIZE(LEVELS) - sizeof(uint32_t)) : 0)
32#define INCR_LENGTH (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1)) += 2) : 0)
33
34static void
35indent(grn_ctx *ctx, grn_obj *outbuf, size_t level)
36{
37 size_t i;
38 for (i = 0; i < level; i++) {
39 GRN_TEXT_PUTS(ctx, outbuf, " ");
40 }
41}
42
43static void
44json_array_open(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
45{
46 GRN_TEXT_PUTC(ctx, outbuf, '[');
47 if (ctx->impl->output.is_pretty) {
48 GRN_TEXT_PUTC(ctx, outbuf, '\n');
49 (*indent_level)++;
50 indent(ctx, outbuf, *indent_level);
51 }
52}
53
54static void
55json_array_close(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
56{
57 if (ctx->impl->output.is_pretty) {
58 GRN_TEXT_PUTC(ctx, outbuf, '\n');
59 (*indent_level)--;
60 indent(ctx, outbuf, *indent_level);
61 }
62 GRN_TEXT_PUTC(ctx, outbuf, ']');
63}
64
65static void
66json_element_end(grn_ctx *ctx, grn_obj *outbuf, size_t indent_level)
67{
68 GRN_TEXT_PUTC(ctx, outbuf, ',');
69 if (ctx->impl->output.is_pretty) {
70 GRN_TEXT_PUTC(ctx, outbuf, '\n');
71 indent(ctx, outbuf, indent_level);
72 }
73}
74
75static void
76json_map_open(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
77{
78 GRN_TEXT_PUTC(ctx, outbuf, '{');
79 if (ctx->impl->output.is_pretty) {
80 GRN_TEXT_PUTC(ctx, outbuf, '\n');
81 (*indent_level)++;
82 indent(ctx, outbuf, *indent_level);
83 }
84}
85
86static void
87json_map_close(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
88{
89 if (ctx->impl->output.is_pretty) {
90 GRN_TEXT_PUTC(ctx, outbuf, '\n');
91 (*indent_level)--;
92 indent(ctx, outbuf, *indent_level);
93 }
94 GRN_TEXT_PUTC(ctx, outbuf, '}');
95}
96
97static void
98json_key_end(grn_ctx *ctx, grn_obj *outbuf)
99{
100 GRN_TEXT_PUTC(ctx, outbuf, ':');
101 if (ctx->impl->output.is_pretty) {
102 GRN_TEXT_PUTC(ctx, outbuf, ' ');
103 }
104}
105
106static void
107json_key(grn_ctx *ctx, grn_obj *outbuf, const char *key)
108{
109 grn_text_esc(ctx, outbuf, key, strlen(key));
110 json_key_end(ctx, outbuf);
111}
112
113static void
114json_value_end(grn_ctx *ctx, grn_obj *outbuf, size_t indent_level)
115{
116 GRN_TEXT_PUTC(ctx, outbuf, ',');
117 if (ctx->impl->output.is_pretty) {
118 GRN_TEXT_PUTC(ctx, outbuf, '\n');
119 indent(ctx, outbuf, indent_level);
120 }
121}
122
123static void
124put_delimiter(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
125{
126 uint32_t level = CURR_LEVEL;
127 switch (output_type) {
128 case GRN_CONTENT_JSON:
129 if (level < 2) {
130 if (DEPTH > 0 && ctx->impl->output.is_pretty) {
131 GRN_TEXT_PUTC(ctx, outbuf, '\n');
132 indent(ctx, outbuf, DEPTH + 1);
133 }
134 return;
135 }
136 if ((level & 3) == 3) {
137 GRN_TEXT_PUTC(ctx, outbuf, ':');
138 if (ctx->impl->output.is_pretty) {
139 GRN_TEXT_PUTC(ctx, outbuf, ' ');
140 }
141 } else {
142 json_element_end(ctx, outbuf, DEPTH + 1);
143 }
144 // if (DEPTH == 1 && ((level & 3) != 3)) { GRN_TEXT_PUTC(ctx, outbuf, '\n'); }
145 break;
146 case GRN_CONTENT_XML:
147 if (!DEPTH) { return; }
148 GRN_TEXT_PUTC(ctx, outbuf, '\n');
149 break;
150 case GRN_CONTENT_TSV:
151 if (level < 2) { return; }
152 if (DEPTH <= 2) {
153 GRN_TEXT_PUTC(ctx, outbuf, ((level & 3) == 3) ? '\t' : '\n');
154 } else {
155 GRN_TEXT_PUTC(ctx, outbuf, '\t');
156 }
157 case GRN_CONTENT_MSGPACK :
158 // do nothing
159 break;
160 case GRN_CONTENT_GROONGA_COMMAND_LIST :
161 break;
162 case GRN_CONTENT_NONE:
163 break;
164 }
165}
166
167void
168grn_output_array_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
169 const char *name, int nelements)
170{
171 put_delimiter(ctx, outbuf, output_type);
172 switch (output_type) {
173 case GRN_CONTENT_JSON:
174 GRN_TEXT_PUTC(ctx, outbuf, '[');
175 break;
176 case GRN_CONTENT_XML:
177 GRN_TEXT_PUTC(ctx, outbuf, '<');
178 GRN_TEXT_PUTS(ctx, outbuf, name);
179 GRN_TEXT_PUTC(ctx, outbuf, '>');
180 grn_vector_add_element(ctx,
181 &ctx->impl->output.names,
182 name, strlen(name),
183 0, GRN_DB_SHORT_TEXT);
184 break;
185 case GRN_CONTENT_TSV:
186 if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "[\t"); }
187 break;
188 case GRN_CONTENT_MSGPACK :
189#ifdef GRN_WITH_MESSAGE_PACK
190 if (nelements < 0) {
191 GRN_LOG(ctx, GRN_LOG_DEBUG,
192 "grn_output_array_open nelements (%d) for <%s>",
193 nelements,
194 name);
195 }
196 msgpack_pack_array(&ctx->impl->output.msgpacker, nelements);
197#endif
198 break;
199 case GRN_CONTENT_GROONGA_COMMAND_LIST :
200 break;
201 case GRN_CONTENT_NONE:
202 break;
203 }
204 INCR_DEPTH(0);
205}
206
207void
208grn_output_array_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
209{
210 switch (output_type) {
211 case GRN_CONTENT_JSON:
212 if (ctx->impl->output.is_pretty) {
213 GRN_TEXT_PUTC(ctx, outbuf, '\n');
214 indent(ctx, outbuf, DEPTH);
215 }
216 GRN_TEXT_PUTC(ctx, outbuf, ']');
217 break;
218 case GRN_CONTENT_TSV:
219 if (DEPTH > 3) {
220 if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
221 GRN_TEXT_PUTC(ctx, outbuf, ']');
222 }
223 break;
224 case GRN_CONTENT_XML:
225 {
226 const char *name;
227 unsigned int name_len;
228 name_len = grn_vector_pop_element(ctx,
229 &ctx->impl->output.names,
230 &name, NULL, NULL);
231 GRN_TEXT_PUTS(ctx, outbuf, "</");
232 GRN_TEXT_PUT(ctx, outbuf, name, name_len);
233 GRN_TEXT_PUTC(ctx, outbuf, '>');
234 }
235 break;
236 case GRN_CONTENT_MSGPACK :
237 // do nothing
238 break;
239 case GRN_CONTENT_GROONGA_COMMAND_LIST :
240 break;
241 case GRN_CONTENT_NONE:
242 break;
243 }
244 DECR_DEPTH;
245 INCR_LENGTH;
246}
247
248void
249grn_output_map_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
250 const char *name, int nelements)
251{
252 put_delimiter(ctx, outbuf, output_type);
253 switch (output_type) {
254 case GRN_CONTENT_JSON:
255 GRN_TEXT_PUTS(ctx, outbuf, "{");
256 break;
257 case GRN_CONTENT_XML:
258 GRN_TEXT_PUTC(ctx, outbuf, '<');
259 GRN_TEXT_PUTS(ctx, outbuf, name);
260 GRN_TEXT_PUTC(ctx, outbuf, '>');
261 grn_vector_add_element(ctx,
262 &ctx->impl->output.names,
263 name, strlen(name), 0, GRN_DB_SHORT_TEXT);
264 break;
265 case GRN_CONTENT_TSV:
266 if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "{\t"); }
267 break;
268 case GRN_CONTENT_MSGPACK :
269#ifdef GRN_WITH_MESSAGE_PACK
270 if (nelements < 0) {
271 GRN_LOG(ctx, GRN_LOG_DEBUG,
272 "grn_output_map_open nelements (%d) for <%s>",
273 nelements,
274 name);
275 }
276 msgpack_pack_map(&ctx->impl->output.msgpacker, nelements);
277#endif
278 break;
279 case GRN_CONTENT_GROONGA_COMMAND_LIST :
280 break;
281 case GRN_CONTENT_NONE:
282 break;
283 }
284 INCR_DEPTH(1);
285}
286
287void
288grn_output_map_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
289{
290 switch (output_type) {
291 case GRN_CONTENT_JSON:
292 if (ctx->impl->output.is_pretty) {
293 GRN_TEXT_PUTC(ctx, outbuf, '\n');
294 indent(ctx, outbuf, DEPTH);
295 }
296 GRN_TEXT_PUTS(ctx, outbuf, "}");
297 break;
298 case GRN_CONTENT_TSV:
299 if (DEPTH > 3) {
300 if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
301 GRN_TEXT_PUTC(ctx, outbuf, '}');
302 }
303 break;
304 case GRN_CONTENT_XML:
305 {
306 const char *name;
307 unsigned int name_len;
308 name_len = grn_vector_pop_element(ctx,
309 &ctx->impl->output.names,
310 &name, NULL, NULL);
311 GRN_TEXT_PUTS(ctx, outbuf, "</");
312 GRN_TEXT_PUT(ctx, outbuf, name, name_len);
313 GRN_TEXT_PUTC(ctx, outbuf, '>');
314 }
315 break;
316 case GRN_CONTENT_MSGPACK :
317 // do nothing
318 break;
319 case GRN_CONTENT_GROONGA_COMMAND_LIST :
320 break;
321 case GRN_CONTENT_NONE:
322 break;
323 }
324 DECR_DEPTH;
325 INCR_LENGTH;
326}
327
328void
329grn_output_int32(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int value)
330{
331 put_delimiter(ctx, outbuf, output_type);
332 switch (output_type) {
333 case GRN_CONTENT_JSON:
334 grn_text_itoa(ctx, outbuf, value);
335 break;
336 case GRN_CONTENT_TSV:
337 grn_text_itoa(ctx, outbuf, value);
338 break;
339 case GRN_CONTENT_XML:
340 GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
341 grn_text_itoa(ctx, outbuf, value);
342 GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
343 break;
344 case GRN_CONTENT_MSGPACK :
345#ifdef GRN_WITH_MESSAGE_PACK
346 msgpack_pack_int32(&ctx->impl->output.msgpacker, value);
347#endif
348 break;
349 case GRN_CONTENT_GROONGA_COMMAND_LIST :
350 grn_text_itoa(ctx, outbuf, value);
351 break;
352 case GRN_CONTENT_NONE:
353 break;
354 }
355 INCR_LENGTH;
356}
357
358void
359grn_output_int64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
360{
361 put_delimiter(ctx, outbuf, output_type);
362 switch (output_type) {
363 case GRN_CONTENT_JSON:
364 grn_text_lltoa(ctx, outbuf, value);
365 break;
366 case GRN_CONTENT_TSV:
367 grn_text_lltoa(ctx, outbuf, value);
368 break;
369 case GRN_CONTENT_XML:
370 GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
371 grn_text_lltoa(ctx, outbuf, value);
372 GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
373 break;
374 case GRN_CONTENT_MSGPACK :
375#ifdef GRN_WITH_MESSAGE_PACK
376 msgpack_pack_int64(&ctx->impl->output.msgpacker, value);
377#endif
378 break;
379 case GRN_CONTENT_GROONGA_COMMAND_LIST :
380 grn_text_lltoa(ctx, outbuf, value);
381 break;
382 case GRN_CONTENT_NONE:
383 break;
384 }
385 INCR_LENGTH;
386}
387
388void
389grn_output_uint64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, uint64_t value)
390{
391 put_delimiter(ctx, outbuf, output_type);
392 switch (output_type) {
393 case GRN_CONTENT_JSON:
394 grn_text_ulltoa(ctx, outbuf, value);
395 break;
396 case GRN_CONTENT_TSV:
397 grn_text_ulltoa(ctx, outbuf, value);
398 break;
399 case GRN_CONTENT_XML:
400 GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
401 grn_text_ulltoa(ctx, outbuf, value);
402 GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
403 break;
404 case GRN_CONTENT_MSGPACK :
405#ifdef GRN_WITH_MESSAGE_PACK
406 msgpack_pack_uint64(&ctx->impl->output.msgpacker, value);
407#endif
408 break;
409 case GRN_CONTENT_GROONGA_COMMAND_LIST :
410 grn_text_ulltoa(ctx, outbuf, value);
411 break;
412 case GRN_CONTENT_NONE:
413 break;
414 }
415 INCR_LENGTH;
416}
417
418void
419grn_output_float(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, double value)
420{
421 put_delimiter(ctx, outbuf, output_type);
422 switch (output_type) {
423 case GRN_CONTENT_JSON:
424 grn_text_ftoa(ctx, outbuf, value);
425 break;
426 case GRN_CONTENT_TSV:
427 grn_text_ftoa(ctx, outbuf, value);
428 break;
429 case GRN_CONTENT_XML:
430 GRN_TEXT_PUTS(ctx, outbuf, "<FLOAT>");
431 grn_text_ftoa(ctx, outbuf, value);
432 GRN_TEXT_PUTS(ctx, outbuf, "</FLOAT>");
433 break;
434 case GRN_CONTENT_MSGPACK :
435#ifdef GRN_WITH_MESSAGE_PACK
436 msgpack_pack_double(&ctx->impl->output.msgpacker, value);
437#endif
438 break;
439 case GRN_CONTENT_GROONGA_COMMAND_LIST :
440 grn_text_ftoa(ctx, outbuf, value);
441 break;
442 case GRN_CONTENT_NONE:
443 break;
444 }
445 INCR_LENGTH;
446}
447
448void
449grn_output_str(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
450 const char *value, size_t value_len)
451{
452 put_delimiter(ctx, outbuf, output_type);
453 switch (output_type) {
454 case GRN_CONTENT_JSON:
455 grn_text_esc(ctx, outbuf, value, value_len);
456 break;
457 case GRN_CONTENT_TSV:
458 grn_text_esc(ctx, outbuf, value, value_len);
459 break;
460 case GRN_CONTENT_XML:
461 GRN_TEXT_PUTS(ctx, outbuf, "<TEXT>");
462 grn_text_escape_xml(ctx, outbuf, value, value_len);
463 GRN_TEXT_PUTS(ctx, outbuf, "</TEXT>");
464 break;
465 case GRN_CONTENT_MSGPACK :
466#ifdef GRN_WITH_MESSAGE_PACK
467 msgpack_pack_str(&ctx->impl->output.msgpacker, value_len);
468 msgpack_pack_str_body(&ctx->impl->output.msgpacker, value, value_len);
469#endif
470 break;
471 case GRN_CONTENT_GROONGA_COMMAND_LIST :
472 GRN_TEXT_PUT(ctx, outbuf, value, value_len);
473 break;
474 case GRN_CONTENT_NONE:
475 break;
476 }
477 INCR_LENGTH;
478}
479
480void
481grn_output_cstr(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
482 const char *value)
483{
484 grn_output_str(ctx, outbuf, output_type, value, strlen(value));
485}
486
487void
488grn_output_bool(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, grn_bool value)
489{
490 put_delimiter(ctx, outbuf, output_type);
491 switch (output_type) {
492 case GRN_CONTENT_JSON:
493 GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
494 break;
495 case GRN_CONTENT_TSV:
496 GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
497 break;
498 case GRN_CONTENT_XML:
499 GRN_TEXT_PUTS(ctx, outbuf, "<BOOL>");
500 GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
501 GRN_TEXT_PUTS(ctx, outbuf, "</BOOL>");
502 break;
503 case GRN_CONTENT_MSGPACK :
504#ifdef GRN_WITH_MESSAGE_PACK
505 if (value) {
506 msgpack_pack_true(&ctx->impl->output.msgpacker);
507 } else {
508 msgpack_pack_false(&ctx->impl->output.msgpacker);
509 }
510#endif
511 break;
512 case GRN_CONTENT_GROONGA_COMMAND_LIST :
513 GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
514 break;
515 case GRN_CONTENT_NONE:
516 break;
517 }
518 INCR_LENGTH;
519}
520
521void
522grn_output_null(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
523{
524 put_delimiter(ctx, outbuf, output_type);
525 switch (output_type) {
526 case GRN_CONTENT_JSON:
527 GRN_TEXT_PUTS(ctx, outbuf, "null");
528 break;
529 case GRN_CONTENT_TSV:
530 break;
531 case GRN_CONTENT_XML:
532 GRN_TEXT_PUTS(ctx, outbuf, "<NULL/>");
533 break;
534 case GRN_CONTENT_MSGPACK :
535#ifdef GRN_WITH_MESSAGE_PACK
536 msgpack_pack_nil(&ctx->impl->output.msgpacker);
537#endif
538 break;
539 case GRN_CONTENT_GROONGA_COMMAND_LIST :
540 break;
541 case GRN_CONTENT_NONE:
542 break;
543 }
544 INCR_LENGTH;
545}
546
547static inline void
548grn_output_bulk_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
549 const char *value, size_t value_len)
550{
551 if (value_len == sizeof(grn_id) && *(grn_id *)value == GRN_ID_NIL) {
552 grn_output_null(ctx, outbuf, output_type);
553 } else {
554 grn_output_str(ctx, outbuf, output_type, value, value_len);
555 }
556}
557
558void
559grn_output_time(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
560{
561 double dv = value;
562 dv /= 1000000.0;
563 put_delimiter(ctx, outbuf, output_type);
564 switch (output_type) {
565 case GRN_CONTENT_JSON:
566 grn_text_ftoa(ctx, outbuf, dv);
567 break;
568 case GRN_CONTENT_TSV:
569 grn_text_ftoa(ctx, outbuf, dv);
570 break;
571 case GRN_CONTENT_XML:
572 GRN_TEXT_PUTS(ctx, outbuf, "<DATE>");
573 grn_text_ftoa(ctx, outbuf, dv);
574 GRN_TEXT_PUTS(ctx, outbuf, "</DATE>");
575 break;
576 case GRN_CONTENT_MSGPACK :
577#ifdef GRN_WITH_MESSAGE_PACK
578 msgpack_pack_double(&ctx->impl->output.msgpacker, dv);
579#endif
580 break;
581 case GRN_CONTENT_GROONGA_COMMAND_LIST :
582 grn_text_ftoa(ctx, outbuf, dv);
583 break;
584 case GRN_CONTENT_NONE:
585 break;
586 }
587 INCR_LENGTH;
588}
589
590void
591grn_output_geo_point(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
592 grn_geo_point *value)
593{
594 put_delimiter(ctx, outbuf, output_type);
595 switch (output_type) {
596 case GRN_CONTENT_JSON:
597 if (value) {
598 GRN_TEXT_PUTC(ctx, outbuf, '"');
599 grn_text_itoa(ctx, outbuf, value->latitude);
600 GRN_TEXT_PUTC(ctx, outbuf, 'x');
601 grn_text_itoa(ctx, outbuf, value->longitude);
602 GRN_TEXT_PUTC(ctx, outbuf, '"');
603 } else {
604 GRN_TEXT_PUTS(ctx, outbuf, "null");
605 }
606 break;
607 case GRN_CONTENT_TSV:
608 if (value) {
609 GRN_TEXT_PUTC(ctx, outbuf, '"');
610 grn_text_itoa(ctx, outbuf, value->latitude);
611 GRN_TEXT_PUTC(ctx, outbuf, 'x');
612 grn_text_itoa(ctx, outbuf, value->longitude);
613 GRN_TEXT_PUTC(ctx, outbuf, '"');
614 } else {
615 GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
616 }
617 break;
618 case GRN_CONTENT_XML:
619 GRN_TEXT_PUTS(ctx, outbuf, "<GEO_POINT>");
620 if (value) {
621 grn_text_itoa(ctx, outbuf, value->latitude);
622 GRN_TEXT_PUTC(ctx, outbuf, 'x');
623 grn_text_itoa(ctx, outbuf, value->longitude);
624 }
625 GRN_TEXT_PUTS(ctx, outbuf, "</GEO_POINT>");
626 break;
627 case GRN_CONTENT_MSGPACK :
628#ifdef GRN_WITH_MESSAGE_PACK
629 if (value) {
630 grn_obj buf;
631 GRN_TEXT_INIT(&buf, 0);
632 grn_text_itoa(ctx, &buf, value->latitude);
633 GRN_TEXT_PUTC(ctx, &buf, 'x');
634 grn_text_itoa(ctx, &buf, value->longitude);
635 msgpack_pack_str(&ctx->impl->output.msgpacker, GRN_TEXT_LEN(&buf));
636 msgpack_pack_str_body(&ctx->impl->output.msgpacker,
637 GRN_TEXT_VALUE(&buf),
638 GRN_TEXT_LEN(&buf));
639 grn_obj_close(ctx, &buf);
640 } else {
641 msgpack_pack_nil(&ctx->impl->output.msgpacker);
642 }
643#endif
644 break;
645 case GRN_CONTENT_GROONGA_COMMAND_LIST :
646 if (value) {
647 GRN_TEXT_PUTC(ctx, outbuf, '"');
648 grn_text_itoa(ctx, outbuf, value->latitude);
649 GRN_TEXT_PUTC(ctx, outbuf, 'x');
650 grn_text_itoa(ctx, outbuf, value->longitude);
651 GRN_TEXT_PUTC(ctx, outbuf, '"');
652 } else {
653 GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
654 }
655 break;
656 case GRN_CONTENT_NONE:
657 break;
658 }
659 INCR_LENGTH;
660}
661
662static void
663grn_text_atoj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
664 grn_obj *obj, grn_id id)
665{
666 uint32_t vs;
667 grn_obj buf;
668 if (obj->header.type == GRN_ACCESSOR) {
669 grn_accessor *a = (grn_accessor *)obj;
670 GRN_TEXT_INIT(&buf, 0);
671 for (;;) {
672 buf.header.domain = grn_obj_get_range(ctx, obj);
673 GRN_BULK_REWIND(&buf);
674 switch (a->action) {
675 case GRN_ACCESSOR_GET_ID :
676 GRN_UINT32_PUT(ctx, &buf, id);
677 buf.header.domain = GRN_DB_UINT32;
678 break;
679 case GRN_ACCESSOR_GET_KEY :
680 grn_table_get_key2(ctx, a->obj, id, &buf);
681 buf.header.domain = DB_OBJ(a->obj)->header.domain;
682 break;
683 case GRN_ACCESSOR_GET_VALUE :
684 grn_obj_get_value(ctx, a->obj, id, &buf);
685 buf.header.domain = DB_OBJ(a->obj)->range;
686 break;
687 case GRN_ACCESSOR_GET_SCORE :
688 {
689 grn_rset_recinfo *ri =
690 (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
691 if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
692 int32_t int32_score = ri->score;
693 GRN_INT32_PUT(ctx, &buf, int32_score);
694 buf.header.domain = GRN_DB_INT32;
695 } else {
696 double float_score = ri->score;
697 GRN_FLOAT_PUT(ctx, &buf, float_score);
698 buf.header.domain = GRN_DB_FLOAT;
699 }
700 }
701 break;
702 case GRN_ACCESSOR_GET_NSUBRECS :
703 {
704 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
705 GRN_INT32_PUT(ctx, &buf, ri->n_subrecs);
706 }
707 buf.header.domain = GRN_DB_INT32;
708 break;
709 case GRN_ACCESSOR_GET_MAX :
710 {
711 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
712 int64_t max;
713 max = grn_rset_recinfo_get_max(ctx, ri, a->obj);
714 GRN_INT64_PUT(ctx, &buf, max);
715 }
716 buf.header.domain = GRN_DB_INT64;
717 break;
718 case GRN_ACCESSOR_GET_MIN :
719 {
720 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
721 int64_t min;
722 min = grn_rset_recinfo_get_min(ctx, ri, a->obj);
723 GRN_INT64_PUT(ctx, &buf, min);
724 }
725 buf.header.domain = GRN_DB_INT64;
726 break;
727 case GRN_ACCESSOR_GET_SUM :
728 {
729 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
730 int64_t sum;
731 sum = grn_rset_recinfo_get_sum(ctx, ri, a->obj);
732 GRN_INT64_PUT(ctx, &buf, sum);
733 }
734 buf.header.domain = GRN_DB_INT64;
735 break;
736 case GRN_ACCESSOR_GET_AVG :
737 {
738 grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
739 double avg;
740 avg = grn_rset_recinfo_get_avg(ctx, ri, a->obj);
741 GRN_FLOAT_PUT(ctx, &buf, avg);
742 }
743 buf.header.domain = GRN_DB_FLOAT;
744 break;
745 case GRN_ACCESSOR_GET_COLUMN_VALUE :
746 if ((a->obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
747 if (a->next) {
748 grn_id *idp;
749 grn_obj_get_value(ctx, a->obj, id, &buf);
750 idp = (grn_id *)GRN_BULK_HEAD(&buf);
751 vs = GRN_BULK_VSIZE(&buf) / sizeof(grn_id);
752 grn_output_array_open(ctx, outbuf, output_type, "VECTOR", vs);
753 for (; vs--; idp++) {
754 grn_text_atoj(ctx, outbuf, output_type, (grn_obj *)a->next, *idp);
755 }
756 grn_output_array_close(ctx, outbuf, output_type);
757 } else {
758 grn_text_atoj(ctx, outbuf, output_type, a->obj, id);
759 }
760 goto exit;
761 } else {
762 grn_obj_get_value(ctx, a->obj, id, &buf);
763 }
764 break;
765 case GRN_ACCESSOR_GET_DB_OBJ :
766 /* todo */
767 break;
768 case GRN_ACCESSOR_LOOKUP :
769 /* todo */
770 break;
771 case GRN_ACCESSOR_FUNCALL :
772 /* todo */
773 break;
774 }
775 if (a->next) {
776 a = a->next;
777 if (GRN_BULK_VSIZE(&buf) >= sizeof(grn_id)) {
778 id = *((grn_id *)GRN_BULK_HEAD(&buf));
779 } else {
780 id = GRN_ID_NIL;
781 }
782 } else {
783 break;
784 }
785 }
786 grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
787 } else {
788 grn_obj_format *format_argument = NULL;
789 grn_obj_format format;
790 GRN_OBJ_FORMAT_INIT(&format, 0, 0, 0, 0);
791 switch (obj->header.type) {
792 case GRN_COLUMN_FIX_SIZE :
793 GRN_VALUE_FIX_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
794 break;
795 case GRN_COLUMN_VAR_SIZE :
796 if ((obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
797 grn_obj *range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
798 if (GRN_OBJ_TABLEP(range) ||
799 (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) == 0) {
800 GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
801 } else {
802 GRN_VALUE_VAR_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
803 }
804 if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
805 format.flags |= GRN_OBJ_FORMAT_WITH_WEIGHT;
806 format_argument = &format;
807 }
808 } else {
809 GRN_VALUE_VAR_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
810 }
811 break;
812 case GRN_COLUMN_INDEX :
813 GRN_UINT32_INIT(&buf, 0);
814 break;
815 default:
816 GRN_TEXT_INIT(&buf, 0);
817 break;
818 }
819 grn_obj_get_value(ctx, obj, id, &buf);
820 grn_output_obj(ctx, outbuf, output_type, &buf, format_argument);
821 }
822exit :
823 grn_obj_close(ctx, &buf);
824}
825
826static inline void
827grn_output_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
828 grn_obj *bulk, grn_obj_format *format)
829{
830 grn_output_null(ctx, outbuf, output_type);
831}
832
833static inline void
834grn_output_bulk(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
835 grn_obj *bulk, grn_obj_format *format)
836{
837 grn_obj buf;
838 GRN_TEXT_INIT(&buf, 0);
839 switch (bulk->header.domain) {
840 case GRN_DB_VOID :
841 grn_output_bulk_void(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
842 break;
843 case GRN_DB_SHORT_TEXT :
844 case GRN_DB_TEXT :
845 case GRN_DB_LONG_TEXT :
846 grn_output_str(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
847 break;
848 case GRN_DB_BOOL :
849 grn_output_bool(ctx, outbuf, output_type,
850 GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
851 break;
852 case GRN_DB_INT8 :
853 grn_output_int32(ctx, outbuf, output_type,
854 GRN_BULK_VSIZE(bulk) ? GRN_INT8_VALUE(bulk) : 0);
855 break;
856 case GRN_DB_UINT8 :
857 grn_output_int32(ctx, outbuf, output_type,
858 GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
859 break;
860 case GRN_DB_INT16 :
861 grn_output_int32(ctx, outbuf, output_type,
862 GRN_BULK_VSIZE(bulk) ? GRN_INT16_VALUE(bulk) : 0);
863 break;
864 case GRN_DB_UINT16 :
865 grn_output_int32(ctx, outbuf, output_type,
866 GRN_BULK_VSIZE(bulk) ? GRN_UINT16_VALUE(bulk) : 0);
867 break;
868 case GRN_DB_INT32 :
869 grn_output_int32(ctx, outbuf, output_type,
870 GRN_BULK_VSIZE(bulk) ? GRN_INT32_VALUE(bulk) : 0);
871 break;
872 case GRN_DB_UINT32 :
873 grn_output_int64(ctx, outbuf, output_type,
874 GRN_BULK_VSIZE(bulk) ? GRN_UINT32_VALUE(bulk) : 0);
875 break;
876 case GRN_DB_INT64 :
877 grn_output_int64(ctx, outbuf, output_type,
878 GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
879 break;
880 case GRN_DB_UINT64 :
881 grn_output_uint64(ctx, outbuf, output_type,
882 GRN_BULK_VSIZE(bulk) ? GRN_UINT64_VALUE(bulk) : 0);
883 break;
884 case GRN_DB_FLOAT :
885 grn_output_float(ctx, outbuf, output_type,
886 GRN_BULK_VSIZE(bulk) ? GRN_FLOAT_VALUE(bulk) : 0);
887 break;
888 case GRN_DB_TIME :
889 grn_output_time(ctx, outbuf, output_type,
890 GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
891 break;
892 case GRN_DB_TOKYO_GEO_POINT :
893 case GRN_DB_WGS84_GEO_POINT :
894 grn_output_geo_point(ctx, outbuf, output_type,
895 GRN_BULK_VSIZE(bulk) ? (grn_geo_point *)GRN_BULK_HEAD(bulk) : NULL);
896 break;
897 default :
898 if (format) {
899 int j;
900 int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
901 grn_id id = GRN_RECORD_VALUE(bulk);
902 grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
903 if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
904 grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", ncolumns);
905 for (j = 0; j < ncolumns; j++) {
906 grn_id range_id;
907 grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
908 GRN_BULK_REWIND(&buf);
909 grn_column_name_(ctx, columns[j], &buf);
910 grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
911 /* column range */
912 range_id = grn_obj_get_range(ctx, columns[j]);
913 if (range_id == GRN_ID_NIL) {
914 GRN_TEXT_PUTS(ctx, outbuf, "null");
915 } else {
916 int name_len;
917 grn_obj *range_obj;
918 char name_buf[GRN_TABLE_MAX_KEY_SIZE];
919
920 range_obj = grn_ctx_at(ctx, range_id);
921 name_len = grn_obj_name(ctx, range_obj, name_buf,
922 GRN_TABLE_MAX_KEY_SIZE);
923 GRN_BULK_REWIND(&buf);
924 GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
925 grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
926 }
927 grn_output_array_close(ctx, outbuf, output_type);
928 }
929 grn_output_array_close(ctx, outbuf, output_type);
930 }
931 grn_output_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
932 for (j = 0; j < ncolumns; j++) {
933 grn_text_atoj(ctx, outbuf, output_type, columns[j], id);
934 }
935 grn_output_array_close(ctx, outbuf, output_type);
936 } else {
937 grn_obj *table = grn_ctx_at(ctx, bulk->header.domain);
938 grn_id id = GRN_RECORD_VALUE(bulk);
939 if (table && table->header.type != GRN_TABLE_NO_KEY) {
940 grn_obj *accessor = grn_obj_column(ctx, table,
941 GRN_COLUMN_NAME_KEY,
942 GRN_COLUMN_NAME_KEY_LEN);
943 if (accessor) {
944 if (id == GRN_ID_NIL) {
945 grn_obj_reinit_for(ctx, &buf, accessor);
946 } else {
947 grn_obj_get_value(ctx, accessor, id, &buf);
948 }
949 grn_obj_unlink(ctx, accessor);
950 }
951 grn_output_obj(ctx, outbuf, output_type, &buf, format);
952 } else {
953 grn_output_int64(ctx, outbuf, output_type, id);
954 }
955 }
956 break;
957 }
958 GRN_OBJ_FIN(ctx, &buf);
959}
960
961static void
962grn_output_uvector_result_set(grn_ctx *ctx,
963 grn_obj *outbuf,
964 grn_content_type output_type,
965 grn_obj *uvector,
966 grn_obj_format *format)
967{
968 unsigned int i_hit, n_hits;
969 unsigned int i_column, n_columns;
970 unsigned int n_elements;
971 grn_obj **columns;
972 grn_obj buf;
973 grn_bool with_column_names = GRN_FALSE;
974
975 n_hits = grn_vector_size(ctx, uvector);
976
977 n_columns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
978 columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
979
980 GRN_TEXT_INIT(&buf, 0);
981
982 if (n_hits > 0 && format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
983 with_column_names = GRN_TRUE;
984 }
985
986 n_elements = 1; /* for NHITS */
987 if (with_column_names) {
988 n_elements += 1; /* for COLUMNS */
989 }
990 n_elements += n_hits; /* for HITS */
991 grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", n_elements);
992
993 grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
994 grn_text_itoa(ctx, outbuf, n_hits);
995 grn_output_array_close(ctx, outbuf, output_type);
996
997 if (with_column_names) {
998 grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_columns);
999 for (i_column = 0; i_column < n_columns; i_column++) {
1000 grn_id range_id;
1001 grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
1002
1003 /* name */
1004 GRN_BULK_REWIND(&buf);
1005 grn_column_name_(ctx, columns[i_column], &buf);
1006 grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
1007
1008 /* type */
1009 range_id = grn_obj_get_range(ctx, columns[i_column]);
1010 if (range_id == GRN_ID_NIL) {
1011 GRN_TEXT_PUTS(ctx, outbuf, "null");
1012 } else {
1013 int name_len;
1014 grn_obj *range_obj;
1015 char name_buf[GRN_TABLE_MAX_KEY_SIZE];
1016
1017 range_obj = grn_ctx_at(ctx, range_id);
1018 name_len = grn_obj_name(ctx, range_obj, name_buf,
1019 GRN_TABLE_MAX_KEY_SIZE);
1020 GRN_BULK_REWIND(&buf);
1021 GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
1022 grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
1023 }
1024
1025 grn_output_array_close(ctx, outbuf, output_type);
1026 }
1027 grn_output_array_close(ctx, outbuf, output_type);
1028 }
1029
1030 for (i_hit = 0; i_hit < n_hits++; i_hit++) {
1031 grn_id id;
1032
1033 id = grn_uvector_get_element(ctx, uvector, i_hit, NULL);
1034 grn_output_array_open(ctx, outbuf, output_type, "HITS", n_columns);
1035 for (i_column = 0; i_column < n_columns; i_column++) {
1036 GRN_BULK_REWIND(&buf);
1037 grn_obj_get_value(ctx, columns[i_column], id, &buf);
1038 grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
1039 }
1040 grn_output_array_close(ctx, outbuf, output_type);
1041 }
1042
1043 grn_output_array_close(ctx, outbuf, output_type);
1044
1045 GRN_OBJ_FIN(ctx, &buf);
1046}
1047
1048static inline void
1049grn_output_uvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
1050 grn_obj *uvector, grn_obj_format *format)
1051{
1052 grn_bool output_result_set = GRN_FALSE;
1053 grn_bool with_weight = GRN_FALSE;
1054 grn_obj *range;
1055 grn_bool range_is_type;
1056
1057 if (format) {
1058 if (GRN_BULK_VSIZE(&(format->columns)) > 0) {
1059 output_result_set = GRN_TRUE;
1060 }
1061 if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
1062 with_weight = GRN_TRUE;
1063 }
1064 }
1065
1066 if (output_result_set) {
1067 grn_output_uvector_result_set(ctx, outbuf, output_type, uvector, format);
1068 return;
1069 }
1070
1071 range = grn_ctx_at(ctx, uvector->header.domain);
1072 range_is_type = (range->header.type == GRN_TYPE);
1073 if (range_is_type) {
1074 unsigned int i, n;
1075 char *raw_elements;
1076 unsigned int element_size;
1077 grn_obj element;
1078
1079 raw_elements = GRN_BULK_HEAD(uvector);
1080 element_size = GRN_TYPE_SIZE(DB_OBJ(range));
1081 n = GRN_BULK_VSIZE(uvector) / element_size;
1082
1083 grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
1084 GRN_OBJ_INIT(&element, GRN_BULK, 0, uvector->header.domain);
1085 for (i = 0; i < n; i++) {
1086 GRN_BULK_REWIND(&element);
1087 grn_bulk_write_from(ctx, &element, raw_elements + (element_size * i),
1088 0, element_size);
1089 grn_output_obj(ctx, outbuf, output_type, &element, NULL);
1090 }
1091 GRN_OBJ_FIN(ctx, &element);
1092 grn_output_array_close(ctx, outbuf, output_type);
1093 } else {
1094 unsigned int i, n;
1095 grn_obj id_value;
1096 grn_obj key_value;
1097
1098 GRN_UINT32_INIT(&id_value, 0);
1099 GRN_OBJ_INIT(&key_value, GRN_BULK, 0, range->header.domain);
1100
1101 n = grn_vector_size(ctx, uvector);
1102 if (with_weight) {
1103 grn_output_map_open(ctx, outbuf, output_type, "WEIGHT_VECTOR", n);
1104 } else {
1105 grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
1106 }
1107
1108 for (i = 0; i < n; i++) {
1109 grn_id id;
1110 unsigned int weight;
1111
1112 id = grn_uvector_get_element(ctx, uvector, i, &weight);
1113 if (range->header.type == GRN_TABLE_NO_KEY) {
1114 GRN_UINT32_SET(ctx, &id_value, id);
1115 grn_output_obj(ctx, outbuf, output_type, &id_value, NULL);
1116 } else {
1117 GRN_BULK_REWIND(&key_value);
1118 grn_table_get_key2(ctx, range, id, &key_value);
1119 grn_output_obj(ctx, outbuf, output_type, &key_value, NULL);
1120 }
1121
1122 if (with_weight) {
1123 grn_output_uint64(ctx, outbuf, output_type, weight);
1124 }
1125 }
1126
1127 if (with_weight) {
1128 grn_output_map_close(ctx, outbuf, output_type);
1129 } else {
1130 grn_output_array_close(ctx, outbuf, output_type);
1131 }
1132
1133 GRN_OBJ_FIN(ctx, &id_value);
1134 GRN_OBJ_FIN(ctx, &key_value);
1135 }
1136 grn_obj_unlink(ctx, range);
1137}
1138
1139static inline void
1140grn_output_vector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
1141 grn_obj *vector, grn_obj_format *format)
1142{
1143 grn_bool with_weight = GRN_FALSE;
1144
1145 if (vector->header.domain == GRN_DB_VOID) {
1146 ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
1147 return;
1148 }
1149
1150 if (format) {
1151 if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
1152 with_weight = GRN_TRUE;
1153 }
1154 }
1155
1156 if (with_weight) {
1157 unsigned int i, n;
1158 grn_obj value;
1159
1160 GRN_VOID_INIT(&value);
1161 n = grn_vector_size(ctx, vector);
1162 grn_output_map_open(ctx, outbuf, output_type, "WEIGHT_VECTOR", n);
1163 for (i = 0; i < n; i++) {
1164 const char *_value;
1165 unsigned int weight, length;
1166 grn_id domain;
1167
1168 length = grn_vector_get_element(ctx, vector, i,
1169 &_value, &weight, &domain);
1170 if (domain != GRN_DB_VOID) {
1171 grn_obj_reinit(ctx, &value, domain, 0);
1172 } else {
1173 grn_obj_reinit(ctx, &value, vector->header.domain, 0);
1174 }
1175 grn_bulk_write(ctx, &value, _value, length);
1176 grn_output_obj(ctx, outbuf, output_type, &value, NULL);
1177 grn_output_uint64(ctx, outbuf, output_type, weight);
1178 }
1179 grn_output_map_close(ctx, outbuf, output_type);
1180 GRN_OBJ_FIN(ctx, &value);
1181 } else {
1182 unsigned int i, n;
1183 grn_obj value;
1184 GRN_VOID_INIT(&value);
1185 n = grn_vector_size(ctx, vector);
1186 grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
1187 for (i = 0; i < n; i++) {
1188 const char *_value;
1189 unsigned int weight, length;
1190 grn_id domain;
1191
1192 length = grn_vector_get_element(ctx, vector, i,
1193 &_value, &weight, &domain);
1194 if (domain != GRN_DB_VOID) {
1195 grn_obj_reinit(ctx, &value, domain, 0);
1196 } else {
1197 grn_obj_reinit(ctx, &value, vector->header.domain, 0);
1198 }
1199 grn_bulk_write(ctx, &value, _value, length);
1200 grn_output_obj(ctx, outbuf, output_type, &value, NULL);
1201 }
1202 grn_output_array_close(ctx, outbuf, output_type);
1203 GRN_OBJ_FIN(ctx, &value);
1204 }
1205}
1206
1207static inline void
1208grn_output_pvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
1209 grn_obj *pvector, grn_obj_format *format)
1210{
1211 if (format) {
1212 ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
1213 "cannot print GRN_PVECTOR using grn_obj_format");
1214 } else {
1215 unsigned int i, n;
1216 grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
1217 n = GRN_BULK_VSIZE(pvector) / sizeof(grn_obj *);
1218 for (i = 0; i < n; i++) {
1219 grn_obj *value;
1220
1221 value = GRN_PTR_VALUE_AT(pvector, i);
1222 grn_output_obj(ctx, outbuf, output_type, value, NULL);
1223 }
1224 grn_output_array_close(ctx, outbuf, output_type);
1225 }
1226}
1227
1228static inline void
1229grn_output_result_set_n_hits_v1(grn_ctx *ctx,
1230 grn_obj *outbuf,
1231 grn_content_type output_type,
1232 grn_obj_format *format)
1233{
1234 grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
1235 if (output_type == GRN_CONTENT_XML) {
1236 grn_text_itoa(ctx, outbuf, format->nhits);
1237 } else {
1238 grn_output_int32(ctx, outbuf, output_type, format->nhits);
1239 }
1240 grn_output_array_close(ctx, outbuf, output_type);
1241}
1242
1243static inline void
1244grn_output_result_set_n_hits_v3(grn_ctx *ctx,
1245 grn_obj *outbuf,
1246 grn_content_type output_type,
1247 grn_obj_format *format)
1248{
1249 grn_output_cstr(ctx, outbuf, output_type, "n_hits");
1250 grn_output_int32(ctx, outbuf, output_type, format->nhits);
1251}
1252
1253static inline void
1254grn_output_result_set_n_hits(grn_ctx *ctx,
1255 grn_obj *outbuf,
1256 grn_content_type output_type,
1257 grn_obj_format *format)
1258{
1259 if (format->nhits == -1) {
1260 return;
1261 }
1262
1263 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1264 grn_output_result_set_n_hits_v1(ctx, outbuf, output_type, format);
1265 } else {
1266 grn_output_result_set_n_hits_v3(ctx, outbuf, output_type, format);
1267 }
1268}
1269
1270static inline void
1271grn_output_table_column_info(grn_ctx *ctx,
1272 grn_obj *outbuf,
1273 grn_content_type output_type,
1274 const char *name,
1275 const char *type)
1276{
1277 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1278 grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
1279 if (name) {
1280 grn_output_cstr(ctx, outbuf, output_type, name);
1281 } else {
1282 grn_output_null(ctx, outbuf, output_type);
1283 }
1284 if (type) {
1285 grn_output_cstr(ctx, outbuf, output_type, type);
1286 } else {
1287 grn_output_null(ctx, outbuf, output_type);
1288 }
1289 grn_output_array_close(ctx, outbuf, output_type);
1290 } else {
1291 grn_output_map_open(ctx, outbuf, output_type, "column", 2);
1292 grn_output_cstr(ctx, outbuf, output_type, "name");
1293 if (name) {
1294 grn_output_cstr(ctx, outbuf, output_type, name);
1295 } else {
1296 grn_output_null(ctx, outbuf, output_type);
1297 }
1298 grn_output_cstr(ctx, outbuf, output_type, "type");
1299 if (type) {
1300 grn_output_cstr(ctx, outbuf, output_type, type);
1301 } else {
1302 grn_output_null(ctx, outbuf, output_type);
1303 }
1304 grn_output_map_close(ctx, outbuf, output_type);
1305 }
1306}
1307
1308static inline int
1309count_n_elements_in_expression(grn_ctx *ctx, grn_obj *expression)
1310{
1311 int n_elements = 0;
1312 grn_bool is_first_comma = GRN_TRUE;
1313 grn_expr *expr = (grn_expr *)expression;
1314 grn_expr_code *code;
1315 grn_expr_code *code_end = expr->codes + expr->codes_curr;
1316
1317 for (code = expr->codes; code < code_end; code++) {
1318 if (code->op == GRN_OP_COMMA) {
1319 n_elements++;
1320 if (is_first_comma) {
1321 n_elements++;
1322 is_first_comma = GRN_FALSE;
1323 }
1324 }
1325 }
1326
1327 return n_elements;
1328}
1329
1330static grn_bool
1331is_score_accessor(grn_ctx *ctx, grn_obj *obj)
1332{
1333 grn_accessor *a;
1334
1335 if (obj->header.type != GRN_ACCESSOR) {
1336 return GRN_FALSE;
1337 }
1338
1339 for (a = (grn_accessor *)obj; a->next; a = a->next) {
1340 }
1341 return a->action == GRN_ACCESSOR_GET_SCORE;
1342}
1343
1344static inline void
1345grn_output_table_column(grn_ctx *ctx, grn_obj *outbuf,
1346 grn_content_type output_type,
1347 grn_obj *column, grn_obj *buf)
1348{
1349 grn_id range_id = GRN_ID_NIL;
1350
1351 if (!column) {
1352 grn_output_table_column_info(ctx, outbuf, output_type, NULL, NULL);
1353 return;
1354 }
1355
1356 GRN_BULK_REWIND(buf);
1357 grn_column_name_(ctx, column, buf);
1358 GRN_TEXT_PUTC(ctx, buf, '\0');
1359
1360 if (column->header.type == GRN_COLUMN_INDEX) {
1361 range_id = GRN_DB_UINT32;
1362 } else if (is_score_accessor(ctx, column)) {
1363 if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
1364 range_id = GRN_DB_INT32;
1365 } else {
1366 range_id = GRN_DB_FLOAT;
1367 }
1368 }
1369 if (range_id == GRN_ID_NIL) {
1370 range_id = grn_obj_get_range(ctx, column);
1371 }
1372 if (range_id == GRN_ID_NIL) {
1373 grn_output_table_column_info(ctx,
1374 outbuf,
1375 output_type,
1376 GRN_TEXT_VALUE(buf),
1377 NULL);
1378 } else {
1379 grn_obj *range_obj;
1380 char type_name[GRN_TABLE_MAX_KEY_SIZE];
1381 int type_name_len;
1382
1383 range_obj = grn_ctx_at(ctx, range_id);
1384 type_name_len = grn_obj_name(ctx,
1385 range_obj,
1386 type_name,
1387 GRN_TABLE_MAX_KEY_SIZE);
1388 type_name[type_name_len] = '\0';
1389 grn_output_table_column_info(ctx,
1390 outbuf,
1391 output_type,
1392 GRN_TEXT_VALUE(buf),
1393 type_name);
1394 }
1395}
1396
1397static inline void
1398grn_output_table_column_by_expression(grn_ctx *ctx, grn_obj *outbuf,
1399 grn_content_type output_type,
1400 grn_expr_code *code,
1401 grn_expr_code *code_end,
1402 grn_obj *buf)
1403{
1404 if (code_end <= code) {
1405 grn_output_table_column_info(ctx,
1406 outbuf,
1407 output_type,
1408 NULL,
1409 NULL);
1410 return;
1411 }
1412
1413 switch (code_end[-1].op) {
1414 case GRN_OP_GET_MEMBER :
1415 if ((code_end - code) == 3) {
1416 GRN_BULK_REWIND(buf);
1417 grn_column_name_(ctx, code[0].value, buf);
1418 GRN_TEXT_PUTC(ctx, buf, '[');
1419 grn_inspect(ctx, buf, code[1].value);
1420 GRN_TEXT_PUTC(ctx, buf, ']');
1421 GRN_TEXT_PUTC(ctx, buf, '\0');
1422
1423 grn_output_table_column_info(ctx,
1424 outbuf,
1425 output_type,
1426 GRN_TEXT_VALUE(buf),
1427 NULL);
1428 } else {
1429 grn_output_table_column(ctx, outbuf, output_type, code->value, buf);
1430 }
1431 break;
1432 default :
1433 grn_output_table_column(ctx, outbuf, output_type, code->value, buf);
1434 break;
1435 }
1436}
1437
1438static inline void
1439grn_output_table_columns_open(grn_ctx *ctx,
1440 grn_obj *outbuf,
1441 grn_content_type output_type,
1442 int n_columns)
1443{
1444 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1445 grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_columns);
1446 } else {
1447 grn_output_cstr(ctx, outbuf, output_type, "columns");
1448 grn_output_array_open(ctx, outbuf, output_type, "columns", n_columns);
1449 }
1450}
1451
1452static inline void
1453grn_output_table_columns_close(grn_ctx *ctx,
1454 grn_obj *outbuf,
1455 grn_content_type output_type)
1456{
1457 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1458 grn_output_array_close(ctx, outbuf, output_type);
1459 } else {
1460 grn_output_array_close(ctx, outbuf, output_type);
1461 }
1462}
1463
1464static inline void
1465grn_output_table_columns_by_expression(grn_ctx *ctx, grn_obj *outbuf,
1466 grn_content_type output_type,
1467 grn_obj *table, grn_obj_format *format,
1468 grn_obj *buf)
1469{
1470 int n_elements;
1471 int previous_comma_offset = -1;
1472 grn_bool is_first_comma = GRN_TRUE;
1473 grn_bool have_comma = GRN_FALSE;
1474 grn_expr *expr = (grn_expr *)format->expression;
1475 grn_expr_code *code;
1476 grn_expr_code *code_end = expr->codes + expr->codes_curr;
1477
1478 n_elements = count_n_elements_in_expression(ctx, format->expression);
1479
1480 grn_output_table_columns_open(ctx, outbuf, output_type, n_elements);
1481
1482 for (code = expr->codes; code < code_end; code++) {
1483 int code_start_offset;
1484
1485 if (code->op != GRN_OP_COMMA) {
1486 continue;
1487 }
1488
1489 have_comma = GRN_TRUE;
1490 if (is_first_comma) {
1491 unsigned int n_used_codes;
1492 int code_end_offset;
1493
1494 n_used_codes = grn_expr_code_n_used_codes(ctx, expr->codes, code - 1);
1495 code_end_offset = code - expr->codes - n_used_codes;
1496
1497 grn_output_table_column_by_expression(ctx, outbuf, output_type,
1498 expr->codes,
1499 expr->codes + code_end_offset,
1500 buf);
1501 code_start_offset = code_end_offset;
1502 is_first_comma = GRN_FALSE;
1503 } else {
1504 code_start_offset = previous_comma_offset + 1;
1505 }
1506
1507 grn_output_table_column_by_expression(ctx, outbuf, output_type,
1508 expr->codes + code_start_offset,
1509 code,
1510 buf);
1511 previous_comma_offset = code - expr->codes;
1512 }
1513
1514 if (!have_comma && expr->codes_curr > 0) {
1515 grn_output_table_column_by_expression(ctx, outbuf, output_type,
1516 expr->codes,
1517 code_end,
1518 buf);
1519 }
1520
1521 grn_output_table_columns_close(ctx, outbuf, output_type);
1522}
1523
1524static inline void
1525grn_output_table_columns_by_columns(grn_ctx *ctx, grn_obj *outbuf,
1526 grn_content_type output_type,
1527 grn_obj *table, grn_obj_format *format,
1528 grn_obj *buf)
1529{
1530 int i;
1531 int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
1532 grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
1533
1534 grn_output_table_columns_open(ctx, outbuf, output_type, ncolumns);
1535 for (i = 0; i < ncolumns; i++) {
1536 grn_output_table_column(ctx, outbuf, output_type, columns[i], buf);
1537 }
1538 grn_output_table_columns_close(ctx, outbuf, output_type);
1539}
1540
1541void
1542grn_output_table_columns(grn_ctx *ctx, grn_obj *outbuf,
1543 grn_content_type output_type,
1544 grn_obj *table, grn_obj_format *format)
1545{
1546 grn_obj buf;
1547
1548 GRN_TEXT_INIT(&buf, 0);
1549 if (format->expression) {
1550 grn_output_table_columns_by_expression(ctx, outbuf, output_type,
1551 table, format, &buf);
1552 } else {
1553 grn_output_table_columns_by_columns(ctx, outbuf, output_type,
1554 table, format, &buf);
1555 }
1556 GRN_OBJ_FIN(ctx, &buf);
1557}
1558
1559static inline void
1560grn_output_table_record_open(grn_ctx *ctx,
1561 grn_obj *outbuf,
1562 grn_content_type output_type,
1563 int n_columns)
1564{
1565 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1566 grn_output_array_open(ctx, outbuf, output_type, "HIT", n_columns);
1567 } else {
1568 grn_output_array_open(ctx, outbuf, output_type, "record", n_columns);
1569 }
1570}
1571
1572static inline void
1573grn_output_table_record_close(grn_ctx *ctx,
1574 grn_obj *outbuf,
1575 grn_content_type output_type)
1576{
1577 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1578 grn_output_array_close(ctx, outbuf, output_type);
1579 } else {
1580 grn_output_array_close(ctx, outbuf, output_type);
1581 }
1582}
1583
1584static inline void
1585grn_output_table_record_by_column(grn_ctx *ctx,
1586 grn_obj *outbuf,
1587 grn_content_type output_type,
1588 grn_obj *column,
1589 grn_id id)
1590{
1591 grn_text_atoj(ctx, outbuf, output_type, column, id);
1592}
1593
1594static inline void
1595grn_output_table_record_by_expression(grn_ctx *ctx,
1596 grn_obj *outbuf,
1597 grn_content_type output_type,
1598 grn_obj *expression,
1599 grn_obj *record)
1600{
1601 grn_expr *expr = (grn_expr *)expression;
1602
1603 if (expr->codes_curr == 1 && expr->codes[0].op == GRN_OP_GET_VALUE) {
1604 grn_obj *column = expr->codes[0].value;
1605 grn_output_table_record_by_column(ctx,
1606 outbuf,
1607 output_type,
1608 column,
1609 GRN_RECORD_VALUE(record));
1610 } else {
1611 grn_obj *result;
1612 result = grn_expr_exec(ctx, expression, 0);
1613 if (result) {
1614 grn_output_obj(ctx, outbuf, output_type, result, NULL);
1615 } else {
1616 grn_output_cstr(ctx, outbuf, output_type, ctx->errbuf);
1617 }
1618 }
1619}
1620
1621static inline void
1622grn_output_table_records_by_expression(grn_ctx *ctx, grn_obj *outbuf,
1623 grn_content_type output_type,
1624 grn_table_cursor *tc,
1625 grn_obj_format *format)
1626{
1627 int n_elements = 0;
1628 grn_id id;
1629 grn_obj *record;
1630 grn_expr *expr = (grn_expr *)format->expression;
1631 grn_expr_code *code;
1632 grn_expr_code *code_end = expr->codes + expr->codes_curr;
1633
1634 n_elements = count_n_elements_in_expression(ctx, format->expression);
1635 record = grn_expr_get_var_by_offset(ctx, format->expression, 0);
1636 while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
1637 int previous_comma_offset = -1;
1638 grn_bool is_first_comma = GRN_TRUE;
1639 grn_bool have_comma = GRN_FALSE;
1640 GRN_RECORD_SET(ctx, record, id);
1641 grn_output_table_record_open(ctx, outbuf, output_type, n_elements);
1642 for (code = expr->codes; code < code_end; code++) {
1643 if (code->op == GRN_OP_COMMA) {
1644 int code_start_offset = previous_comma_offset + 1;
1645 int code_end_offset;
1646 int original_codes_curr = expr->codes_curr;
1647
1648 have_comma = GRN_TRUE;
1649 if (is_first_comma) {
1650 int second_code_offset;
1651 unsigned int second_code_n_used_codes;
1652 second_code_offset = code - expr->codes - 1;
1653 second_code_n_used_codes =
1654 grn_expr_code_n_used_codes(ctx,
1655 expr->codes,
1656 expr->codes + second_code_offset);
1657 expr->codes_curr = second_code_offset - second_code_n_used_codes + 1;
1658 grn_output_table_record_by_expression(ctx,
1659 outbuf,
1660 output_type,
1661 format->expression,
1662 record);
1663 code_start_offset = expr->codes_curr;
1664 is_first_comma = GRN_FALSE;
1665 }
1666 code_end_offset = code - expr->codes - code_start_offset;
1667 expr->codes += code_start_offset;
1668 expr->codes_curr = code_end_offset;
1669 grn_output_table_record_by_expression(ctx,
1670 outbuf,
1671 output_type,
1672 format->expression,
1673 record);
1674 expr->codes -= code_start_offset;
1675 expr->codes_curr = original_codes_curr;
1676 previous_comma_offset = code - expr->codes;
1677 }
1678 }
1679
1680 if (!have_comma && expr->codes_curr > 0) {
1681 grn_output_table_record_by_expression(ctx,
1682 outbuf,
1683 output_type,
1684 format->expression,
1685 record);
1686 }
1687
1688 grn_output_table_record_close(ctx, outbuf, output_type);
1689 }
1690}
1691
1692static inline void
1693grn_output_table_records_by_columns(grn_ctx *ctx, grn_obj *outbuf,
1694 grn_content_type output_type,
1695 grn_table_cursor *tc,
1696 grn_obj_format *format)
1697{
1698 int i;
1699 grn_id id;
1700 int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
1701 grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
1702 while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
1703 grn_output_table_record_open(ctx, outbuf, output_type, ncolumns);
1704 for (i = 0; i < ncolumns; i++) {
1705 grn_output_table_record_by_column(ctx,
1706 outbuf,
1707 output_type,
1708 columns[i],
1709 id);
1710 }
1711 grn_output_table_record_close(ctx, outbuf, output_type);
1712 }
1713}
1714
1715static inline void
1716grn_output_table_records_open(grn_ctx *ctx,
1717 grn_obj *outbuf,
1718 grn_content_type output_type,
1719 int n_records)
1720{
1721 if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
1722 grn_output_cstr(ctx, outbuf, output_type, "records");
1723 grn_output_array_open(ctx, outbuf, output_type, "records", n_records);
1724 }
1725}
1726
1727static inline void
1728grn_output_table_records_close(grn_ctx *ctx,
1729 grn_obj *outbuf,
1730 grn_content_type output_type)
1731{
1732 if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
1733 grn_output_array_close(ctx, outbuf, output_type);
1734 }
1735}
1736
1737void
1738grn_output_table_records(grn_ctx *ctx, grn_obj *outbuf,
1739 grn_content_type output_type,
1740 grn_obj *table, grn_obj_format *format)
1741{
1742 grn_table_cursor *tc;
1743
1744 grn_output_table_records_open(ctx, outbuf, output_type, format->limit);
1745 tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
1746 format->offset, format->limit,
1747 GRN_CURSOR_ASCENDING);
1748 if (tc) {
1749 if (format->expression) {
1750 grn_output_table_records_by_expression(ctx, outbuf, output_type,
1751 tc, format);
1752 } else {
1753 grn_output_table_records_by_columns(ctx, outbuf, output_type,
1754 tc, format);
1755 }
1756 grn_table_cursor_close(ctx, tc);
1757 } else {
1758 ERRCLR(ctx);
1759 }
1760 grn_output_table_records_close(ctx, outbuf, output_type);
1761}
1762
1763static void
1764grn_output_result_set_open_v1(grn_ctx *ctx,
1765 grn_obj *outbuf,
1766 grn_content_type output_type,
1767 grn_obj *table,
1768 grn_obj_format *format,
1769 uint32_t n_additional_elements)
1770{
1771 grn_obj buf;
1772 GRN_TEXT_INIT(&buf, 0);
1773 if (format) {
1774 int resultset_size = 1;
1775 /* resultset: [NHITS, (COLUMNS), (HITS)] */
1776 if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
1777 resultset_size++;
1778 }
1779 resultset_size += format->limit;
1780 resultset_size += n_additional_elements;
1781 grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", resultset_size);
1782 grn_output_result_set_n_hits(ctx, outbuf, output_type, format);
1783 if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
1784 grn_output_table_columns(ctx, outbuf, output_type, table, format);
1785 }
1786 grn_output_table_records(ctx, outbuf, output_type, table, format);
1787 } else {
1788 int i;
1789 grn_obj *column = grn_obj_column(ctx, table,
1790 GRN_COLUMN_NAME_KEY,
1791 GRN_COLUMN_NAME_KEY_LEN);
1792 grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
1793 0, -1, GRN_CURSOR_ASCENDING);
1794 grn_output_array_open(ctx, outbuf, output_type, "HIT", -1);
1795 if (tc) {
1796 grn_id id;
1797 for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
1798 GRN_BULK_REWIND(&buf);
1799 grn_obj_get_value(ctx, column, id, &buf);
1800 grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
1801 }
1802 grn_table_cursor_close(ctx, tc);
1803 }
1804 grn_obj_unlink(ctx, column);
1805 }
1806 GRN_OBJ_FIN(ctx, &buf);
1807}
1808
1809static void
1810grn_output_result_set_close_v1(grn_ctx *ctx,
1811 grn_obj *outbuf,
1812 grn_content_type output_type,
1813 grn_obj *table,
1814 grn_obj_format *format)
1815{
1816 grn_output_array_close(ctx, outbuf, output_type);
1817}
1818
1819static void
1820grn_output_result_set_open_v3(grn_ctx *ctx,
1821 grn_obj *outbuf,
1822 grn_content_type output_type,
1823 grn_obj *result_set,
1824 grn_obj_format *format,
1825 uint32_t n_additional_elements)
1826{
1827 grn_obj buf;
1828 GRN_TEXT_INIT(&buf, 0);
1829 if (format) {
1830 int n_elements = 2;
1831 /* result_set: {"n_hits": N, ("columns": COLUMNS,) "records": records} */
1832 if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
1833 n_elements++;
1834 }
1835 n_elements += n_additional_elements;
1836 grn_output_map_open(ctx, outbuf, output_type, "result_set", n_elements);
1837 grn_output_result_set_n_hits(ctx, outbuf, output_type, format);
1838 if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
1839 grn_output_table_columns(ctx, outbuf, output_type, result_set, format);
1840 }
1841 grn_output_table_records(ctx, outbuf, output_type, result_set, format);
1842 } else {
1843 grn_obj *column;
1844 int n_records;
1845 int n_elements = 1;
1846
1847 column = grn_obj_column(ctx,
1848 result_set,
1849 GRN_COLUMN_NAME_KEY,
1850 GRN_COLUMN_NAME_KEY_LEN);
1851 n_elements += n_additional_elements;
1852 grn_output_map_open(ctx, outbuf, output_type, "result_set", n_elements);
1853 n_records = grn_table_size(ctx, result_set);
1854 grn_output_cstr(ctx, outbuf, output_type, "keys");
1855 grn_output_array_open(ctx, outbuf, output_type, "keys", n_records);
1856 GRN_TABLE_EACH_BEGIN(ctx, result_set, cursor, id) {
1857 GRN_BULK_REWIND(&buf);
1858 grn_obj_get_value(ctx, column, id, &buf);
1859 grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
1860 } GRN_TABLE_EACH_END(ctx, cursor);
1861 grn_output_array_close(ctx, outbuf, output_type);
1862 grn_obj_unlink(ctx, column);
1863 }
1864 GRN_OBJ_FIN(ctx, &buf);
1865}
1866
1867static void
1868grn_output_result_set_close_v3(grn_ctx *ctx,
1869 grn_obj *outbuf,
1870 grn_content_type output_type,
1871 grn_obj *result_set,
1872 grn_obj_format *format)
1873{
1874 grn_output_map_close(ctx, outbuf, output_type);
1875}
1876
1877void
1878grn_output_result_set_open(grn_ctx *ctx,
1879 grn_obj *outbuf,
1880 grn_content_type output_type,
1881 grn_obj *result_set,
1882 grn_obj_format *format,
1883 uint32_t n_additional_elements)
1884{
1885 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1886 grn_output_result_set_open_v1(ctx,
1887 outbuf,
1888 output_type,
1889 result_set,
1890 format,
1891 n_additional_elements);
1892 } else {
1893 grn_output_result_set_open_v3(ctx,
1894 outbuf,
1895 output_type,
1896 result_set,
1897 format,
1898 n_additional_elements);
1899 }
1900}
1901
1902void
1903grn_output_result_set_close(grn_ctx *ctx,
1904 grn_obj *outbuf,
1905 grn_content_type output_type,
1906 grn_obj *result_set,
1907 grn_obj_format *format)
1908{
1909 if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
1910 grn_output_result_set_close_v1(ctx, outbuf, output_type, result_set, format);
1911 } else {
1912 grn_output_result_set_close_v3(ctx, outbuf, output_type, result_set, format);
1913 }
1914}
1915
1916void
1917grn_output_result_set(grn_ctx *ctx,
1918 grn_obj *outbuf,
1919 grn_content_type output_type,
1920 grn_obj *result_set,
1921 grn_obj_format *format)
1922{
1923 uint32_t n_additional_elements = 0;
1924
1925 grn_output_result_set_open(ctx,
1926 outbuf,
1927 output_type,
1928 result_set,
1929 format,
1930 n_additional_elements);
1931 grn_output_result_set_close(ctx, outbuf, output_type, result_set, format);
1932}
1933
1934void
1935grn_output_obj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
1936 grn_obj *obj, grn_obj_format *format)
1937{
1938 grn_obj buf;
1939 GRN_TEXT_INIT(&buf, 0);
1940 switch (obj->header.type) {
1941 case GRN_VOID :
1942 grn_output_void(ctx, outbuf, output_type, obj, format);
1943 break;
1944 case GRN_BULK :
1945 grn_output_bulk(ctx, outbuf, output_type, obj, format);
1946 break;
1947 case GRN_UVECTOR :
1948 grn_output_uvector(ctx, outbuf, output_type, obj, format);
1949 break;
1950 case GRN_VECTOR :
1951 grn_output_vector(ctx, outbuf, output_type, obj, format);
1952 break;
1953 case GRN_PVECTOR :
1954 grn_output_pvector(ctx, outbuf, output_type, obj, format);
1955 break;
1956 case GRN_TABLE_HASH_KEY :
1957 case GRN_TABLE_PAT_KEY :
1958 case GRN_TABLE_DAT_KEY :
1959 case GRN_TABLE_NO_KEY :
1960 /* Deprecated. Use grn_output_result_set() directly. */
1961 grn_output_result_set(ctx, outbuf, output_type, obj, format);
1962 break;
1963 }
1964 GRN_OBJ_FIN(ctx, &buf);
1965}
1966
1967typedef enum {
1968 XML_START,
1969 XML_START_ELEMENT,
1970 XML_END_ELEMENT,
1971 XML_TEXT
1972} xml_status;
1973
1974typedef enum {
1975 XML_PLACE_NONE,
1976 XML_PLACE_COLUMN,
1977 XML_PLACE_HIT
1978} xml_place;
1979
1980static char *
1981transform_xml_next_column(grn_obj *columns, int n)
1982{
1983 char *column = GRN_TEXT_VALUE(columns);
1984 while (n--) {
1985 while (*column) {
1986 column++;
1987 }
1988 column++;
1989 }
1990 return column;
1991}
1992
1993static void
1994transform_xml(grn_ctx *ctx, grn_obj *output, grn_obj *transformed)
1995{
1996 char *s, *e;
1997 xml_status status = XML_START;
1998 xml_place place = XML_PLACE_NONE;
1999 grn_obj buf, name, columns, *expr;
2000 unsigned int len;
2001 int offset = 0, limit = 0, record_n = 0;
2002 int column_n = 0, column_text_n = 0, result_set_n = -1;
2003 grn_bool in_vector = GRN_FALSE;
2004 unsigned int vector_element_n = 0;
2005 grn_bool in_weight_vector = GRN_FALSE;
2006 unsigned int weight_vector_item_n = 0;
2007
2008 s = GRN_TEXT_VALUE(output);
2009 e = GRN_BULK_CURR(output);
2010 GRN_TEXT_INIT(&buf, 0);
2011 GRN_TEXT_INIT(&name, 0);
2012 GRN_TEXT_INIT(&columns, 0);
2013
2014 expr = ctx->impl->curr_expr;
2015
2016#define EQUAL_NAME_P(_name) \
2017 (GRN_TEXT_LEN(&name) == strlen(_name) && \
2018 !memcmp(GRN_TEXT_VALUE(&name), _name, strlen(_name)))
2019
2020 while (s < e) {
2021 switch (*s) {
2022 case '<' :
2023 s++;
2024 switch (*s) {
2025 case '/' :
2026 status = XML_END_ELEMENT;
2027 s++;
2028 break;
2029 default :
2030 status = XML_START_ELEMENT;
2031 break;
2032 }
2033 GRN_BULK_REWIND(&name);
2034 break;
2035 case '>' :
2036 switch (status) {
2037 case XML_START_ELEMENT :
2038 if (EQUAL_NAME_P("COLUMN")) {
2039 place = XML_PLACE_COLUMN;
2040 column_text_n = 0;
2041 } else if (EQUAL_NAME_P("HIT")) {
2042 place = XML_PLACE_HIT;
2043 column_n = 0;
2044 if (result_set_n == 0) {
2045 GRN_TEXT_PUTS(ctx, transformed, "<HIT NO=\"");
2046 grn_text_itoa(ctx, transformed, record_n++);
2047 GRN_TEXT_PUTS(ctx, transformed, "\">\n");
2048 } else {
2049 GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONELEMENT ");
2050 }
2051 } else if (EQUAL_NAME_P("RESULTSET")) {
2052 GRN_BULK_REWIND(&columns);
2053 result_set_n++;
2054 if (result_set_n == 0) {
2055 } else {
2056 GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONENTRY>\n");
2057 }
2058 } else if (EQUAL_NAME_P("VECTOR")) {
2059 char *c = transform_xml_next_column(&columns, column_n++);
2060 in_vector = GRN_TRUE;
2061 vector_element_n = 0;
2062 GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
2063 GRN_TEXT_PUTS(ctx, transformed, c);
2064 GRN_TEXT_PUTS(ctx, transformed, "\">");
2065 } else if (EQUAL_NAME_P("WEIGHT_VECTOR")) {
2066 char *c = transform_xml_next_column(&columns, column_n++);
2067 in_weight_vector = GRN_TRUE;
2068 weight_vector_item_n = 0;
2069 GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
2070 GRN_TEXT_PUTS(ctx, transformed, c);
2071 GRN_TEXT_PUTS(ctx, transformed, "\">");
2072 }
2073 break;
2074 case XML_END_ELEMENT :
2075 if (EQUAL_NAME_P("HIT")) {
2076 place = XML_PLACE_NONE;
2077 if (result_set_n == 0) {
2078 GRN_TEXT_PUTS(ctx, transformed, "</HIT>\n");
2079 } else {
2080 GRN_TEXT_PUTS(ctx, transformed, "/>\n");
2081 }
2082 } else if (EQUAL_NAME_P("RESULTSET")) {
2083 place = XML_PLACE_NONE;
2084 if (result_set_n == 0) {
2085 GRN_TEXT_PUTS(ctx, transformed, "</RESULTSET>\n");
2086 } else {
2087 GRN_TEXT_PUTS(ctx, transformed,
2088 "</NAVIGATIONELEMENTS>\n"
2089 "</NAVIGATIONENTRY>\n");
2090 }
2091 } else if (EQUAL_NAME_P("RESULT")) {
2092 GRN_TEXT_PUTS(ctx, transformed,
2093 "</RESULTPAGE>\n"
2094 "</SEGMENT>\n"
2095 "</SEGMENTS>\n");
2096 } else if (EQUAL_NAME_P("VECTOR")) {
2097 in_vector = GRN_FALSE;
2098 GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
2099 } else if (EQUAL_NAME_P("WEIGHT_VECTOR")) {
2100 in_weight_vector = GRN_FALSE;
2101 GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
2102 } else {
2103 switch (place) {
2104 case XML_PLACE_HIT :
2105 if (result_set_n == 0) {
2106 if (in_vector) {
2107 if (vector_element_n > 0) {
2108 GRN_TEXT_PUTS(ctx, transformed, ", ");
2109 }
2110 GRN_TEXT_PUT(ctx, transformed,
2111 GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2112 vector_element_n++;
2113 } else if (in_weight_vector) {
2114 grn_bool is_key;
2115 is_key = ((weight_vector_item_n % 2) == 0);
2116 if (is_key) {
2117 unsigned int weight_vector_key_n;
2118 weight_vector_key_n = weight_vector_item_n / 2;
2119 if (weight_vector_key_n > 0) {
2120 GRN_TEXT_PUTS(ctx, transformed, ", ");
2121 }
2122 } else {
2123 GRN_TEXT_PUTS(ctx, transformed, ":");
2124 }
2125 GRN_TEXT_PUT(ctx, transformed,
2126 GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2127 weight_vector_item_n++;
2128 } else {
2129 char *c = transform_xml_next_column(&columns, column_n++);
2130 GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
2131 GRN_TEXT_PUTS(ctx, transformed, c);
2132 GRN_TEXT_PUTS(ctx, transformed, "\">");
2133 GRN_TEXT_PUT(ctx, transformed,
2134 GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2135 GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
2136 }
2137 } else {
2138 char *c = transform_xml_next_column(&columns, column_n++);
2139 GRN_TEXT_PUTS(ctx, transformed, c);
2140 GRN_TEXT_PUTS(ctx, transformed, "=\"");
2141 GRN_TEXT_PUT(ctx, transformed,
2142 GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2143 GRN_TEXT_PUTS(ctx, transformed, "\" ");
2144 }
2145 break;
2146 default :
2147 if (EQUAL_NAME_P("NHITS")) {
2148 if (result_set_n == 0) {
2149 uint32_t nhits;
2150 grn_obj *offset_value, *limit_value;
2151
2152 nhits = grn_atoui(GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf),
2153 NULL);
2154 offset_value = grn_expr_get_var(ctx, expr,
2155 "offset", strlen("offset"));
2156 limit_value = grn_expr_get_var(ctx, expr,
2157 "limit", strlen("limit"));
2158 if (GRN_TEXT_LEN(offset_value)) {
2159 offset = grn_atoi(GRN_TEXT_VALUE(offset_value),
2160 GRN_BULK_CURR(offset_value),
2161 NULL);
2162 } else {
2163 offset = 0;
2164 }
2165 if (GRN_TEXT_LEN(limit_value)) {
2166 limit = grn_atoi(GRN_TEXT_VALUE(limit_value),
2167 GRN_BULK_CURR(limit_value),
2168 NULL);
2169 } else {
2170#define DEFAULT_LIMIT 10
2171 limit = DEFAULT_LIMIT;
2172#undef DEFAULT_LIMIT
2173 }
2174 grn_normalize_offset_and_limit(ctx, nhits, &offset, &limit);
2175 record_n = offset + 1;
2176 GRN_TEXT_PUTS(ctx, transformed,
2177 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
2178 "<SEGMENTS>\n"
2179 "<SEGMENT>\n"
2180 "<RESULTPAGE>\n"
2181 "<RESULTSET OFFSET=\"");
2182 grn_text_lltoa(ctx, transformed, offset);
2183 GRN_TEXT_PUTS(ctx, transformed, "\" LIMIT=\"");
2184 grn_text_lltoa(ctx, transformed, limit);
2185 GRN_TEXT_PUTS(ctx, transformed, "\" NHITS=\"");
2186 grn_text_lltoa(ctx, transformed, nhits);
2187 GRN_TEXT_PUTS(ctx, transformed, "\">\n");
2188 } else {
2189 GRN_TEXT_PUTS(ctx, transformed,
2190 "<NAVIGATIONELEMENTS COUNT=\"");
2191 GRN_TEXT_PUT(ctx, transformed,
2192 GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2193 GRN_TEXT_PUTS(ctx, transformed,
2194 "\">\n");
2195 }
2196 } else if (EQUAL_NAME_P("TEXT")) {
2197 switch (place) {
2198 case XML_PLACE_COLUMN :
2199 if (column_text_n == 0) {
2200 GRN_TEXT_PUT(ctx, &columns,
2201 GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
2202 GRN_TEXT_PUTC(ctx, &columns, '\0');
2203 }
2204 column_text_n++;
2205 break;
2206 default :
2207 break;
2208 }
2209 }
2210 }
2211 }
2212 default :
2213 break;
2214 }
2215 s++;
2216 GRN_BULK_REWIND(&buf);
2217 status = XML_TEXT;
2218 break;
2219 default :
2220 len = grn_charlen(ctx, s, e);
2221 switch (status) {
2222 case XML_START_ELEMENT :
2223 case XML_END_ELEMENT :
2224 GRN_TEXT_PUT(ctx, &name, s, len);
2225 break;
2226 default :
2227 GRN_TEXT_PUT(ctx, &buf, s, len);
2228 break;
2229 }
2230 s += len;
2231 break;
2232 }
2233 }
2234#undef EQUAL_NAME_P
2235
2236 GRN_OBJ_FIN(ctx, &buf);
2237 GRN_OBJ_FIN(ctx, &name);
2238 GRN_OBJ_FIN(ctx, &columns);
2239}
2240
2241#ifdef GRN_WITH_MESSAGE_PACK
2242typedef struct {
2243 grn_ctx *ctx;
2244 grn_obj *buffer;
2245} msgpack_writer_ctx;
2246
2247static inline int
2248msgpack_buffer_writer(void* data, const char* buf, msgpack_size_t len)
2249{
2250 msgpack_writer_ctx *writer_ctx = (msgpack_writer_ctx *)data;
2251 return grn_bulk_write(writer_ctx->ctx, writer_ctx->buffer, buf, len);
2252}
2253#endif
2254
2255#define JSON_CALLBACK_PARAM "callback"
2256
2257static void
2258grn_output_envelope_json_v1(grn_ctx *ctx,
2259 grn_rc rc,
2260 grn_obj *head,
2261 grn_obj *body,
2262 grn_obj *foot,
2263 double started,
2264 double elapsed,
2265 const char *file,
2266 int line)
2267{
2268 size_t indent_level = 0;
2269
2270 json_array_open(ctx, head, &indent_level);
2271 {
2272 json_array_open(ctx, head, &indent_level);
2273 {
2274 grn_text_itoa(ctx, head, rc);
2275
2276 json_element_end(ctx, head, indent_level);
2277 grn_text_ftoa(ctx, head, started);
2278
2279 json_element_end(ctx, head, indent_level);
2280 grn_text_ftoa(ctx, head, elapsed);
2281
2282 if (rc != GRN_SUCCESS) {
2283 json_element_end(ctx, head, indent_level);
2284 grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
2285
2286 if (ctx->errfunc && ctx->errfile) {
2287 grn_obj *command;
2288
2289 json_element_end(ctx, head, indent_level);
2290 json_array_open(ctx, head, &indent_level);
2291 {
2292 json_array_open(ctx, head, &indent_level);
2293 {
2294 grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
2295
2296 json_element_end(ctx, head, indent_level);
2297 grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
2298
2299 json_element_end(ctx, head, indent_level);
2300 grn_text_itoa(ctx, head, ctx->errline);
2301 }
2302 json_array_close(ctx, head, &indent_level);
2303
2304 if (file && (command = GRN_CTX_USER_DATA(ctx)->ptr)) {
2305 json_element_end(ctx, head, indent_level);
2306 json_array_open(ctx, head, &indent_level);
2307 {
2308 grn_text_esc(ctx, head, file, strlen(file));
2309
2310 json_element_end(ctx, head, indent_level);
2311 grn_text_itoa(ctx, head, line);
2312
2313 json_element_end(ctx, head, indent_level);
2314 grn_text_esc(ctx, head,
2315 GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
2316 }
2317 json_array_close(ctx, head, &indent_level);
2318 }
2319 }
2320 json_array_close(ctx, head, &indent_level);
2321 }
2322 }
2323 }
2324 json_array_close(ctx, head, &indent_level);
2325 }
2326
2327 if (GRN_TEXT_LEN(body)) {
2328 json_element_end(ctx, head, indent_level);
2329 }
2330
2331 json_array_close(ctx, foot, &indent_level);
2332}
2333
2334static void
2335grn_output_envelope_json(grn_ctx *ctx,
2336 grn_rc rc,
2337 grn_obj *head,
2338 grn_obj *body,
2339 grn_obj *foot,
2340 double started,
2341 double elapsed,
2342 const char *file,
2343 int line)
2344{
2345 size_t indent_level = 0;
2346
2347 json_map_open(ctx, head, &indent_level);
2348 {
2349 json_key(ctx, head, "header");
2350 json_map_open(ctx, head, &indent_level);
2351 {
2352 json_key(ctx, head, "return_code");
2353 grn_text_itoa(ctx, head, rc);
2354
2355 json_value_end(ctx, head, indent_level);
2356 json_key(ctx, head, "start_time");
2357 grn_text_ftoa(ctx, head, started);
2358
2359 json_value_end(ctx, head, indent_level);
2360 json_key(ctx, head, "elapsed_time");
2361 grn_text_ftoa(ctx, head, elapsed);
2362
2363 if (rc != GRN_SUCCESS) {
2364 json_value_end(ctx, head, indent_level);
2365 json_key(ctx, head, "error");
2366 json_map_open(ctx, head, &indent_level);
2367 {
2368 json_key(ctx, head, "message");
2369 grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
2370
2371 if (ctx->errfunc && ctx->errfile) {
2372 json_value_end(ctx, head, indent_level);
2373 json_key(ctx, head, "function");
2374 grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
2375
2376 json_value_end(ctx, head, indent_level);
2377 json_key(ctx, head, "file");
2378 grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
2379
2380 json_value_end(ctx, head, indent_level);
2381 json_key(ctx, head, "line");
2382 grn_text_itoa(ctx, head, ctx->errline);
2383 }
2384
2385 if (file) {
2386 grn_obj *command;
2387
2388 command = GRN_CTX_USER_DATA(ctx)->ptr;
2389 if (command) {
2390 json_value_end(ctx, head, indent_level);
2391 json_key(ctx, head, "input");
2392 json_map_open(ctx, head, &indent_level);
2393 {
2394 json_key(ctx, head, "file");
2395 grn_text_esc(ctx, head, file, strlen(file));
2396
2397 json_value_end(ctx, head, indent_level);
2398 json_key(ctx, head, "line");
2399 grn_text_itoa(ctx, head, line);
2400
2401 json_value_end(ctx, head, indent_level);
2402 json_key(ctx, head, "command");
2403 grn_text_esc(ctx, head,
2404 GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
2405 }
2406 json_map_close(ctx, head, &indent_level);
2407 }
2408 }
2409 }
2410 json_map_close(ctx, head, &indent_level);
2411 }
2412 }
2413 json_map_close(ctx, head, &indent_level);
2414
2415 if (GRN_TEXT_LEN(body)) {
2416 json_value_end(ctx, head, indent_level);
2417 json_key(ctx, head, "body");
2418 }
2419
2420 json_map_close(ctx, foot, &indent_level);
2421 }
2422}
2423
2424#ifdef GRN_WITH_MESSAGE_PACK
2425static void
2426msgpack_pack_cstr(msgpack_packer *packer,
2427 const char *string)
2428{
2429 size_t size;
2430
2431 size = strlen(string);
2432 msgpack_pack_str(packer, size);
2433 msgpack_pack_str_body(packer, string, size);
2434}
2435
2436static void
2437grn_output_envelope_msgpack_v1(grn_ctx *ctx,
2438 grn_rc rc,
2439 grn_obj *head,
2440 grn_obj *body,
2441 grn_obj *foot,
2442 double started,
2443 double elapsed,
2444 const char *file,
2445 int line)
2446{
2447 msgpack_writer_ctx head_writer_ctx;
2448 msgpack_packer header_packer;
2449 int header_size;
2450
2451 head_writer_ctx.ctx = ctx;
2452 head_writer_ctx.buffer = head;
2453 msgpack_packer_init(&header_packer, &head_writer_ctx, msgpack_buffer_writer);
2454
2455 /* [HEADER, (BODY)] */
2456 if (GRN_TEXT_LEN(body) > 0) {
2457 msgpack_pack_array(&header_packer, 2);
2458 } else {
2459 msgpack_pack_array(&header_packer, 1);
2460 }
2461
2462 /* HEADER := [rc, started, elapsed, (error, (ERROR DETAIL))] */
2463 header_size = 3;
2464 if (rc != GRN_SUCCESS) {
2465 header_size++;
2466 if (ctx->errfunc && ctx->errfile) {
2467 header_size++;
2468 }
2469 }
2470 msgpack_pack_array(&header_packer, header_size);
2471 msgpack_pack_int(&header_packer, rc);
2472
2473 msgpack_pack_double(&header_packer, started);
2474 msgpack_pack_double(&header_packer, elapsed);
2475
2476 if (rc != GRN_SUCCESS) {
2477 msgpack_pack_str(&header_packer, strlen(ctx->errbuf));
2478 msgpack_pack_str_body(&header_packer, ctx->errbuf, strlen(ctx->errbuf));
2479 if (ctx->errfunc && ctx->errfile) {
2480 grn_obj *command = GRN_CTX_USER_DATA(ctx)->ptr;
2481 int error_detail_size;
2482
2483 /* ERROR DETAIL : = [[errfunc, errfile, errline,
2484 (file, line, command)]] */
2485 /* TODO: output backtrace */
2486 msgpack_pack_array(&header_packer, 1);
2487 error_detail_size = 3;
2488 if (command) {
2489 error_detail_size += 3;
2490 }
2491 msgpack_pack_array(&header_packer, error_detail_size);
2492
2493 msgpack_pack_str(&header_packer, strlen(ctx->errfunc));
2494 msgpack_pack_str_body(&header_packer, ctx->errfunc, strlen(ctx->errfunc));
2495
2496 msgpack_pack_str(&header_packer, strlen(ctx->errfile));
2497 msgpack_pack_str_body(&header_packer, ctx->errfile, strlen(ctx->errfile));
2498
2499 msgpack_pack_int(&header_packer, ctx->errline);
2500
2501 if (command) {
2502 if (file) {
2503 msgpack_pack_str(&header_packer, strlen(file));
2504 msgpack_pack_str_body(&header_packer, file, strlen(file));
2505 } else {
2506 msgpack_pack_str(&header_packer, 7);
2507 msgpack_pack_str_body(&header_packer, "(stdin)", 7);
2508 }
2509
2510 msgpack_pack_int(&header_packer, line);
2511
2512 msgpack_pack_str(&header_packer, GRN_TEXT_LEN(command));
2513 msgpack_pack_str_body(&header_packer, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
2514 }
2515 }
2516 }
2517}
2518
2519static void
2520grn_output_envelope_msgpack(grn_ctx *ctx,
2521 grn_rc rc,
2522 grn_obj *head,
2523 grn_obj *body,
2524 grn_obj *foot,
2525 double started,
2526 double elapsed,
2527 const char *file,
2528 int line)
2529{
2530 msgpack_writer_ctx writer_ctx;
2531 msgpack_packer packer;
2532 int n_elements;
2533
2534 writer_ctx.ctx = ctx;
2535 writer_ctx.buffer = head;
2536 msgpack_packer_init(&packer, &writer_ctx, msgpack_buffer_writer);
2537
2538 /*
2539 * ENVELOPE := {
2540 * "header": HEADER,
2541 * "body": BODY (optional)
2542 * }
2543 */
2544 if (GRN_TEXT_LEN(body) > 0) {
2545 n_elements = 2;
2546 } else {
2547 n_elements = 1;
2548 }
2549
2550 msgpack_pack_map(&packer, n_elements);
2551 {
2552 int n_header_elements = 3;
2553
2554 /*
2555 * HEADER := {
2556 * "return_code": rc,
2557 * "start_time": started,
2558 * "elapsed_time": elapsed,
2559 " "error": { (optional)
2560 * "message": errbuf,
2561 * "function": errfunc,
2562 * "file": errfile,
2563 * "line": errline,
2564 * "input": { (optional)
2565 * "file": input_file,
2566 * "line": line,
2567 * "command": command
2568 * }
2569 * }
2570 * }
2571 */
2572
2573 if (rc != GRN_SUCCESS) {
2574 n_header_elements++;
2575 }
2576
2577 msgpack_pack_cstr(&packer, "header");
2578 msgpack_pack_map(&packer, n_header_elements);
2579 {
2580 msgpack_pack_cstr(&packer, "return_code");
2581 msgpack_pack_int(&packer, rc);
2582
2583 msgpack_pack_cstr(&packer, "start_time");
2584 msgpack_pack_double(&packer, started);
2585
2586 msgpack_pack_cstr(&packer, "elapsed_time");
2587 msgpack_pack_double(&packer, elapsed);
2588
2589 if (rc != GRN_SUCCESS) {
2590 int n_error_elements = 1;
2591 grn_obj *command;
2592
2593 if (ctx->errfunc) {
2594 n_error_elements++;
2595 }
2596 if (ctx->errfile) {
2597 n_error_elements += 2;
2598 }
2599
2600 command = GRN_CTX_USER_DATA(ctx)->ptr;
2601 if (file || command) {
2602 n_error_elements++;
2603 }
2604
2605 msgpack_pack_cstr(&packer, "error");
2606 msgpack_pack_map(&packer, n_error_elements);
2607 {
2608 msgpack_pack_cstr(&packer, "message");
2609 msgpack_pack_cstr(&packer, ctx->errbuf);
2610
2611 if (ctx->errfunc) {
2612 msgpack_pack_cstr(&packer, "function");
2613 msgpack_pack_cstr(&packer, ctx->errfunc);
2614 }
2615
2616 if (ctx->errfile) {
2617 msgpack_pack_cstr(&packer, "file");
2618 msgpack_pack_cstr(&packer, ctx->errfile);
2619
2620 msgpack_pack_cstr(&packer, "line");
2621 msgpack_pack_int(&packer, ctx->errline);
2622 }
2623
2624 if (file || command) {
2625 int n_input_elements = 0;
2626
2627 if (file) {
2628 n_input_elements += 2;
2629 }
2630 if (command) {
2631 n_input_elements++;
2632 }
2633
2634 msgpack_pack_cstr(&packer, "input");
2635 msgpack_pack_map(&packer, n_input_elements);
2636
2637 if (file) {
2638 msgpack_pack_cstr(&packer, "file");
2639 msgpack_pack_cstr(&packer, file);
2640
2641 msgpack_pack_cstr(&packer, "line");
2642 msgpack_pack_int(&packer, line);
2643 }
2644
2645 if (command) {
2646 msgpack_pack_cstr(&packer, "command");
2647 msgpack_pack_str(&packer, GRN_TEXT_LEN(command));
2648 msgpack_pack_str_body(&packer,
2649 GRN_TEXT_VALUE(command),
2650 GRN_TEXT_LEN(command));
2651 }
2652 }
2653 }
2654 }
2655 }
2656
2657 if (GRN_TEXT_LEN(body) > 0) {
2658 msgpack_pack_cstr(&packer, "body");
2659 }
2660 }
2661}
2662#endif /* GRN_WITH_MESSAGE_PACK */
2663
2664void
2665grn_output_envelope(grn_ctx *ctx,
2666 grn_rc rc,
2667 grn_obj *head,
2668 grn_obj *body,
2669 grn_obj *foot,
2670 const char *file,
2671 int line)
2672{
2673 double started, finished, elapsed;
2674
2675 grn_timeval tv_now;
2676 grn_timeval_now(ctx, &tv_now);
2677 started = ctx->impl->tv.tv_sec;
2678 started += ctx->impl->tv.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
2679 finished = tv_now.tv_sec;
2680 finished += tv_now.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
2681 elapsed = finished - started;
2682
2683 switch (ctx->impl->output.type) {
2684 case GRN_CONTENT_JSON:
2685 {
2686 grn_obj *expr;
2687 grn_obj *jsonp_func = NULL;
2688
2689 expr = ctx->impl->curr_expr;
2690 if (expr) {
2691 jsonp_func = grn_expr_get_var(ctx, expr, JSON_CALLBACK_PARAM,
2692 strlen(JSON_CALLBACK_PARAM));
2693 }
2694 if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
2695 GRN_TEXT_PUT(ctx, head,
2696 GRN_TEXT_VALUE(jsonp_func), GRN_TEXT_LEN(jsonp_func));
2697 GRN_TEXT_PUTC(ctx, head, '(');
2698 }
2699
2700 if (grn_ctx_get_command_version(ctx) <= GRN_COMMAND_VERSION_2) {
2701 grn_output_envelope_json_v1(ctx, rc,
2702 head, body, foot,
2703 started, elapsed,
2704 file, line);
2705 } else {
2706 grn_output_envelope_json(ctx, rc,
2707 head, body, foot,
2708 started, elapsed,
2709 file, line);
2710 }
2711
2712 if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
2713 GRN_TEXT_PUTS(ctx, foot, ");");
2714 }
2715 }
2716 break;
2717 case GRN_CONTENT_TSV:
2718 grn_text_itoa(ctx, head, rc);
2719 GRN_TEXT_PUTC(ctx, head, '\t');
2720 grn_text_ftoa(ctx, head, started);
2721 GRN_TEXT_PUTC(ctx, head, '\t');
2722 grn_text_ftoa(ctx, head, elapsed);
2723 if (rc != GRN_SUCCESS) {
2724 GRN_TEXT_PUTC(ctx, head, '\t');
2725 grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
2726 if (ctx->errfunc && ctx->errfile) {
2727 /* TODO: output backtrace */
2728 GRN_TEXT_PUTC(ctx, head, '\t');
2729 grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
2730 GRN_TEXT_PUTC(ctx, head, '\t');
2731 grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
2732 GRN_TEXT_PUTC(ctx, head, '\t');
2733 grn_text_itoa(ctx, head, ctx->errline);
2734 }
2735 }
2736 GRN_TEXT_PUTS(ctx, head, "\n");
2737 GRN_TEXT_PUTS(ctx, foot, "\nEND");
2738 break;
2739 case GRN_CONTENT_XML:
2740 {
2741 char buf[GRN_TABLE_MAX_KEY_SIZE];
2742 int is_select = 0;
2743 if (!rc && ctx->impl->curr_expr) {
2744 int len = grn_obj_name(ctx, ctx->impl->curr_expr,
2745 buf, GRN_TABLE_MAX_KEY_SIZE);
2746 buf[len] = '\0';
2747 is_select = strcmp(buf, "select") == 0;
2748 }
2749 if (is_select) {
2750 grn_obj transformed;
2751 GRN_TEXT_INIT(&transformed, 0);
2752 transform_xml(ctx, body, &transformed);
2753 GRN_TEXT_SET(ctx, body,
2754 GRN_TEXT_VALUE(&transformed), GRN_TEXT_LEN(&transformed));
2755 GRN_OBJ_FIN(ctx, &transformed);
2756 } else {
2757 GRN_TEXT_PUTS(ctx, head, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RESULT CODE=\"");
2758 grn_text_itoa(ctx, head, rc);
2759 GRN_TEXT_PUTS(ctx, head, "\" UP=\"");
2760 grn_text_ftoa(ctx, head, started);
2761 GRN_TEXT_PUTS(ctx, head, "\" ELAPSED=\"");
2762 grn_text_ftoa(ctx, head, elapsed);
2763 GRN_TEXT_PUTS(ctx, head, "\">\n");
2764 if (rc != GRN_SUCCESS) {
2765 GRN_TEXT_PUTS(ctx, head, "<ERROR>");
2766 grn_text_escape_xml(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
2767 if (ctx->errfunc && ctx->errfile) {
2768 /* TODO: output backtrace */
2769 GRN_TEXT_PUTS(ctx, head, "<INFO FUNC=\"");
2770 grn_text_escape_xml(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
2771 GRN_TEXT_PUTS(ctx, head, "\" FILE=\"");
2772 grn_text_escape_xml(ctx, head, ctx->errfile, strlen(ctx->errfile));
2773 GRN_TEXT_PUTS(ctx, head, "\" LINE=\"");
2774 grn_text_itoa(ctx, head, ctx->errline);
2775 GRN_TEXT_PUTS(ctx, head, "\"/>");
2776 }
2777 GRN_TEXT_PUTS(ctx, head, "</ERROR>");
2778 }
2779 GRN_TEXT_PUTS(ctx, foot, "\n</RESULT>");
2780 }
2781 }
2782 break;
2783 case GRN_CONTENT_MSGPACK:
2784#ifdef GRN_WITH_MESSAGE_PACK
2785 if (grn_ctx_get_command_version(ctx) <= GRN_COMMAND_VERSION_2) {
2786 grn_output_envelope_msgpack_v1(ctx, rc,
2787 head, body, foot,
2788 started, elapsed,
2789 file, line);
2790 } else {
2791 grn_output_envelope_msgpack(ctx, rc,
2792 head, body, foot,
2793 started, elapsed,
2794 file, line);
2795 }
2796#endif /* GRN_WITH_MESSAGE_PACK */
2797 break;
2798 case GRN_CONTENT_GROONGA_COMMAND_LIST :
2799 break;
2800 case GRN_CONTENT_NONE:
2801 break;
2802 }
2803}
2804
2805static inline grn_bool
2806is_output_columns_format_v1(grn_ctx *ctx,
2807 const char *output_columns,
2808 unsigned int output_columns_len)
2809{
2810 const char *current;
2811 const char *end;
2812 grn_bool in_identifier = GRN_FALSE;
2813
2814 current = output_columns;
2815 end = current + output_columns_len;
2816 while (current < end) {
2817 int char_length;
2818
2819 char_length = grn_charlen(ctx, current, end);
2820 if (char_length != 1) {
2821 return GRN_FALSE;
2822 }
2823
2824 switch (current[0]) {
2825 case ' ' :
2826 case ',' :
2827 in_identifier = GRN_FALSE;
2828 break;
2829 case '_' :
2830 in_identifier = GRN_TRUE;
2831 break;
2832 case '.' :
2833 case '-' :
2834 case '#' :
2835 case '@' :
2836 if (!in_identifier) {
2837 return GRN_FALSE;
2838 }
2839 break;
2840 default :
2841 if ('a' <= current[0] && current[0] <= 'z') {
2842 in_identifier = GRN_TRUE;
2843 break;
2844 } else if ('A' <= current[0] && current[0] <= 'Z') {
2845 in_identifier = GRN_TRUE;
2846 break;
2847 } else if ('0' <= current[0] && current[0] <= '9') {
2848 in_identifier = GRN_TRUE;
2849 break;
2850 } else {
2851 return GRN_FALSE;
2852 }
2853 }
2854
2855 current += char_length;
2856 }
2857
2858 return GRN_TRUE;
2859}
2860
2861grn_rc
2862grn_output_format_set_columns(grn_ctx *ctx, grn_obj_format *format,
2863 grn_obj *table,
2864 const char *columns, int columns_len)
2865{
2866 grn_rc rc;
2867
2868 if (is_output_columns_format_v1(ctx, columns, columns_len)) {
2869 rc = grn_obj_columns(ctx, table, columns, columns_len, &(format->columns));
2870 } else {
2871 grn_obj *variable;
2872 GRN_EXPR_CREATE_FOR_QUERY(ctx, table, format->expression, variable);
2873 rc = grn_expr_parse(ctx, format->expression,
2874 columns, columns_len, NULL,
2875 GRN_OP_MATCH, GRN_OP_AND,
2876 GRN_EXPR_SYNTAX_OUTPUT_COLUMNS);
2877 }
2878
2879 return rc;
2880}
2881