1 /* -*- c-basic-offset: 2 -*- */
2 /*
3   Copyright(C) 2009-2017 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-1335  USA
17 */
18 
19 #include "grn.h"
20 #include <string.h>
21 #include "grn_request_canceler.h"
22 #include "grn_request_timer.h"
23 #include "grn_tokenizers.h"
24 #include "grn_ctx_impl.h"
25 #include "grn_ii.h"
26 #include "grn_pat.h"
27 #include "grn_index_column.h"
28 #include "grn_proc.h"
29 #include "grn_plugin.h"
30 #include "grn_snip.h"
31 #include "grn_output.h"
32 #include "grn_normalizer.h"
33 #include "grn_mrb.h"
34 #include "grn_ctx_impl_mrb.h"
35 #include "grn_logger.h"
36 #include "grn_cache.h"
37 #include "grn_expr.h"
38 #include <stdio.h>
39 #include <stdarg.h>
40 #include <time.h>
41 
42 #ifdef GRN_WITH_ONIGMO
43 # define GRN_SUPPORT_REGEXP
44 #endif /* GRN_WITH_ONIGMO */
45 
46 #ifdef GRN_SUPPORT_REGEXP
47 # include <onigmo.h>
48 #endif /* GRN_SUPPORT_REGEXP */
49 
50 #ifdef WIN32
51 # include <share.h>
52 #else /* WIN32 */
53 # include <netinet/in.h>
54 #endif /* WIN32 */
55 
56 #define GRN_CTX_INITIALIZER(enc) \
57   { GRN_SUCCESS, 0, enc, 0, GRN_LOG_NOTICE,\
58     GRN_CTX_FIN, 0, 0, 0, 0, {0}, NULL, NULL, NULL, NULL, NULL, \
59     {NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL}, ""}
60 
61 #define GRN_CTX_CLOSED(ctx) ((ctx)->stat == GRN_CTX_FIN)
62 
63 grn_ctx grn_gctx = GRN_CTX_INITIALIZER(GRN_ENC_DEFAULT);
64 int grn_pagesize;
65 grn_critical_section grn_glock;
66 uint32_t grn_gtick;
67 int grn_lock_timeout = GRN_LOCK_TIMEOUT;
68 
69 #ifdef USE_UYIELD
70 int grn_uyield_count = 0;
71 #endif
72 
73 static grn_bool grn_ctx_per_db = GRN_FALSE;
74 
75 static void
grn_init_from_env(void)76 grn_init_from_env(void)
77 {
78   {
79     char grn_ctx_per_db_env[GRN_ENV_BUFFER_SIZE];
80     grn_getenv("GRN_CTX_PER_DB",
81                grn_ctx_per_db_env,
82                GRN_ENV_BUFFER_SIZE);
83     if (grn_ctx_per_db_env[0] && strcmp(grn_ctx_per_db_env, "yes") == 0) {
84       grn_ctx_per_db = GRN_TRUE;
85     }
86   }
87 
88   grn_alloc_init_from_env();
89   grn_mrb_init_from_env();
90   grn_ctx_impl_mrb_init_from_env();
91   grn_io_init_from_env();
92   grn_ii_init_from_env();
93   grn_db_init_from_env();
94   grn_expr_init_from_env();
95   grn_index_column_init_from_env();
96   grn_proc_init_from_env();
97   grn_plugin_init_from_env();
98 }
99 
100 static void
grn_init_external_libraries(void)101 grn_init_external_libraries(void)
102 {
103 #ifdef GRN_SUPPORT_REGEXP
104   onig_init();
105 #endif /*  GRN_SUPPORT_REGEXP */
106 }
107 
108 static void
grn_fin_external_libraries(void)109 grn_fin_external_libraries(void)
110 {
111 #ifdef GRN_SUPPORT_REGEXP
112   onig_end();
113 #endif /*  GRN_SUPPORT_REGEXP */
114 }
115 
116 void
grn_sleep(uint32_t seconds)117 grn_sleep(uint32_t seconds)
118 {
119 #ifdef WIN32
120   Sleep(seconds * 1000);
121 #else  // WIN32
122   sleep(seconds);
123 #endif  // WIN32
124 }
125 
126 void
grn_nanosleep(uint64_t nanoseconds)127 grn_nanosleep(uint64_t nanoseconds)
128 {
129 #ifdef WIN32
130   Sleep((DWORD)(nanoseconds / 1000000));
131 #else  // WIN32
132   struct timespec interval;
133   interval.tv_sec = (time_t)(nanoseconds / 1000000000);
134   interval.tv_nsec = (long)(nanoseconds % 1000000000);
135   nanosleep(&interval, NULL);
136 #endif  // WIN32
137 }
138 
139 const char *
grn_get_global_error_message(void)140 grn_get_global_error_message(void)
141 {
142   return grn_gctx.errbuf;
143 }
144 
145 static void
grn_loader_init(grn_loader * loader)146 grn_loader_init(grn_loader *loader)
147 {
148   GRN_TEXT_INIT(&loader->values, 0);
149   GRN_UINT32_INIT(&loader->level, GRN_OBJ_VECTOR);
150   GRN_PTR_INIT(&loader->columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
151   GRN_UINT32_INIT(&loader->ids, GRN_OBJ_VECTOR);
152   GRN_INT32_INIT(&loader->return_codes, GRN_OBJ_VECTOR);
153   GRN_TEXT_INIT(&loader->error_messages, GRN_OBJ_VECTOR);
154   loader->id_offset = -1;
155   loader->key_offset = -1;
156   loader->table = NULL;
157   loader->last = NULL;
158   loader->ifexists = NULL;
159   loader->each = NULL;
160   loader->values_size = 0;
161   loader->nrecords = 0;
162   loader->stat = GRN_LOADER_BEGIN;
163   loader->columns_status = GRN_LOADER_COLUMNS_UNSET;
164   loader->rc = GRN_SUCCESS;
165   loader->errbuf[0] = '\0';
166   loader->output_ids = GRN_FALSE;
167   loader->output_errors = GRN_FALSE;
168 }
169 
170 void
grn_ctx_loader_clear(grn_ctx * ctx)171 grn_ctx_loader_clear(grn_ctx *ctx)
172 {
173   grn_loader *loader = &ctx->impl->loader;
174   grn_obj *v = (grn_obj *)(GRN_BULK_HEAD(&loader->values));
175   grn_obj *ve = (grn_obj *)(GRN_BULK_CURR(&loader->values));
176   grn_obj **p = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
177   uint32_t i = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
178   if (ctx->impl->db) { while (i--) { grn_obj_unlink(ctx, *p++); } }
179   if (loader->ifexists) { grn_obj_unlink(ctx, loader->ifexists); }
180   if (loader->each) { grn_obj_unlink(ctx, loader->each); }
181   while (v < ve) { GRN_OBJ_FIN(ctx, v++); }
182   GRN_OBJ_FIN(ctx, &loader->values);
183   GRN_OBJ_FIN(ctx, &loader->level);
184   GRN_OBJ_FIN(ctx, &loader->columns);
185   GRN_OBJ_FIN(ctx, &loader->ids);
186   GRN_OBJ_FIN(ctx, &loader->return_codes);
187   GRN_OBJ_FIN(ctx, &loader->error_messages);
188   grn_loader_init(loader);
189 }
190 
191 #define IMPL_SIZE ((sizeof(struct _grn_ctx_impl) + (grn_pagesize - 1)) & ~(grn_pagesize - 1))
192 
193 #ifdef GRN_WITH_MESSAGE_PACK
194 static int
grn_msgpack_buffer_write(void * data,const char * buf,msgpack_size_t len)195 grn_msgpack_buffer_write(void *data, const char *buf, msgpack_size_t len)
196 {
197   grn_ctx *ctx = (grn_ctx *)data;
198   return grn_bulk_write(ctx, ctx->impl->output.buf, buf, len);
199 }
200 #endif
201 
202 static grn_rc
grn_ctx_impl_init(grn_ctx * ctx)203 grn_ctx_impl_init(grn_ctx *ctx)
204 {
205   grn_io_mapinfo mi;
206   if (!(ctx->impl = grn_io_anon_map(ctx, &mi, IMPL_SIZE))) {
207     return ctx->rc;
208   }
209   grn_alloc_init_ctx_impl(ctx);
210   ctx->impl->encoding = ctx->encoding;
211   ctx->impl->lifoseg = -1;
212   ctx->impl->currseg = -1;
213   CRITICAL_SECTION_INIT(ctx->impl->lock);
214   if (!(ctx->impl->values = grn_array_create(ctx, NULL, sizeof(grn_db_obj *),
215                                              GRN_ARRAY_TINY))) {
216     CRITICAL_SECTION_FIN(ctx->impl->lock);
217     grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
218     ctx->impl = NULL;
219     return ctx->rc;
220   }
221   if (!(ctx->impl->temporary_columns = grn_pat_create(ctx, NULL,
222                                                       GRN_TABLE_MAX_KEY_SIZE,
223                                                       sizeof(grn_obj *),
224                                                       0))) {
225     grn_array_close(ctx, ctx->impl->values);
226     CRITICAL_SECTION_FIN(ctx->impl->lock);
227     grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
228     ctx->impl = NULL;
229     return ctx->rc;
230   }
231   if (!(ctx->impl->ios = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE,
232                                          sizeof(grn_io *),
233                                          GRN_OBJ_KEY_VAR_SIZE|GRN_HASH_TINY))) {
234     grn_array_close(ctx, ctx->impl->values);
235     grn_pat_close(ctx, ctx->impl->temporary_columns);
236     CRITICAL_SECTION_FIN(ctx->impl->lock);
237     grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
238     ctx->impl = NULL;
239     return ctx->rc;
240   }
241   ctx->impl->db = NULL;
242 
243   ctx->impl->expr_vars = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_obj *), 0);
244   ctx->impl->stack_curr = 0;
245   ctx->impl->curr_expr = NULL;
246   GRN_TEXT_INIT(&ctx->impl->current_request_id, 0);
247   ctx->impl->current_request_timer_id = NULL;
248   ctx->impl->parser = NULL;
249 
250   GRN_TEXT_INIT(&ctx->impl->output.names, GRN_OBJ_VECTOR);
251   GRN_UINT32_INIT(&ctx->impl->output.levels, GRN_OBJ_VECTOR);
252 
253   ctx->impl->command.flags = 0;
254   if (ctx == &grn_gctx) {
255     ctx->impl->command.version = GRN_COMMAND_VERSION_STABLE;
256   } else {
257     ctx->impl->command.version = grn_get_default_command_version();
258   }
259   ctx->impl->command.keep.command = NULL;
260   ctx->impl->command.keep.version = ctx->impl->command.version;
261 
262   if (ctx == &grn_gctx) {
263     ctx->impl->match_escalation_threshold =
264       GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD;
265   } else {
266     ctx->impl->match_escalation_threshold =
267       grn_get_default_match_escalation_threshold();
268   }
269 
270   ctx->impl->finalizer = NULL;
271 
272   ctx->impl->com = NULL;
273   ctx->impl->output.buf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT);
274   ctx->impl->output.func = NULL;
275   ctx->impl->output.data.ptr = NULL;
276 #ifdef GRN_WITH_MESSAGE_PACK
277   msgpack_packer_init(&ctx->impl->output.msgpacker,
278                       ctx, grn_msgpack_buffer_write);
279 #endif
280   ctx->impl->tv.tv_sec = 0;
281   ctx->impl->tv.tv_nsec = 0;
282   ctx->impl->edge = NULL;
283   grn_loader_init(&ctx->impl->loader);
284   ctx->impl->plugin_path = NULL;
285 
286   GRN_TEXT_INIT(&ctx->impl->query_log_buf, 0);
287 
288   ctx->impl->previous_errbuf[0] = '\0';
289   ctx->impl->n_same_error_messages = 0;
290 
291   grn_ctx_impl_mrb_init(ctx);
292 
293   GRN_TEXT_INIT(&(ctx->impl->temporary_open_spaces.stack), 0);
294   ctx->impl->temporary_open_spaces.current = NULL;
295 
296   return ctx->rc;
297 }
298 
299 void
grn_ctx_set_keep_command(grn_ctx * ctx,grn_obj * command)300 grn_ctx_set_keep_command(grn_ctx *ctx, grn_obj *command)
301 {
302   ctx->impl->command.keep.command = command;
303   ctx->impl->command.keep.version = ctx->impl->command.version;
304 }
305 
306 static void
grn_ctx_impl_clear_n_same_error_messagges(grn_ctx * ctx)307 grn_ctx_impl_clear_n_same_error_messagges(grn_ctx *ctx)
308 {
309   if (ctx->impl->n_same_error_messages == 0) {
310     return;
311   }
312 
313   GRN_LOG(ctx, GRN_LOG_NOTICE, "(%u same messages are truncated)",
314           ctx->impl->n_same_error_messages);
315   ctx->impl->n_same_error_messages = 0;
316 }
317 
318 grn_bool
grn_ctx_impl_should_log(grn_ctx * ctx)319 grn_ctx_impl_should_log(grn_ctx *ctx)
320 {
321   if (!ctx->impl) {
322     return GRN_TRUE;
323   }
324 
325   if (strcmp(ctx->errbuf, ctx->impl->previous_errbuf) == 0) {
326     ctx->impl->n_same_error_messages++;
327     return GRN_FALSE;
328   }
329 
330   return GRN_TRUE;
331 }
332 
333 void
grn_ctx_impl_set_current_error_message(grn_ctx * ctx)334 grn_ctx_impl_set_current_error_message(grn_ctx *ctx)
335 {
336   if (!ctx->impl) {
337     return;
338   }
339 
340   grn_ctx_impl_clear_n_same_error_messagges(ctx);
341   grn_strcpy(ctx->impl->previous_errbuf, GRN_CTX_MSGSIZE, ctx->errbuf);
342 }
343 
344 static grn_rc
grn_ctx_init_internal(grn_ctx * ctx,int flags)345 grn_ctx_init_internal(grn_ctx *ctx, int flags)
346 {
347   if (!ctx) { return GRN_INVALID_ARGUMENT; }
348   // if (ctx->stat != GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
349   ctx->rc = GRN_SUCCESS;
350   ERRCLR(ctx);
351   ctx->flags = flags;
352   if (grn_ctx_per_db) {
353     ctx->flags |= GRN_CTX_PER_DB;
354   }
355   ctx->stat = GRN_CTX_INITED;
356   ctx->encoding = grn_gctx.encoding;
357   ctx->seqno = 0;
358   ctx->seqno2 = 0;
359   ctx->subno = 0;
360   ctx->impl = NULL;
361   ctx->user_data.ptr = NULL;
362   CRITICAL_SECTION_ENTER(grn_glock);
363   ctx->next = grn_gctx.next;
364   ctx->prev = &grn_gctx;
365   grn_gctx.next->prev = ctx;
366   grn_gctx.next = ctx;
367   CRITICAL_SECTION_LEAVE(grn_glock);
368   ctx->errline = 0;
369   ctx->errfile = "";
370   ctx->errfunc = "";
371   ctx->trace[0] = NULL;
372   ctx->errbuf[0] = '\0';
373   return GRN_SUCCESS;
374 }
375 
376 grn_rc
grn_ctx_init(grn_ctx * ctx,int flags)377 grn_ctx_init(grn_ctx *ctx, int flags)
378 {
379   grn_rc rc;
380 
381   rc = grn_ctx_init_internal(ctx, flags);
382   if (rc == GRN_SUCCESS) {
383     grn_ctx_impl_init(ctx);
384     rc = ctx->rc;
385     if (rc != GRN_SUCCESS) {
386       grn_ctx_fin(ctx);
387       if (flags & GRN_CTX_ALLOCATED) {
388         CRITICAL_SECTION_ENTER(grn_glock);
389         ctx->next->prev = ctx->prev;
390         ctx->prev->next = ctx->next;
391         CRITICAL_SECTION_LEAVE(grn_glock);
392       }
393     }
394   }
395 
396   return rc;
397 }
398 
399 grn_ctx *
grn_ctx_open(int flags)400 grn_ctx_open(int flags)
401 {
402   grn_ctx *ctx = GRN_GMALLOCN(grn_ctx, 1);
403   if (ctx) {
404     grn_ctx_init(ctx, flags|GRN_CTX_ALLOCATED);
405     if (ERRP(ctx, GRN_ERROR)) {
406       GRN_GFREE(ctx);
407       ctx = NULL;
408     }
409   }
410   return ctx;
411 }
412 
413 grn_rc
grn_ctx_fin(grn_ctx * ctx)414 grn_ctx_fin(grn_ctx *ctx)
415 {
416   grn_rc rc = GRN_SUCCESS;
417   if (!ctx) { return GRN_INVALID_ARGUMENT; }
418   if (ctx->stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
419   if (!(ctx->flags & GRN_CTX_ALLOCATED)) {
420     CRITICAL_SECTION_ENTER(grn_glock);
421     ctx->next->prev = ctx->prev;
422     ctx->prev->next = ctx->next;
423     CRITICAL_SECTION_LEAVE(grn_glock);
424   }
425   if (ctx->impl) {
426     grn_ctx_impl_clear_n_same_error_messagges(ctx);
427     if (ctx->impl->finalizer) {
428       ctx->impl->finalizer(ctx, 0, NULL, &(ctx->user_data));
429     }
430     {
431       grn_obj *stack;
432       grn_obj *spaces;
433       unsigned int i, n_spaces;
434 
435       stack = &(ctx->impl->temporary_open_spaces.stack);
436       spaces = (grn_obj *)GRN_BULK_HEAD(stack);
437       n_spaces = GRN_BULK_VSIZE(stack) / sizeof(grn_obj);
438       for (i = 0; i < n_spaces; i++) {
439         grn_obj *space = spaces + (n_spaces - i - 1);
440         GRN_OBJ_FIN(ctx, space);
441       }
442       GRN_OBJ_FIN(ctx, stack);
443     }
444     grn_ctx_impl_mrb_fin(ctx);
445     grn_ctx_loader_clear(ctx);
446     if (ctx->impl->parser) {
447       grn_expr_parser_close(ctx);
448     }
449     GRN_OBJ_FIN(ctx, &ctx->impl->current_request_id);
450     if (ctx->impl->values) {
451 #ifndef USE_MEMORY_DEBUG
452       grn_db_obj *o;
453       GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
454         grn_obj_close(ctx, *((grn_obj **)o));
455       });
456 #endif
457       grn_array_close(ctx, ctx->impl->values);
458     }
459     if (ctx->impl->temporary_columns) {
460 #ifndef USE_MEMORY_DEBUG
461       grn_obj *value;
462       GRN_PAT_EACH(ctx, ctx->impl->temporary_columns, id, NULL, NULL, &value, {
463         grn_obj_close(ctx, *((grn_obj **)value));
464       });
465 #endif
466       grn_pat_close(ctx, ctx->impl->temporary_columns);
467     }
468     if (ctx->impl->ios) {
469       grn_hash_close(ctx, ctx->impl->ios);
470     }
471     if (ctx->impl->com) {
472       if (ctx->stat != GRN_CTX_QUIT) {
473         int flags;
474         char *str;
475         unsigned int str_len;
476         grn_ctx_send(ctx, "quit", 4, GRN_CTX_HEAD);
477         grn_ctx_recv(ctx, &str, &str_len, &flags);
478       }
479       grn_ctx_send(ctx, "ACK", 3, GRN_CTX_HEAD);
480       rc = grn_com_close(ctx, ctx->impl->com);
481     }
482     GRN_OBJ_FIN(ctx, &ctx->impl->query_log_buf);
483     GRN_OBJ_FIN(ctx, &ctx->impl->output.names);
484     GRN_OBJ_FIN(ctx, &ctx->impl->output.levels);
485     rc = grn_obj_close(ctx, ctx->impl->output.buf);
486     {
487       grn_hash **vp;
488       grn_obj *value;
489       GRN_HASH_EACH(ctx, ctx->impl->expr_vars, eid, NULL, NULL, &vp, {
490         if (*vp) {
491           GRN_HASH_EACH(ctx, *vp, id, NULL, NULL, &value, {
492             GRN_OBJ_FIN(ctx, value);
493           });
494         }
495         grn_hash_close(ctx, *vp);
496       });
497     }
498     grn_hash_close(ctx, ctx->impl->expr_vars);
499     if (ctx->impl->db && ctx->flags & GRN_CTX_PER_DB) {
500       grn_obj *db = ctx->impl->db;
501       ctx->impl->db = NULL;
502       grn_obj_close(ctx, db);
503     }
504     grn_alloc_fin_ctx_impl(ctx);
505     grn_alloc_info_dump(ctx);
506     grn_alloc_info_free(ctx);
507     CRITICAL_SECTION_FIN(ctx->impl->lock);
508     {
509       grn_io_mapinfo mi;
510       mi.map = (void *)ctx->impl;
511       grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
512     }
513     ctx->impl = NULL;
514   }
515   ctx->stat = GRN_CTX_FIN;
516   return rc;
517 }
518 
519 grn_rc
grn_ctx_set_finalizer(grn_ctx * ctx,grn_proc_func * finalizer)520 grn_ctx_set_finalizer(grn_ctx *ctx, grn_proc_func *finalizer)
521 {
522   if (!ctx) { return GRN_INVALID_ARGUMENT; }
523   if (!ctx->impl) {
524     if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; }
525   }
526   ctx->impl->finalizer = finalizer;
527   return GRN_SUCCESS;
528 }
529 
530 grn_timeval grn_starttime;
531 
532 static void
check_overcommit_memory(grn_ctx * ctx)533 check_overcommit_memory(grn_ctx *ctx)
534 {
535   FILE *file;
536   int value;
537   file = grn_fopen("/proc/sys/vm/overcommit_memory", "r");
538   if (!file) { return; }
539   value = fgetc(file);
540   if (value != '1') {
541     GRN_LOG(ctx, GRN_LOG_NOTICE,
542             "vm.overcommit_memory kernel parameter should be 1: <%c>: "
543             "See INFO level log to resolve this",
544             value);
545     GRN_LOG(ctx, GRN_LOG_INFO,
546             "Some processings with vm.overcommit_memory != 1 "
547             "may break DB under low memory condition.");
548     GRN_LOG(ctx, GRN_LOG_INFO,
549             "To set vm.overcommit_memory to 1");
550     GRN_LOG(ctx, GRN_LOG_INFO,
551             "add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and "
552             "restart your system or");
553     GRN_LOG(ctx, GRN_LOG_INFO,
554             "run 'sudo /sbin/sysctl vm.overcommit_memory=1' command.");
555   }
556   fclose(file);
557 }
558 
559 grn_rc
grn_init(void)560 grn_init(void)
561 {
562   grn_rc rc;
563   grn_ctx *ctx = &grn_gctx;
564   grn_init_from_env();
565   grn_init_external_libraries();
566   grn_alloc_info_init();
567   grn_logger_init();
568   grn_query_logger_init();
569   CRITICAL_SECTION_INIT(grn_glock);
570   grn_gtick = 0;
571   ctx->next = ctx;
572   ctx->prev = ctx;
573   rc = grn_ctx_init_internal(ctx, 0);
574   if (rc) {
575     goto fail_ctx_init_internal;
576   }
577   ctx->encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING);
578   rc = grn_timeval_now(ctx, &grn_starttime);
579   if (rc) {
580     goto fail_start_time;
581   }
582 #ifdef WIN32
583   {
584     SYSTEM_INFO si;
585     GetSystemInfo(&si);
586     grn_pagesize = si.dwAllocationGranularity;
587   }
588 #else /* WIN32 */
589   if ((grn_pagesize = sysconf(_SC_PAGESIZE)) == -1) {
590     SERR("_SC_PAGESIZE");
591     rc = ctx->rc;
592     goto fail_page_size;
593   }
594 #endif /* WIN32 */
595   if (grn_pagesize & (grn_pagesize - 1)) {
596     GRN_LOG(ctx, GRN_LOG_CRIT, "pagesize=%x", grn_pagesize);
597   }
598   // expand_stack();
599   if ((rc = grn_com_init())) {
600     GRN_LOG(ctx, GRN_LOG_ALERT, "grn_com_init failed (%d)", rc);
601     goto fail_com;
602   }
603   if ((rc = grn_ctx_impl_init(ctx))) {
604     GRN_LOG(ctx, GRN_LOG_ALERT, "grn_ctx_impl_init failed (%d)", rc);
605     goto fail_ctx_impl;
606   }
607   if ((rc = grn_plugins_init())) {
608     GRN_LOG(ctx, GRN_LOG_ALERT, "grn_plugins_init failed (%d)", rc);
609     goto fail_plugins;
610   }
611   if ((rc = grn_normalizer_init())) {
612     GRN_LOG(ctx, GRN_LOG_ALERT, "grn_normalizer_init failed (%d)", rc);
613     goto fail_normalizer;
614   }
615   if ((rc = grn_tokenizers_init())) {
616     GRN_LOG(ctx, GRN_LOG_ALERT, "grn_tokenizers_init failed (%d)", rc);
617     goto fail_tokenizer;
618   }
619   grn_cache_init();
620   if (!grn_request_canceler_init()) {
621     rc = ctx->rc;
622     GRN_LOG(ctx, GRN_LOG_ALERT,
623             "failed to initialize request canceler (%d)", rc);
624     goto fail_request_canceler;
625   }
626   if (!grn_request_timer_init()) {
627     rc = ctx->rc;
628     GRN_LOG(ctx, GRN_LOG_ALERT,
629             "failed to initialize request timer (%d)", rc);
630     goto fail_request_timer;
631   }
632   GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init: <%s>", grn_get_version());
633   check_overcommit_memory(ctx);
634   return rc;
635 
636 fail_request_timer:
637   grn_request_canceler_fin();
638 fail_request_canceler:
639   grn_cache_fin();
640 fail_tokenizer:
641   grn_normalizer_fin();
642 fail_normalizer:
643   grn_plugins_fin();
644 fail_plugins:
645   grn_ctx_fin(ctx);
646 fail_ctx_impl:
647   grn_com_fin();
648 fail_com:
649 #ifndef WIN32
650 fail_page_size:
651 #endif /* WIN32 */
652 fail_start_time:
653 fail_ctx_init_internal:
654   GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init: <%s>: failed", grn_get_version());
655   grn_query_logger_fin(ctx);
656   grn_logger_fin(ctx);
657   CRITICAL_SECTION_FIN(grn_glock);
658   grn_alloc_info_fin();
659   grn_fin_external_libraries();
660   return rc;
661 }
662 
663 grn_encoding
grn_get_default_encoding(void)664 grn_get_default_encoding(void)
665 {
666   return grn_gctx.encoding;
667 }
668 
669 grn_rc
grn_set_default_encoding(grn_encoding encoding)670 grn_set_default_encoding(grn_encoding encoding)
671 {
672   switch (encoding) {
673   case GRN_ENC_DEFAULT :
674     grn_gctx.encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING);
675     return GRN_SUCCESS;
676   case GRN_ENC_NONE :
677   case GRN_ENC_EUC_JP :
678   case GRN_ENC_UTF8 :
679   case GRN_ENC_SJIS :
680   case GRN_ENC_LATIN1 :
681   case GRN_ENC_KOI8R :
682     grn_gctx.encoding = encoding;
683     return GRN_SUCCESS;
684   default :
685     return GRN_INVALID_ARGUMENT;
686   }
687 }
688 
689 grn_command_version
grn_get_default_command_version(void)690 grn_get_default_command_version(void)
691 {
692   return grn_ctx_get_command_version(&grn_gctx);
693 }
694 
695 grn_rc
grn_set_default_command_version(grn_command_version version)696 grn_set_default_command_version(grn_command_version version)
697 {
698   return grn_ctx_set_command_version(&grn_gctx, version);
699 }
700 
701 long long int
grn_get_default_match_escalation_threshold(void)702 grn_get_default_match_escalation_threshold(void)
703 {
704   return grn_ctx_get_match_escalation_threshold(&grn_gctx);
705 }
706 
707 grn_rc
grn_set_default_match_escalation_threshold(long long int threshold)708 grn_set_default_match_escalation_threshold(long long int threshold)
709 {
710   return grn_ctx_set_match_escalation_threshold(&grn_gctx, threshold);
711 }
712 
713 int
grn_get_lock_timeout(void)714 grn_get_lock_timeout(void)
715 {
716   return grn_lock_timeout;
717 }
718 
719 grn_rc
grn_set_lock_timeout(int timeout)720 grn_set_lock_timeout(int timeout)
721 {
722   grn_lock_timeout = timeout;
723   return GRN_SUCCESS;
724 }
725 
726 grn_rc
grn_fin(void)727 grn_fin(void)
728 {
729   grn_ctx *ctx, *ctx_;
730   if (grn_gctx.stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
731   for (ctx = grn_gctx.next; ctx != &grn_gctx; ctx = ctx_) {
732     ctx_ = ctx->next;
733     if (ctx->stat != GRN_CTX_FIN) { grn_ctx_fin(ctx); }
734     if (ctx->flags & GRN_CTX_ALLOCATED) {
735       ctx->next->prev = ctx->prev;
736       ctx->prev->next = ctx->next;
737       GRN_GFREE(ctx);
738     }
739   }
740   grn_query_logger_fin(ctx);
741   grn_request_timer_fin();
742   grn_request_canceler_fin();
743   grn_cache_fin();
744   grn_tokenizers_fin();
745   grn_normalizer_fin();
746   grn_plugins_fin();
747   grn_ctx_fin(ctx);
748   grn_com_fin();
749   GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_fin (%d)", grn_alloc_count());
750   grn_logger_fin(ctx);
751   CRITICAL_SECTION_FIN(grn_glock);
752   grn_alloc_info_fin();
753   grn_fin_external_libraries();
754   return GRN_SUCCESS;
755 }
756 
757 grn_rc
grn_ctx_connect(grn_ctx * ctx,const char * host,int port,int flags)758 grn_ctx_connect(grn_ctx *ctx, const char *host, int port, int flags)
759 {
760   GRN_API_ENTER;
761   if (!ctx->impl) { goto exit; }
762   {
763     grn_com *com = grn_com_copen(ctx, NULL, host, port);
764     if (com) {
765       ctx->impl->com = com;
766     }
767   }
768 exit :
769   GRN_API_RETURN(ctx->rc);
770 }
771 
772 grn_rc
grn_ctx_close(grn_ctx * ctx)773 grn_ctx_close(grn_ctx *ctx)
774 {
775   grn_rc rc = grn_ctx_fin(ctx);
776   CRITICAL_SECTION_ENTER(grn_glock);
777   ctx->next->prev = ctx->prev;
778   ctx->prev->next = ctx->next;
779   CRITICAL_SECTION_LEAVE(grn_glock);
780   GRN_GFREE(ctx);
781   return rc;
782 }
783 
784 grn_command_version
grn_ctx_get_command_version(grn_ctx * ctx)785 grn_ctx_get_command_version(grn_ctx *ctx)
786 {
787   if (ctx->impl) {
788     return ctx->impl->command.version;
789   } else {
790     return GRN_COMMAND_VERSION_STABLE;
791   }
792 }
793 
794 grn_rc
grn_ctx_set_command_version(grn_ctx * ctx,grn_command_version version)795 grn_ctx_set_command_version(grn_ctx *ctx, grn_command_version version)
796 {
797   switch (version) {
798   case GRN_COMMAND_VERSION_DEFAULT :
799     ctx->impl->command.version = GRN_COMMAND_VERSION_STABLE;
800     return GRN_SUCCESS;
801   default :
802     if (GRN_COMMAND_VERSION_MIN <= version &&
803         version <= GRN_COMMAND_VERSION_MAX) {
804       ctx->impl->command.version = version;
805       return GRN_SUCCESS;
806     } else {
807       return GRN_UNSUPPORTED_COMMAND_VERSION;
808     }
809   }
810 }
811 
812 grn_content_type
grn_ctx_get_output_type(grn_ctx * ctx)813 grn_ctx_get_output_type(grn_ctx *ctx)
814 {
815   if (ctx->impl) {
816     return ctx->impl->output.type;
817   } else {
818     return GRN_CONTENT_NONE;
819   }
820 }
821 
822 grn_rc
grn_ctx_set_output_type(grn_ctx * ctx,grn_content_type type)823 grn_ctx_set_output_type(grn_ctx *ctx, grn_content_type type)
824 {
825   grn_rc rc = GRN_SUCCESS;
826 
827   if (ctx->impl) {
828     ctx->impl->output.type = type;
829     switch (ctx->impl->output.type) {
830     case GRN_CONTENT_NONE :
831       ctx->impl->output.mime_type = "application/octet-stream";
832       break;
833     case GRN_CONTENT_TSV :
834       ctx->impl->output.mime_type = "text/tab-separated-values";
835       break;
836     case GRN_CONTENT_JSON :
837       ctx->impl->output.mime_type = "application/json";
838       break;
839     case GRN_CONTENT_XML :
840       ctx->impl->output.mime_type = "text/xml";
841       break;
842     case GRN_CONTENT_MSGPACK :
843       ctx->impl->output.mime_type = "application/x-msgpack";
844       break;
845     case GRN_CONTENT_GROONGA_COMMAND_LIST :
846       ctx->impl->output.mime_type = "text/x-groonga-command-list";
847       break;
848     }
849   } else {
850     rc = GRN_INVALID_ARGUMENT;
851   }
852 
853   return rc;
854 }
855 
856 const char *
grn_ctx_get_mime_type(grn_ctx * ctx)857 grn_ctx_get_mime_type(grn_ctx *ctx)
858 {
859   if (ctx->impl) {
860     return ctx->impl->output.mime_type;
861   } else {
862     return NULL;
863   }
864 }
865 
866 long long int
grn_ctx_get_match_escalation_threshold(grn_ctx * ctx)867 grn_ctx_get_match_escalation_threshold(grn_ctx *ctx)
868 {
869   if (ctx->impl) {
870     return ctx->impl->match_escalation_threshold;
871   } else {
872     return GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD;
873   }
874 }
875 
876 grn_rc
grn_ctx_set_match_escalation_threshold(grn_ctx * ctx,long long int threshold)877 grn_ctx_set_match_escalation_threshold(grn_ctx *ctx, long long int threshold)
878 {
879   ctx->impl->match_escalation_threshold = threshold;
880   return GRN_SUCCESS;
881 }
882 
883 grn_content_type
grn_get_ctype(grn_obj * var)884 grn_get_ctype(grn_obj *var)
885 {
886   return grn_content_type_parse(NULL, var, GRN_CONTENT_JSON);
887 }
888 
889 grn_content_type
grn_content_type_parse(grn_ctx * ctx,grn_obj * var,grn_content_type default_value)890 grn_content_type_parse(grn_ctx *ctx,
891                        grn_obj *var,
892                        grn_content_type default_value)
893 {
894   grn_content_type ct = default_value;
895   if (var->header.domain == GRN_DB_INT32) {
896     ct = GRN_INT32_VALUE(var);
897   } else if (GRN_TEXT_LEN(var)) {
898     switch (*(GRN_TEXT_VALUE(var))) {
899     case 't' :
900     case 'T' :
901       ct = GRN_CONTENT_TSV;
902       break;
903     case 'j' :
904     case 'J' :
905       ct = GRN_CONTENT_JSON;
906       break;
907     case 'x' :
908     case 'X' :
909       ct = GRN_CONTENT_XML;
910       break;
911     }
912   }
913   return ct;
914 }
915 
916 static void
get_content_mime_type(grn_ctx * ctx,const char * p,const char * pe)917 get_content_mime_type(grn_ctx *ctx, const char *p, const char *pe)
918 {
919   ctx->impl->output.type = GRN_CONTENT_NONE;
920   ctx->impl->output.mime_type = "application/octet-stream";
921 
922   if (p + 2 <= pe) {
923     switch (*p) {
924     case 'c' :
925       if (p + 3 == pe && !memcmp(p, "css", 3)) {
926         ctx->impl->output.type = GRN_CONTENT_NONE;
927         ctx->impl->output.mime_type = "text/css";
928       }
929       break;
930     case 'g' :
931       if (p + 3 == pe && !memcmp(p, "gif", 3)) {
932         ctx->impl->output.type = GRN_CONTENT_NONE;
933         ctx->impl->output.mime_type = "image/gif";
934       }
935       break;
936     case 'h' :
937       if (p + 4 == pe && !memcmp(p, "html", 4)) {
938         ctx->impl->output.type = GRN_CONTENT_NONE;
939         ctx->impl->output.mime_type = "text/html";
940       }
941       break;
942     case 'j' :
943       if (!memcmp(p, "js", 2)) {
944         if (p + 2 == pe) {
945           ctx->impl->output.type = GRN_CONTENT_NONE;
946           ctx->impl->output.mime_type = "text/javascript";
947         } else if (p + 4 == pe && !memcmp(p + 2, "on", 2)) {
948           ctx->impl->output.type = GRN_CONTENT_JSON;
949           ctx->impl->output.mime_type = "application/json";
950         }
951       } else if (p + 3 == pe && !memcmp(p, "jpg", 3)) {
952         ctx->impl->output.type = GRN_CONTENT_NONE;
953         ctx->impl->output.mime_type = "image/jpeg";
954       }
955       break;
956 #ifdef GRN_WITH_MESSAGE_PACK
957     case 'm' :
958       if (p + 7 == pe && !memcmp(p, "msgpack", 7)) {
959         ctx->impl->output.type = GRN_CONTENT_MSGPACK;
960         ctx->impl->output.mime_type = "application/x-msgpack";
961       }
962       break;
963 #endif
964     case 'p' :
965       if (p + 3 == pe && !memcmp(p, "png", 3)) {
966         ctx->impl->output.type = GRN_CONTENT_NONE;
967         ctx->impl->output.mime_type = "image/png";
968       }
969       break;
970     case 't' :
971       if (p + 3 == pe && !memcmp(p, "txt", 3)) {
972         ctx->impl->output.type = GRN_CONTENT_NONE;
973         ctx->impl->output.mime_type = "text/plain";
974       } else if (p + 3 == pe && !memcmp(p, "tsv", 3)) {
975         ctx->impl->output.type = GRN_CONTENT_TSV;
976         ctx->impl->output.mime_type = "text/tab-separated-values";
977       }
978       break;
979     case 'x':
980       if (p + 3 == pe && !memcmp(p, "xml", 3)) {
981         ctx->impl->output.type = GRN_CONTENT_XML;
982         ctx->impl->output.mime_type = "text/xml";
983       }
984       break;
985     }
986   }
987 }
988 
989 static void
grn_str_get_mime_type(grn_ctx * ctx,const char * p,const char * pe,const char ** key_end,const char ** filename_end)990 grn_str_get_mime_type(grn_ctx *ctx, const char *p, const char *pe,
991                      const char **key_end, const char **filename_end)
992 {
993   const char *pd = NULL;
994   for (; p < pe && *p != '?' && *p != '#'; p++) {
995     if (*p == '.') { pd = p; }
996   }
997   *filename_end = p;
998   if (pd && pd < p) {
999     get_content_mime_type(ctx, pd + 1, p);
1000     *key_end = pd;
1001   } else {
1002     *key_end = pe;
1003   }
1004 }
1005 
1006 static void
get_command_version(grn_ctx * ctx,const char * p,const char * pe)1007 get_command_version(grn_ctx *ctx, const char *p, const char *pe)
1008 {
1009   grn_command_version version;
1010   const char *rest;
1011 
1012   version = grn_atoui(p, pe, &rest);
1013   if (pe == rest) {
1014     grn_rc rc;
1015     rc = grn_ctx_set_command_version(ctx, version);
1016     if (rc == GRN_UNSUPPORTED_COMMAND_VERSION) {
1017       ERR(rc,
1018           "unsupported command version is specified: %d: "
1019           "stable command version: %d: "
1020           "available command versions: %d-%d",
1021           version,
1022           GRN_COMMAND_VERSION_STABLE,
1023           GRN_COMMAND_VERSION_MIN, GRN_COMMAND_VERSION_MAX);
1024     }
1025   }
1026 }
1027 
1028 #define INDEX_HTML          "index.html"
1029 #define OUTPUT_TYPE         "output_type"
1030 #define COMMAND_VERSION     "command_version"
1031 #define REQUEST_ID          "request_id"
1032 #define REQUEST_TIMEOUT     "request_timeout"
1033 #define OUTPUT_PRETTY       "output_pretty"
1034 #define EXPR_MISSING        "expr_missing"
1035 #define OUTPUT_TYPE_LEN     (sizeof(OUTPUT_TYPE) - 1)
1036 #define COMMAND_VERSION_LEN (sizeof(COMMAND_VERSION) - 1)
1037 #define REQUEST_ID_LEN      (sizeof(REQUEST_ID) - 1)
1038 #define REQUEST_TIMEOUT_LEN (sizeof(REQUEST_TIMEOUT) - 1)
1039 #define OUTPUT_PRETTY_LEN   (sizeof(OUTPUT_PRETTY) - 1)
1040 
1041 #define HTTP_QUERY_PAIR_DELIMITER   "="
1042 #define HTTP_QUERY_PAIRS_DELIMITERS "&;"
1043 
1044 static inline int
command_proc_p(grn_obj * expr)1045 command_proc_p(grn_obj *expr)
1046 {
1047   return (expr->header.type == GRN_PROC &&
1048           ((grn_proc *)expr)->type == GRN_PROC_COMMAND);
1049 }
1050 
1051 grn_obj *
grn_ctx_qe_exec_uri(grn_ctx * ctx,const char * path,uint32_t path_len)1052 grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len)
1053 {
1054   grn_obj buf, *expr, *val;
1055   grn_obj request_id;
1056   double request_timeout;
1057   const char *p = path, *e = path + path_len, *v, *key_end, *filename_end;
1058 
1059   request_timeout = grn_get_default_request_timeout();
1060 
1061   GRN_TEXT_INIT(&buf, 0);
1062   GRN_TEXT_INIT(&request_id, 0);
1063   p = grn_text_urldec(ctx, &buf, p, e, '?');
1064   if (!GRN_TEXT_LEN(&buf)) { GRN_TEXT_SETS(ctx, &buf, INDEX_HTML); }
1065   v = GRN_TEXT_VALUE(&buf);
1066   grn_str_get_mime_type(ctx, v, GRN_BULK_CURR(&buf), &key_end, &filename_end);
1067   if ((GRN_TEXT_LEN(&buf) >= 2 && v[0] == 'd' && v[1] == '/')) {
1068     const char *command_name = v + 2;
1069     int command_name_size = key_end - command_name;
1070     expr = grn_ctx_get(ctx, command_name, command_name_size);
1071     if (expr && command_proc_p(expr)) {
1072       while (p < e) {
1073         int l;
1074         GRN_BULK_REWIND(&buf);
1075         p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIR_DELIMITER);
1076         v = GRN_TEXT_VALUE(&buf);
1077         l = GRN_TEXT_LEN(&buf);
1078         if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
1079           GRN_BULK_REWIND(&buf);
1080           p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1081           v = GRN_TEXT_VALUE(&buf);
1082           get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf));
1083         } else if (l == COMMAND_VERSION_LEN &&
1084                    !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) {
1085           GRN_BULK_REWIND(&buf);
1086           p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1087           get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf));
1088           if (ctx->rc) { goto exit; }
1089         } else if (l == REQUEST_ID_LEN &&
1090                    !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) {
1091           GRN_BULK_REWIND(&request_id);
1092           p = grn_text_cgidec(ctx, &request_id, p, e,
1093                               HTTP_QUERY_PAIRS_DELIMITERS);
1094         } else if (l == REQUEST_TIMEOUT_LEN &&
1095                    !memcmp(v, REQUEST_TIMEOUT, REQUEST_TIMEOUT_LEN)) {
1096           GRN_BULK_REWIND(&buf);
1097           p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1098           GRN_TEXT_PUTC(ctx, &buf, '\0');
1099           request_timeout = strtod(GRN_TEXT_VALUE(&buf), NULL);
1100         } else if (l == OUTPUT_PRETTY_LEN &&
1101                    !memcmp(v, OUTPUT_PRETTY, OUTPUT_PRETTY_LEN)) {
1102           GRN_BULK_REWIND(&buf);
1103           p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1104           if (GRN_TEXT_LEN(&buf) == strlen("yes") &&
1105               !memcmp(GRN_TEXT_VALUE(&buf), "yes", GRN_TEXT_LEN(&buf))) {
1106             ctx->impl->output.is_pretty = GRN_TRUE;
1107           } else {
1108             ctx->impl->output.is_pretty = GRN_FALSE;
1109           }
1110         } else {
1111           if (!(val = grn_expr_get_or_add_var(ctx, expr, v, l))) {
1112             val = &buf;
1113           }
1114           grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1115           p = grn_text_cgidec(ctx, val, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
1116         }
1117       }
1118       if (request_timeout > 0 && GRN_TEXT_LEN(&request_id) == 0) {
1119         grn_text_printf(ctx, &request_id, "%p", ctx);
1120       }
1121       if (GRN_TEXT_LEN(&request_id) > 0) {
1122         GRN_TEXT_SET(ctx, &ctx->impl->current_request_id,
1123                      GRN_TEXT_VALUE(&request_id),
1124                      GRN_TEXT_LEN(&request_id));
1125         grn_request_canceler_register(ctx,
1126                                       GRN_TEXT_VALUE(&request_id),
1127                                       GRN_TEXT_LEN(&request_id));
1128         if (request_timeout > 0.0) {
1129           ctx->impl->current_request_timer_id =
1130             grn_request_timer_register(GRN_TEXT_VALUE(&request_id),
1131                                        GRN_TEXT_LEN(&request_id),
1132                                        request_timeout);
1133         }
1134       }
1135       ctx->impl->curr_expr = expr;
1136       grn_expr_exec(ctx, expr, 0);
1137     } else {
1138       ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s",
1139           command_name_size, command_name);
1140     }
1141   } else if ((expr = grn_ctx_get(ctx, GRN_EXPR_MISSING_NAME,
1142                                  strlen(GRN_EXPR_MISSING_NAME)))) {
1143     if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) {
1144       grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1145       GRN_TEXT_SET(ctx, val, v, filename_end - v);
1146     }
1147     ctx->impl->curr_expr = expr;
1148     grn_expr_exec(ctx, expr, 0);
1149   }
1150 exit :
1151   GRN_OBJ_FIN(ctx, &request_id);
1152   GRN_OBJ_FIN(ctx, &buf);
1153 
1154   return expr;
1155 }
1156 
1157 grn_obj *
grn_ctx_qe_exec(grn_ctx * ctx,const char * str,uint32_t str_len)1158 grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len)
1159 {
1160   char tok_type;
1161   int offset = 0;
1162   grn_obj buf, *expr = NULL, *val = NULL;
1163   grn_obj request_id;
1164   double request_timeout;
1165   const char *p = str, *e = str + str_len, *v;
1166 
1167   request_timeout = grn_get_default_request_timeout();
1168 
1169   GRN_TEXT_INIT(&buf, 0);
1170   GRN_TEXT_INIT(&request_id, 0);
1171   p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1172   expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1173   while (p < e) {
1174     GRN_BULK_REWIND(&buf);
1175     p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1176     v = GRN_TEXT_VALUE(&buf);
1177     switch (tok_type) {
1178     case GRN_TOK_VOID :
1179       p = e;
1180       break;
1181     case GRN_TOK_SYMBOL :
1182       if (GRN_TEXT_LEN(&buf) > 2 && v[0] == '-' && v[1] == '-') {
1183         int l = GRN_TEXT_LEN(&buf) - 2;
1184         v += 2;
1185         if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
1186           GRN_BULK_REWIND(&buf);
1187           p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1188           v = GRN_TEXT_VALUE(&buf);
1189           get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf));
1190         } else if (l == COMMAND_VERSION_LEN &&
1191                    !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) {
1192           GRN_BULK_REWIND(&buf);
1193           p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1194           get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf));
1195           if (ctx->rc) { goto exit; }
1196         } else if (l == REQUEST_ID_LEN &&
1197                    !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) {
1198           GRN_BULK_REWIND(&request_id);
1199           p = grn_text_unesc_tok(ctx, &request_id, p, e, &tok_type);
1200         } else if (l == REQUEST_TIMEOUT_LEN &&
1201                    !memcmp(v, REQUEST_TIMEOUT, REQUEST_TIMEOUT_LEN)) {
1202           GRN_BULK_REWIND(&buf);
1203           p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1204           GRN_TEXT_PUTC(ctx, &buf, '\0');
1205           request_timeout = strtod(GRN_TEXT_VALUE(&buf), NULL);
1206         } else if (l == OUTPUT_PRETTY_LEN &&
1207                    !memcmp(v, OUTPUT_PRETTY, OUTPUT_PRETTY_LEN)) {
1208           GRN_BULK_REWIND(&buf);
1209           p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
1210           if (GRN_TEXT_LEN(&buf) == strlen("yes") &&
1211               !memcmp(GRN_TEXT_VALUE(&buf), "yes", GRN_TEXT_LEN(&buf))) {
1212             ctx->impl->output.is_pretty = GRN_TRUE;
1213           } else {
1214             ctx->impl->output.is_pretty = GRN_FALSE;
1215           }
1216         } else if (expr && (val = grn_expr_get_or_add_var(ctx, expr, v, l))) {
1217           grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1218           p = grn_text_unesc_tok(ctx, val, p, e, &tok_type);
1219         } else {
1220           p = e;
1221         }
1222         break;
1223       }
1224       // fallthru
1225     case GRN_TOK_STRING :
1226     case GRN_TOK_QUOTE :
1227       if (expr && (val = grn_expr_get_var_by_offset(ctx, expr, offset++))) {
1228         grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1229         GRN_TEXT_PUT(ctx, val, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
1230       } else {
1231         p = e;
1232       }
1233       break;
1234     }
1235   }
1236   if (request_timeout > 0 && GRN_TEXT_LEN(&request_id) == 0) {
1237     grn_text_printf(ctx, &request_id, "%p", ctx);
1238   }
1239   if (GRN_TEXT_LEN(&request_id) > 0) {
1240     GRN_TEXT_SET(ctx, &ctx->impl->current_request_id,
1241                  GRN_TEXT_VALUE(&request_id),
1242                  GRN_TEXT_LEN(&request_id));
1243     grn_request_canceler_register(ctx,
1244                                   GRN_TEXT_VALUE(&request_id),
1245                                   GRN_TEXT_LEN(&request_id));
1246     if (request_timeout > 0.0) {
1247       ctx->impl->current_request_timer_id =
1248         grn_request_timer_register(GRN_TEXT_VALUE(&request_id),
1249                                    GRN_TEXT_LEN(&request_id),
1250                                    request_timeout);
1251     }
1252   }
1253   ctx->impl->curr_expr = expr;
1254   if (expr && command_proc_p(expr)) {
1255     grn_expr_exec(ctx, expr, 0);
1256   } else {
1257     GRN_BULK_REWIND(&buf);
1258     grn_text_unesc_tok(ctx, &buf, str, str + str_len, &tok_type);
1259     if (GRN_TEXT_LEN(&buf)) {
1260       ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s",
1261           (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
1262     }
1263   }
1264 exit :
1265   GRN_OBJ_FIN(ctx, &request_id);
1266   GRN_OBJ_FIN(ctx, &buf);
1267 
1268   return expr;
1269 }
1270 
1271 grn_rc
grn_ctx_sendv(grn_ctx * ctx,int argc,char ** argv,int flags)1272 grn_ctx_sendv(grn_ctx *ctx, int argc, char **argv, int flags)
1273 {
1274   grn_obj buf;
1275   GRN_API_ENTER;
1276   GRN_TEXT_INIT(&buf, 0);
1277   while (argc--) {
1278     // todo : encode into json like syntax
1279     GRN_TEXT_PUTS(ctx, &buf, *argv);
1280     argv++;
1281     if (argc) { GRN_TEXT_PUTC(ctx, &buf, ' '); }
1282   }
1283   grn_ctx_send(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), flags);
1284   GRN_OBJ_FIN(ctx, &buf);
1285   GRN_API_RETURN(ctx->rc);
1286 }
1287 
1288 static int
comment_command_p(const char * command,unsigned int length)1289 comment_command_p(const char *command, unsigned int length)
1290 {
1291   const char *p, *e;
1292 
1293   e = command + length;
1294   for (p = command; p < e; p++) {
1295     switch (*p) {
1296     case '#' :
1297       return GRN_TRUE;
1298     case ' ' :
1299     case '\t' :
1300       break;
1301     default :
1302       return GRN_FALSE;
1303     }
1304   }
1305   return GRN_FALSE;
1306 }
1307 
1308 unsigned int
grn_ctx_send(grn_ctx * ctx,const char * str,unsigned int str_len,int flags)1309 grn_ctx_send(grn_ctx *ctx, const char *str, unsigned int str_len, int flags)
1310 {
1311   if (!ctx) { return 0; }
1312   GRN_API_ENTER;
1313   if (ctx->impl) {
1314     if ((flags & GRN_CTX_MORE)) { flags |= GRN_CTX_QUIET; }
1315     if (ctx->stat == GRN_CTX_QUIT) { flags |= GRN_CTX_QUIT; }
1316 
1317     ctx->impl->command.flags = flags;
1318     if (ctx->impl->com) {
1319       grn_rc rc;
1320       grn_com_header sheader;
1321       grn_timeval_now(ctx, &ctx->impl->tv);
1322       sheader.proto = GRN_COM_PROTO_GQTP;
1323       sheader.qtype = 0;
1324       sheader.keylen = 0;
1325       sheader.level = 0;
1326       sheader.flags = flags;
1327       sheader.status = 0;
1328       sheader.opaque = 0;
1329       sheader.cas = 0;
1330       if ((rc = grn_com_send(ctx, ctx->impl->com, &sheader, (char *)str, str_len, 0))) {
1331         ERR(rc, "grn_com_send failed");
1332       }
1333       goto exit;
1334     } else {
1335       grn_command_version command_version;
1336       grn_obj *expr = NULL;
1337 
1338       command_version = grn_ctx_get_command_version(ctx);
1339       if (ctx->impl->command.keep.command) {
1340         grn_obj *val;
1341         expr = ctx->impl->command.keep.command;
1342         ctx->impl->command.keep.command = NULL;
1343         grn_ctx_set_command_version(ctx, ctx->impl->command.keep.version);
1344         if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) {
1345           grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
1346           GRN_TEXT_PUT(ctx, val, str, str_len);
1347         }
1348         grn_expr_exec(ctx, expr, 0);
1349       } else {
1350         if (comment_command_p(str, str_len)) { goto output; };
1351         GRN_BULK_REWIND(ctx->impl->output.buf);
1352         ctx->impl->output.type = GRN_CONTENT_JSON;
1353         ctx->impl->output.mime_type = "application/json";
1354         ctx->impl->output.is_pretty = GRN_FALSE;
1355         grn_timeval_now(ctx, &ctx->impl->tv);
1356         GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_COMMAND,
1357                       ">", "%.*s", str_len, str);
1358         if (str_len && *str == '/') {
1359           expr = grn_ctx_qe_exec_uri(ctx, str + 1, str_len - 1);
1360         } else {
1361           expr = grn_ctx_qe_exec(ctx, str, str_len);
1362         }
1363       }
1364       if (ctx->stat == GRN_CTX_QUITTING) { ctx->stat = GRN_CTX_QUIT; }
1365       if (ctx->impl->command.keep.command) {
1366         ERRCLR(ctx);
1367       } else {
1368         if (ctx->impl->current_request_timer_id) {
1369           void *timer_id = ctx->impl->current_request_timer_id;
1370           ctx->impl->current_request_timer_id = NULL;
1371           grn_request_timer_unregister(timer_id);
1372         }
1373         if (GRN_TEXT_LEN(&ctx->impl->current_request_id) > 0) {
1374           grn_obj *request_id = &ctx->impl->current_request_id;
1375           grn_request_canceler_unregister(ctx,
1376                                           GRN_TEXT_VALUE(request_id),
1377                                           GRN_TEXT_LEN(request_id));
1378           GRN_BULK_REWIND(&ctx->impl->current_request_id);
1379         }
1380         GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_RESULT_CODE,
1381                       "<", "rc=%d", ctx->rc);
1382       }
1383     output :
1384       if (!(ctx->impl->command.flags & GRN_CTX_QUIET) &&
1385           ctx->impl->output.func) {
1386         ctx->impl->output.func(ctx, GRN_CTX_TAIL, ctx->impl->output.data.ptr);
1387       }
1388       if (expr) { grn_expr_clear_vars(ctx, expr); }
1389       grn_ctx_set_command_version(ctx, command_version);
1390       goto exit;
1391     }
1392   }
1393   ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned");
1394 exit :
1395   GRN_API_RETURN(0);
1396 }
1397 
1398 unsigned int
grn_ctx_recv(grn_ctx * ctx,char ** str,unsigned int * str_len,int * flags)1399 grn_ctx_recv(grn_ctx *ctx, char **str, unsigned int *str_len, int *flags)
1400 {
1401   if (!ctx) { return GRN_INVALID_ARGUMENT; }
1402 
1403   *flags = 0;
1404 
1405   if (ctx->stat == GRN_CTX_QUIT) {
1406     grn_bool have_buffer = GRN_FALSE;
1407 
1408     if (ctx->impl &&
1409         !ctx->impl->com &&
1410         GRN_TEXT_LEN(ctx->impl->output.buf) > 0) {
1411       have_buffer = GRN_TRUE;
1412     }
1413 
1414     *flags |= GRN_CTX_QUIT;
1415     if (!have_buffer) {
1416       *str = NULL;
1417       *str_len = 0;
1418       return 0;
1419     }
1420   }
1421 
1422   GRN_API_ENTER;
1423   if (ctx->impl) {
1424     if (ctx->impl->com) {
1425       grn_com_header header;
1426       if (grn_com_recv(ctx, ctx->impl->com, &header, ctx->impl->output.buf)) {
1427         *str = NULL;
1428         *str_len = 0;
1429         *flags = 0;
1430       } else {
1431         *str = GRN_BULK_HEAD(ctx->impl->output.buf);
1432         *str_len = GRN_BULK_VSIZE(ctx->impl->output.buf);
1433         if (header.flags & GRN_CTX_QUIT) {
1434           ctx->stat = GRN_CTX_QUIT;
1435           *flags |= GRN_CTX_QUIT;
1436         } else {
1437           if (!(header.flags & GRN_CTX_TAIL)) {
1438             *flags |= GRN_CTX_MORE;
1439           }
1440         }
1441         ctx->impl->output.type = header.qtype;
1442         ctx->rc = (int16_t)ntohs(header.status);
1443         ctx->errbuf[0] = '\0';
1444         ctx->errline = 0;
1445         ctx->errfile = NULL;
1446         ctx->errfunc = NULL;
1447       }
1448       goto exit;
1449     } else {
1450       grn_obj *buf = ctx->impl->output.buf;
1451       unsigned int head = 0, tail = GRN_BULK_VSIZE(buf);
1452       *str = GRN_BULK_HEAD(buf) + head;
1453       *str_len = tail - head;
1454       GRN_BULK_REWIND(ctx->impl->output.buf);
1455       goto exit;
1456     }
1457   }
1458   ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned");
1459 exit :
1460   GRN_API_RETURN(0);
1461 }
1462 
1463 void
grn_ctx_stream_out_func(grn_ctx * ctx,int flags,void * stream)1464 grn_ctx_stream_out_func(grn_ctx *ctx, int flags, void *stream)
1465 {
1466   if (ctx && ctx->impl) {
1467     grn_obj *buf = ctx->impl->output.buf;
1468     uint32_t size = GRN_BULK_VSIZE(buf);
1469     if (size) {
1470       if (fwrite(GRN_BULK_HEAD(buf), 1, size, (FILE *)stream)) {
1471         fputc('\n', (FILE *)stream);
1472         fflush((FILE *)stream);
1473       }
1474       GRN_BULK_REWIND(buf);
1475     }
1476   }
1477 }
1478 
1479 void
grn_ctx_recv_handler_set(grn_ctx * ctx,void (* func)(grn_ctx *,int,void *),void * func_arg)1480 grn_ctx_recv_handler_set(grn_ctx *ctx, void (*func)(grn_ctx *, int, void *), void *func_arg)
1481 {
1482   if (ctx && ctx->impl) {
1483     ctx->impl->output.func = func;
1484     ctx->impl->output.data.ptr = func_arg;
1485   }
1486 }
1487 
1488 grn_rc
grn_ctx_info_get(grn_ctx * ctx,grn_ctx_info * info)1489 grn_ctx_info_get(grn_ctx *ctx, grn_ctx_info *info)
1490 {
1491   if (!ctx || !ctx->impl) { return GRN_INVALID_ARGUMENT; }
1492   if (ctx->impl->com) {
1493     info->fd = ctx->impl->com->fd;
1494     info->com_status = ctx->impl->com_status;
1495     info->outbuf = ctx->impl->output.buf;
1496     info->stat = ctx->stat;
1497   } else {
1498     info->fd = -1;
1499     info->com_status = 0;
1500     info->outbuf = ctx->impl->output.buf;
1501     info->stat = ctx->stat;
1502   }
1503   return GRN_SUCCESS;
1504 }
1505 
1506 #define DB_P(s) ((s) && (s)->header.type == GRN_DB)
1507 
1508 grn_rc
grn_ctx_use(grn_ctx * ctx,grn_obj * db)1509 grn_ctx_use(grn_ctx *ctx, grn_obj *db)
1510 {
1511   GRN_API_ENTER;
1512   if (db && !DB_P(db)) {
1513     ctx->rc = GRN_INVALID_ARGUMENT;
1514   } else {
1515     if (!ctx->rc) {
1516       ctx->impl->db = db;
1517       if (db) {
1518         grn_obj buf;
1519         GRN_TEXT_INIT(&buf, 0);
1520         grn_obj_get_info(ctx, db, GRN_INFO_ENCODING, &buf);
1521         ctx->encoding = *(grn_encoding *)GRN_BULK_HEAD(&buf);
1522         grn_obj_close(ctx, &buf);
1523       }
1524     }
1525   }
1526   GRN_API_RETURN(ctx->rc);
1527 }
1528 
1529 /* don't handle error inside logger functions */
1530 
1531 void
grn_ctx_log(grn_ctx * ctx,const char * fmt,...)1532 grn_ctx_log(grn_ctx *ctx, const char *fmt, ...)
1533 {
1534   va_list ap;
1535   va_start(ap, fmt);
1536   grn_ctx_logv(ctx, fmt, ap);
1537   va_end(ap);
1538 }
1539 
1540 void
grn_ctx_logv(grn_ctx * ctx,const char * fmt,va_list ap)1541 grn_ctx_logv(grn_ctx *ctx, const char *fmt, va_list ap)
1542 {
1543   char buffer[GRN_CTX_MSGSIZE];
1544   grn_vsnprintf(buffer, GRN_CTX_MSGSIZE, fmt, ap);
1545   grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, buffer);
1546 }
1547 
1548 void
grn_assert(grn_ctx * ctx,int cond,const char * file,int line,const char * func)1549 grn_assert(grn_ctx *ctx, int cond, const char* file, int line, const char* func)
1550 {
1551   if (!cond) {
1552     GRN_LOG(ctx, GRN_LOG_WARNING, "ASSERT fail on %s %s:%d", func, file, line);
1553   }
1554 }
1555 
1556 const char *
grn_get_version(void)1557 grn_get_version(void)
1558 {
1559   return GRN_VERSION;
1560 }
1561 
1562 const char *
grn_get_package(void)1563 grn_get_package(void)
1564 {
1565   return PACKAGE;
1566 }
1567 
1568 const char *
grn_get_package_label(void)1569 grn_get_package_label(void)
1570 {
1571   return PACKAGE_LABEL;
1572 }
1573 
1574 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
1575 static int segv_received = 0;
1576 static void
segv_handler(int signal_number,siginfo_t * info,void * context)1577 segv_handler(int signal_number, siginfo_t *info, void *context)
1578 {
1579   grn_ctx *ctx = &grn_gctx;
1580 
1581   if (segv_received) {
1582     GRN_LOG(ctx, GRN_LOG_CRIT, "SEGV received in SEGV handler.");
1583     exit(EXIT_FAILURE);
1584   }
1585   segv_received = 1;
1586 
1587   GRN_LOG(ctx, GRN_LOG_CRIT, "-- CRASHED!!! --");
1588 #ifdef HAVE_BACKTRACE
1589 #  define N_TRACE_LEVEL 1024
1590   {
1591     static void *trace[N_TRACE_LEVEL];
1592     int n = backtrace(trace, N_TRACE_LEVEL);
1593     char **symbols = backtrace_symbols(trace, n);
1594     int i;
1595 
1596     if (symbols) {
1597       for (i = 0; i < n; i++) {
1598         GRN_LOG(ctx, GRN_LOG_CRIT, "%s", symbols[i]);
1599       }
1600       free(symbols);
1601     }
1602   }
1603 #else /* HAVE_BACKTRACE */
1604   GRN_LOG(ctx, GRN_LOG_CRIT, "backtrace() isn't available.");
1605 #endif /* HAVE_BACKTRACE */
1606   GRN_LOG(ctx, GRN_LOG_CRIT, "----------------");
1607   abort();
1608 }
1609 #endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */
1610 
1611 grn_rc
grn_set_segv_handler(void)1612 grn_set_segv_handler(void)
1613 {
1614   grn_rc rc = GRN_SUCCESS;
1615 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
1616   grn_ctx *ctx = &grn_gctx;
1617   struct sigaction action;
1618 
1619   sigemptyset(&action.sa_mask);
1620   action.sa_sigaction = segv_handler;
1621   action.sa_flags = SA_SIGINFO | SA_ONSTACK;
1622 
1623   if (sigaction(SIGSEGV, &action, NULL)) {
1624     SERR("failed to set SIGSEGV action");
1625     rc = ctx->rc;
1626   };
1627 #endif
1628   return rc;
1629 }
1630 
1631 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
1632 static struct sigaction old_int_handler;
1633 static void
int_handler(int signal_number,siginfo_t * info,void * context)1634 int_handler(int signal_number, siginfo_t *info, void *context)
1635 {
1636   grn_gctx.stat = GRN_CTX_QUIT;
1637   sigaction(signal_number, &old_int_handler, NULL);
1638 }
1639 
1640 static struct sigaction old_term_handler;
1641 static void
term_handler(int signal_number,siginfo_t * info,void * context)1642 term_handler(int signal_number, siginfo_t *info, void *context)
1643 {
1644   grn_gctx.stat = GRN_CTX_QUIT;
1645   sigaction(signal_number, &old_term_handler, NULL);
1646 }
1647 #endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */
1648 
1649 grn_rc
grn_set_int_handler(void)1650 grn_set_int_handler(void)
1651 {
1652   grn_rc rc = GRN_SUCCESS;
1653 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
1654   grn_ctx *ctx = &grn_gctx;
1655   struct sigaction action;
1656 
1657   sigemptyset(&action.sa_mask);
1658   action.sa_sigaction = int_handler;
1659   action.sa_flags = SA_SIGINFO;
1660 
1661   if (sigaction(SIGINT, &action, &old_int_handler)) {
1662     SERR("failed to set SIGINT action");
1663     rc = ctx->rc;
1664   }
1665 #endif
1666   return rc;
1667 }
1668 
1669 grn_rc
grn_set_term_handler(void)1670 grn_set_term_handler(void)
1671 {
1672   grn_rc rc = GRN_SUCCESS;
1673 #if defined(HAVE_SIGNAL_H) && !defined(WIN32)
1674   grn_ctx *ctx = &grn_gctx;
1675   struct sigaction action;
1676 
1677   sigemptyset(&action.sa_mask);
1678   action.sa_sigaction = term_handler;
1679   action.sa_flags = SA_SIGINFO;
1680 
1681   if (sigaction(SIGTERM, &action, &old_term_handler)) {
1682     SERR("failed to set SIGTERM action");
1683     rc = ctx->rc;
1684   }
1685 #endif
1686   return rc;
1687 }
1688 
1689 void
grn_ctx_output_flush(grn_ctx * ctx,int flags)1690 grn_ctx_output_flush(grn_ctx *ctx, int flags)
1691 {
1692   if (flags & GRN_CTX_QUIET) {
1693     return;
1694   }
1695   if (!ctx->impl->output.func) {
1696     return;
1697   }
1698   ctx->impl->output.func(ctx, 0, ctx->impl->output.data.ptr);
1699 }
1700 
1701 void
grn_ctx_output_array_open(grn_ctx * ctx,const char * name,int nelements)1702 grn_ctx_output_array_open(grn_ctx *ctx, const char *name, int nelements)
1703 {
1704   grn_output_array_open(ctx,
1705                         ctx->impl->output.buf,
1706                         ctx->impl->output.type,
1707                         name, nelements);
1708 }
1709 
1710 void
grn_ctx_output_array_close(grn_ctx * ctx)1711 grn_ctx_output_array_close(grn_ctx *ctx)
1712 {
1713   grn_output_array_close(ctx,
1714                          ctx->impl->output.buf,
1715                          ctx->impl->output.type);
1716 }
1717 
1718 void
grn_ctx_output_map_open(grn_ctx * ctx,const char * name,int nelements)1719 grn_ctx_output_map_open(grn_ctx *ctx, const char *name, int nelements)
1720 {
1721   grn_output_map_open(ctx,
1722                       ctx->impl->output.buf,
1723                       ctx->impl->output.type,
1724                       name, nelements);
1725 }
1726 
1727 void
grn_ctx_output_map_close(grn_ctx * ctx)1728 grn_ctx_output_map_close(grn_ctx *ctx)
1729 {
1730   grn_output_map_close(ctx,
1731                        ctx->impl->output.buf,
1732                        ctx->impl->output.type);
1733 }
1734 
1735 void
grn_ctx_output_null(grn_ctx * ctx)1736 grn_ctx_output_null(grn_ctx *ctx)
1737 {
1738   grn_output_null(ctx,
1739                   ctx->impl->output.buf,
1740                   ctx->impl->output.type);
1741 }
1742 
1743 void
grn_ctx_output_int32(grn_ctx * ctx,int value)1744 grn_ctx_output_int32(grn_ctx *ctx, int value)
1745 {
1746   grn_output_int32(ctx,
1747                    ctx->impl->output.buf,
1748                    ctx->impl->output.type,
1749                    value);
1750 }
1751 
1752 void
grn_ctx_output_int64(grn_ctx * ctx,int64_t value)1753 grn_ctx_output_int64(grn_ctx *ctx, int64_t value)
1754 {
1755   grn_output_int64(ctx,
1756                    ctx->impl->output.buf,
1757                    ctx->impl->output.type,
1758                    value);
1759 }
1760 
1761 void
grn_ctx_output_uint64(grn_ctx * ctx,uint64_t value)1762 grn_ctx_output_uint64(grn_ctx *ctx, uint64_t value)
1763 {
1764   grn_output_uint64(ctx,
1765                     ctx->impl->output.buf,
1766                     ctx->impl->output.type,
1767                     value);
1768 }
1769 
1770 void
grn_ctx_output_float(grn_ctx * ctx,double value)1771 grn_ctx_output_float(grn_ctx *ctx, double value)
1772 {
1773   grn_output_float(ctx,
1774                    ctx->impl->output.buf,
1775                    ctx->impl->output.type,
1776                    value);
1777 }
1778 
1779 void
grn_ctx_output_cstr(grn_ctx * ctx,const char * value)1780 grn_ctx_output_cstr(grn_ctx *ctx, const char *value)
1781 {
1782   grn_output_cstr(ctx,
1783                   ctx->impl->output.buf,
1784                   ctx->impl->output.type,
1785                   value);
1786 }
1787 
1788 void
grn_ctx_output_str(grn_ctx * ctx,const char * value,unsigned int value_len)1789 grn_ctx_output_str(grn_ctx *ctx, const char *value, unsigned int value_len)
1790 {
1791   grn_output_str(ctx,
1792                  ctx->impl->output.buf,
1793                  ctx->impl->output.type,
1794                  value, value_len);
1795 }
1796 
1797 void
grn_ctx_output_bool(grn_ctx * ctx,grn_bool value)1798 grn_ctx_output_bool(grn_ctx *ctx, grn_bool value)
1799 {
1800   grn_output_bool(ctx,
1801                   ctx->impl->output.buf,
1802                   ctx->impl->output.type,
1803                   value);
1804 }
1805 
1806 void
grn_ctx_output_obj(grn_ctx * ctx,grn_obj * value,grn_obj_format * format)1807 grn_ctx_output_obj(grn_ctx *ctx, grn_obj *value, grn_obj_format *format)
1808 {
1809   grn_output_obj(ctx,
1810                  ctx->impl->output.buf,
1811                  ctx->impl->output.type,
1812                  value, format);
1813 }
1814 
1815 void
grn_ctx_output_result_set_open(grn_ctx * ctx,grn_obj * result_set,grn_obj_format * format,uint32_t n_additional_elements)1816 grn_ctx_output_result_set_open(grn_ctx *ctx,
1817                                grn_obj *result_set,
1818                                grn_obj_format *format,
1819                                uint32_t n_additional_elements)
1820 {
1821   grn_output_result_set_open(ctx,
1822                              ctx->impl->output.buf,
1823                              ctx->impl->output.type,
1824                              result_set,
1825                              format,
1826                              n_additional_elements);
1827 }
1828 
1829 void
grn_ctx_output_result_set_close(grn_ctx * ctx,grn_obj * result_set,grn_obj_format * format)1830 grn_ctx_output_result_set_close(grn_ctx *ctx,
1831                                 grn_obj *result_set,
1832                                 grn_obj_format *format)
1833 {
1834   grn_output_result_set_close(ctx,
1835                               ctx->impl->output.buf,
1836                               ctx->impl->output.type,
1837                               result_set,
1838                               format);
1839 }
1840 
1841 void
grn_ctx_output_result_set(grn_ctx * ctx,grn_obj * result_set,grn_obj_format * format)1842 grn_ctx_output_result_set(grn_ctx *ctx,
1843                           grn_obj *result_set,
1844                           grn_obj_format *format)
1845 {
1846   grn_output_result_set(ctx,
1847                         ctx->impl->output.buf,
1848                         ctx->impl->output.type,
1849                         result_set,
1850                         format);
1851 }
1852 
1853 void
grn_ctx_output_table_columns(grn_ctx * ctx,grn_obj * table,grn_obj_format * format)1854 grn_ctx_output_table_columns(grn_ctx *ctx, grn_obj *table,
1855                              grn_obj_format *format)
1856 {
1857   grn_output_table_columns(ctx,
1858                            ctx->impl->output.buf,
1859                            ctx->impl->output.type,
1860                            table,
1861                            format);
1862 }
1863 
1864 void
grn_ctx_output_table_records(grn_ctx * ctx,grn_obj * table,grn_obj_format * format)1865 grn_ctx_output_table_records(grn_ctx *ctx, grn_obj *table,
1866                              grn_obj_format *format)
1867 {
1868   grn_output_table_records(ctx,
1869                            ctx->impl->output.buf,
1870                            ctx->impl->output.type,
1871                            table,
1872                            format);
1873 }
1874