mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 20:36:16 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			2880 lines
		
	
	
	
		
			89 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2880 lines
		
	
	
	
		
			89 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* -*- c-basic-offset: 2 -*- */
 | 
						|
/* Copyright(C) 2009-2015 Brazil
 | 
						|
 | 
						|
  This library is free software; you can redistribute it and/or
 | 
						|
  modify it under the terms of the GNU Lesser General Public
 | 
						|
  License version 2.1 as published by the Free Software Foundation.
 | 
						|
 | 
						|
  This library is distributed in the hope that it will be useful,
 | 
						|
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
  Lesser General Public License for more details.
 | 
						|
 | 
						|
  You should have received a copy of the GNU Lesser General Public
 | 
						|
  License along with this library; if not, write to the Free Software
 | 
						|
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
 | 
						|
*/
 | 
						|
 | 
						|
#include "grn.h"
 | 
						|
 | 
						|
#include <string.h>
 | 
						|
#include "grn_str.h"
 | 
						|
#include "grn_db.h"
 | 
						|
#include "grn_expr_code.h"
 | 
						|
#include "grn_util.h"
 | 
						|
#include "grn_output.h"
 | 
						|
 | 
						|
#define LEVELS (&ctx->impl->output.levels)
 | 
						|
#define DEPTH (GRN_BULK_VSIZE(LEVELS)>>2)
 | 
						|
#define CURR_LEVEL (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1))) : 0)
 | 
						|
#define INCR_DEPTH(i) GRN_UINT32_PUT(ctx, LEVELS, i)
 | 
						|
#define DECR_DEPTH (DEPTH ? grn_bulk_truncate(ctx, LEVELS, GRN_BULK_VSIZE(LEVELS) - sizeof(uint32_t)) : 0)
 | 
						|
#define INCR_LENGTH (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1)) += 2) : 0)
 | 
						|
 | 
						|
static void
 | 
						|
indent(grn_ctx *ctx, grn_obj *outbuf, size_t level)
 | 
						|
{
 | 
						|
  size_t i;
 | 
						|
  for (i = 0; i < level; i++) {
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "  ");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_array_open(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
 | 
						|
{
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, '[');
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    (*indent_level)++;
 | 
						|
    indent(ctx, outbuf, *indent_level);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_array_close(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
 | 
						|
{
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    (*indent_level)--;
 | 
						|
    indent(ctx, outbuf, *indent_level);
 | 
						|
  }
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, ']');
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_element_end(grn_ctx *ctx, grn_obj *outbuf, size_t indent_level)
 | 
						|
{
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, ',');
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    indent(ctx, outbuf, indent_level);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_map_open(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
 | 
						|
{
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, '{');
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    (*indent_level)++;
 | 
						|
    indent(ctx, outbuf, *indent_level);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_map_close(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
 | 
						|
{
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    (*indent_level)--;
 | 
						|
    indent(ctx, outbuf, *indent_level);
 | 
						|
  }
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, '}');
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_key_end(grn_ctx *ctx, grn_obj *outbuf)
 | 
						|
{
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, ':');
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, ' ');
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_key(grn_ctx *ctx, grn_obj *outbuf, const char *key)
 | 
						|
{
 | 
						|
  grn_text_esc(ctx, outbuf, key, strlen(key));
 | 
						|
  json_key_end(ctx, outbuf);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
json_value_end(grn_ctx *ctx, grn_obj *outbuf, size_t indent_level)
 | 
						|
{
 | 
						|
  GRN_TEXT_PUTC(ctx, outbuf, ',');
 | 
						|
  if (ctx->impl->output.is_pretty) {
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    indent(ctx, outbuf, indent_level);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
put_delimiter(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
 | 
						|
{
 | 
						|
  uint32_t level = CURR_LEVEL;
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    if (level < 2) {
 | 
						|
      if (DEPTH > 0 && ctx->impl->output.is_pretty) {
 | 
						|
        GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
        indent(ctx, outbuf, DEPTH + 1);
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if ((level & 3) == 3) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, ':');
 | 
						|
      if (ctx->impl->output.is_pretty) {
 | 
						|
        GRN_TEXT_PUTC(ctx, outbuf, ' ');
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      json_element_end(ctx, outbuf, DEPTH + 1);
 | 
						|
    }
 | 
						|
    // if (DEPTH == 1 && ((level & 3) != 3)) { GRN_TEXT_PUTC(ctx, outbuf, '\n'); }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    if (!DEPTH) { return; }
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    if (level < 2) { return; }
 | 
						|
    if (DEPTH <= 2) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, ((level & 3) == 3) ? '\t' : '\n');
 | 
						|
    } else {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '\t');
 | 
						|
    }
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
    // do nothing
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_array_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                      const char *name, int nelements)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '[');
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '<');
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, name);
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '>');
 | 
						|
    grn_vector_add_element(ctx,
 | 
						|
                           &ctx->impl->output.names,
 | 
						|
                           name, strlen(name),
 | 
						|
                           0, GRN_DB_SHORT_TEXT);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "[\t"); }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    if (nelements < 0) {
 | 
						|
      GRN_LOG(ctx, GRN_LOG_DEBUG,
 | 
						|
              "grn_output_array_open nelements (%d) for <%s>",
 | 
						|
              nelements,
 | 
						|
              name);
 | 
						|
    }
 | 
						|
    msgpack_pack_array(&ctx->impl->output.msgpacker, nelements);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_DEPTH(0);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_array_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
 | 
						|
{
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    if (ctx->impl->output.is_pretty) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
      indent(ctx, outbuf, DEPTH);
 | 
						|
    }
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, ']');
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    if (DEPTH > 3) {
 | 
						|
      if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, ']');
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    {
 | 
						|
      const char *name;
 | 
						|
      unsigned int name_len;
 | 
						|
      name_len = grn_vector_pop_element(ctx,
 | 
						|
                                        &ctx->impl->output.names,
 | 
						|
                                        &name, NULL, NULL);
 | 
						|
      GRN_TEXT_PUTS(ctx, outbuf, "</");
 | 
						|
      GRN_TEXT_PUT(ctx, outbuf, name, name_len);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '>');
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
    // do nothing
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  DECR_DEPTH;
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_map_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                    const char *name, int nelements)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "{");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '<');
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, name);
 | 
						|
    GRN_TEXT_PUTC(ctx, outbuf, '>');
 | 
						|
    grn_vector_add_element(ctx,
 | 
						|
                           &ctx->impl->output.names,
 | 
						|
                           name, strlen(name), 0, GRN_DB_SHORT_TEXT);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "{\t"); }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    if (nelements < 0) {
 | 
						|
      GRN_LOG(ctx, GRN_LOG_DEBUG,
 | 
						|
              "grn_output_map_open nelements (%d) for <%s>",
 | 
						|
              nelements,
 | 
						|
              name);
 | 
						|
    }
 | 
						|
    msgpack_pack_map(&ctx->impl->output.msgpacker, nelements);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_DEPTH(1);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_map_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
 | 
						|
{
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    if (ctx->impl->output.is_pretty) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '\n');
 | 
						|
      indent(ctx, outbuf, DEPTH);
 | 
						|
    }
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "}");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    if (DEPTH > 3) {
 | 
						|
      if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '}');
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    {
 | 
						|
      const char *name;
 | 
						|
      unsigned int name_len;
 | 
						|
      name_len = grn_vector_pop_element(ctx,
 | 
						|
                                        &ctx->impl->output.names,
 | 
						|
                                        &name, NULL, NULL);
 | 
						|
      GRN_TEXT_PUTS(ctx, outbuf, "</");
 | 
						|
      GRN_TEXT_PUT(ctx, outbuf, name, name_len);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '>');
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
    // do nothing
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  DECR_DEPTH;
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_int32(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int value)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    grn_text_itoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_itoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
 | 
						|
    grn_text_itoa(ctx, outbuf, value);
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_int32(&ctx->impl->output.msgpacker, value);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    grn_text_itoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_int64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    grn_text_lltoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_lltoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
 | 
						|
    grn_text_lltoa(ctx, outbuf, value);
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_int64(&ctx->impl->output.msgpacker, value);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    grn_text_lltoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_uint64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, uint64_t value)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    grn_text_ulltoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_ulltoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
 | 
						|
    grn_text_ulltoa(ctx, outbuf, value);
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_uint64(&ctx->impl->output.msgpacker, value);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    grn_text_ulltoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_float(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, double value)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    grn_text_ftoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_ftoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<FLOAT>");
 | 
						|
    grn_text_ftoa(ctx, outbuf, value);
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</FLOAT>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_double(&ctx->impl->output.msgpacker, value);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    grn_text_ftoa(ctx, outbuf, value);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_str(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
               const char *value, size_t value_len)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    grn_text_esc(ctx, outbuf, value, value_len);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_esc(ctx, outbuf, value, value_len);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<TEXT>");
 | 
						|
    grn_text_escape_xml(ctx, outbuf, value, value_len);
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</TEXT>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_str(&ctx->impl->output.msgpacker, value_len);
 | 
						|
    msgpack_pack_str_body(&ctx->impl->output.msgpacker, value, value_len);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    GRN_TEXT_PUT(ctx, outbuf, value, value_len);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_cstr(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                const char *value)
 | 
						|
{
 | 
						|
  grn_output_str(ctx, outbuf, output_type, value, strlen(value));
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_bool(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, grn_bool value)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<BOOL>");
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</BOOL>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    if (value) {
 | 
						|
      msgpack_pack_true(&ctx->impl->output.msgpacker);
 | 
						|
    } else {
 | 
						|
      msgpack_pack_false(&ctx->impl->output.msgpacker);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_null(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "null");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<NULL/>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_nil(&ctx->impl->output.msgpacker);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_bulk_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                     const char *value, size_t value_len)
 | 
						|
{
 | 
						|
  if (value_len == sizeof(grn_id) && *(grn_id *)value == GRN_ID_NIL) {
 | 
						|
    grn_output_null(ctx, outbuf, output_type);
 | 
						|
  } else {
 | 
						|
    grn_output_str(ctx, outbuf, output_type, value, value_len);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_time(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
 | 
						|
{
 | 
						|
  double dv = value;
 | 
						|
  dv /= 1000000.0;
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    grn_text_ftoa(ctx, outbuf, dv);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_ftoa(ctx, outbuf, dv);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<DATE>");
 | 
						|
    grn_text_ftoa(ctx, outbuf, dv);
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</DATE>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    msgpack_pack_double(&ctx->impl->output.msgpacker, dv);
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    grn_text_ftoa(ctx, outbuf, dv);
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_geo_point(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                     grn_geo_point *value)
 | 
						|
{
 | 
						|
  put_delimiter(ctx, outbuf, output_type);
 | 
						|
  switch (output_type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    if (value) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '"');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->latitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, 'x');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->longitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '"');
 | 
						|
    } else {
 | 
						|
      GRN_TEXT_PUTS(ctx, outbuf, "null");
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    if (value) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '"');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->latitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, 'x');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->longitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '"');
 | 
						|
    } else {
 | 
						|
      GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "<GEO_POINT>");
 | 
						|
    if (value) {
 | 
						|
      grn_text_itoa(ctx, outbuf, value->latitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, 'x');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->longitude);
 | 
						|
    }
 | 
						|
    GRN_TEXT_PUTS(ctx, outbuf, "</GEO_POINT>");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK :
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    if (value) {
 | 
						|
      grn_obj buf;
 | 
						|
      GRN_TEXT_INIT(&buf, 0);
 | 
						|
      grn_text_itoa(ctx, &buf, value->latitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, &buf, 'x');
 | 
						|
      grn_text_itoa(ctx, &buf, value->longitude);
 | 
						|
      msgpack_pack_str(&ctx->impl->output.msgpacker, GRN_TEXT_LEN(&buf));
 | 
						|
      msgpack_pack_str_body(&ctx->impl->output.msgpacker,
 | 
						|
                            GRN_TEXT_VALUE(&buf),
 | 
						|
                            GRN_TEXT_LEN(&buf));
 | 
						|
      grn_obj_close(ctx, &buf);
 | 
						|
    } else {
 | 
						|
      msgpack_pack_nil(&ctx->impl->output.msgpacker);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    if (value) {
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '"');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->latitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, 'x');
 | 
						|
      grn_text_itoa(ctx, outbuf, value->longitude);
 | 
						|
      GRN_TEXT_PUTC(ctx, outbuf, '"');
 | 
						|
    } else {
 | 
						|
      GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  INCR_LENGTH;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_text_atoj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
              grn_obj *obj, grn_id id)
 | 
						|
{
 | 
						|
  uint32_t vs;
 | 
						|
  grn_obj buf;
 | 
						|
  if (obj->header.type == GRN_ACCESSOR) {
 | 
						|
    grn_accessor *a = (grn_accessor *)obj;
 | 
						|
    GRN_TEXT_INIT(&buf, 0);
 | 
						|
    for (;;) {
 | 
						|
      buf.header.domain = grn_obj_get_range(ctx, obj);
 | 
						|
      GRN_BULK_REWIND(&buf);
 | 
						|
      switch (a->action) {
 | 
						|
      case GRN_ACCESSOR_GET_ID :
 | 
						|
        GRN_UINT32_PUT(ctx, &buf, id);
 | 
						|
        buf.header.domain = GRN_DB_UINT32;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_KEY :
 | 
						|
        grn_table_get_key2(ctx, a->obj, id, &buf);
 | 
						|
        buf.header.domain = DB_OBJ(a->obj)->header.domain;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_VALUE :
 | 
						|
        grn_obj_get_value(ctx, a->obj, id, &buf);
 | 
						|
        buf.header.domain = DB_OBJ(a->obj)->range;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_SCORE :
 | 
						|
        {
 | 
						|
          grn_rset_recinfo *ri =
 | 
						|
            (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
 | 
						|
          if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
 | 
						|
            int32_t int32_score = ri->score;
 | 
						|
            GRN_INT32_PUT(ctx, &buf, int32_score);
 | 
						|
            buf.header.domain = GRN_DB_INT32;
 | 
						|
          } else {
 | 
						|
            double float_score = ri->score;
 | 
						|
            GRN_FLOAT_PUT(ctx, &buf, float_score);
 | 
						|
            buf.header.domain = GRN_DB_FLOAT;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_NSUBRECS :
 | 
						|
        {
 | 
						|
          grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
 | 
						|
          GRN_INT32_PUT(ctx, &buf, ri->n_subrecs);
 | 
						|
        }
 | 
						|
        buf.header.domain = GRN_DB_INT32;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_MAX :
 | 
						|
        {
 | 
						|
          grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
 | 
						|
          int64_t max;
 | 
						|
          max = grn_rset_recinfo_get_max(ctx, ri, a->obj);
 | 
						|
          GRN_INT64_PUT(ctx, &buf, max);
 | 
						|
        }
 | 
						|
        buf.header.domain = GRN_DB_INT64;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_MIN :
 | 
						|
        {
 | 
						|
          grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
 | 
						|
          int64_t min;
 | 
						|
          min = grn_rset_recinfo_get_min(ctx, ri, a->obj);
 | 
						|
          GRN_INT64_PUT(ctx, &buf, min);
 | 
						|
        }
 | 
						|
        buf.header.domain = GRN_DB_INT64;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_SUM :
 | 
						|
        {
 | 
						|
          grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
 | 
						|
          int64_t sum;
 | 
						|
          sum = grn_rset_recinfo_get_sum(ctx, ri, a->obj);
 | 
						|
          GRN_INT64_PUT(ctx, &buf, sum);
 | 
						|
        }
 | 
						|
        buf.header.domain = GRN_DB_INT64;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_AVG :
 | 
						|
        {
 | 
						|
          grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
 | 
						|
          double avg;
 | 
						|
          avg = grn_rset_recinfo_get_avg(ctx, ri, a->obj);
 | 
						|
          GRN_FLOAT_PUT(ctx, &buf, avg);
 | 
						|
        }
 | 
						|
        buf.header.domain = GRN_DB_FLOAT;
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_COLUMN_VALUE :
 | 
						|
        if ((a->obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
 | 
						|
          if (a->next) {
 | 
						|
            grn_id *idp;
 | 
						|
            grn_obj_get_value(ctx, a->obj, id, &buf);
 | 
						|
            idp = (grn_id *)GRN_BULK_HEAD(&buf);
 | 
						|
            vs = GRN_BULK_VSIZE(&buf) / sizeof(grn_id);
 | 
						|
            grn_output_array_open(ctx, outbuf, output_type, "VECTOR", vs);
 | 
						|
            for (; vs--; idp++) {
 | 
						|
              grn_text_atoj(ctx, outbuf, output_type, (grn_obj *)a->next, *idp);
 | 
						|
            }
 | 
						|
            grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
          } else {
 | 
						|
            grn_text_atoj(ctx, outbuf, output_type, a->obj, id);
 | 
						|
          }
 | 
						|
          goto exit;
 | 
						|
        } else {
 | 
						|
          grn_obj_get_value(ctx, a->obj, id, &buf);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_GET_DB_OBJ :
 | 
						|
        /* todo */
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_LOOKUP :
 | 
						|
        /* todo */
 | 
						|
        break;
 | 
						|
      case GRN_ACCESSOR_FUNCALL :
 | 
						|
        /* todo */
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      if (a->next) {
 | 
						|
        a = a->next;
 | 
						|
        if ((size_t) GRN_BULK_VSIZE(&buf) >= sizeof(grn_id)) {
 | 
						|
          id = *((grn_id *)GRN_BULK_HEAD(&buf));
 | 
						|
        } else {
 | 
						|
          id = GRN_ID_NIL;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
 | 
						|
  } else {
 | 
						|
    grn_obj_format *format_argument = NULL;
 | 
						|
    grn_obj_format format;
 | 
						|
    GRN_OBJ_FORMAT_INIT(&format, 0, 0, 0, 0);
 | 
						|
    switch (obj->header.type) {
 | 
						|
    case GRN_COLUMN_FIX_SIZE :
 | 
						|
      GRN_VALUE_FIX_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
 | 
						|
      break;
 | 
						|
    case GRN_COLUMN_VAR_SIZE :
 | 
						|
      if ((obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
 | 
						|
        grn_obj *range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
 | 
						|
        if (GRN_OBJ_TABLEP(range) ||
 | 
						|
            (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) == 0) {
 | 
						|
          GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
 | 
						|
        } else {
 | 
						|
          GRN_VALUE_VAR_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
 | 
						|
        }
 | 
						|
        if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
 | 
						|
          format.flags |= GRN_OBJ_FORMAT_WITH_WEIGHT;
 | 
						|
          format_argument = &format;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        GRN_VALUE_VAR_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    case GRN_COLUMN_INDEX :
 | 
						|
      GRN_UINT32_INIT(&buf, 0);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      GRN_TEXT_INIT(&buf, 0);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    grn_obj_get_value(ctx, obj, id, &buf);
 | 
						|
    grn_output_obj(ctx, outbuf, output_type, &buf, format_argument);
 | 
						|
  }
 | 
						|
exit :
 | 
						|
  grn_obj_close(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                grn_obj *bulk, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_output_null(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_bulk(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                grn_obj *bulk, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_obj buf;
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
  switch (bulk->header.domain) {
 | 
						|
  case GRN_DB_VOID :
 | 
						|
    grn_output_bulk_void(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
 | 
						|
    break;
 | 
						|
  case GRN_DB_SHORT_TEXT :
 | 
						|
  case GRN_DB_TEXT :
 | 
						|
  case GRN_DB_LONG_TEXT :
 | 
						|
    grn_output_str(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
 | 
						|
    break;
 | 
						|
  case GRN_DB_BOOL :
 | 
						|
    grn_output_bool(ctx, outbuf, output_type,
 | 
						|
                    GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_INT8 :
 | 
						|
    grn_output_int32(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_INT8_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_UINT8 :
 | 
						|
    grn_output_int32(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_INT16 :
 | 
						|
    grn_output_int32(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_INT16_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_UINT16 :
 | 
						|
    grn_output_int32(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_UINT16_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_INT32 :
 | 
						|
    grn_output_int32(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_INT32_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_UINT32 :
 | 
						|
    grn_output_int64(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_UINT32_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_INT64 :
 | 
						|
    grn_output_int64(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_UINT64 :
 | 
						|
    grn_output_uint64(ctx, outbuf, output_type,
 | 
						|
                      GRN_BULK_VSIZE(bulk) ? GRN_UINT64_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_FLOAT :
 | 
						|
    grn_output_float(ctx, outbuf, output_type,
 | 
						|
                     GRN_BULK_VSIZE(bulk) ? GRN_FLOAT_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_TIME :
 | 
						|
    grn_output_time(ctx, outbuf, output_type,
 | 
						|
                    GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
 | 
						|
    break;
 | 
						|
  case GRN_DB_TOKYO_GEO_POINT :
 | 
						|
  case GRN_DB_WGS84_GEO_POINT :
 | 
						|
    grn_output_geo_point(ctx, outbuf, output_type,
 | 
						|
                         GRN_BULK_VSIZE(bulk) ? (grn_geo_point *)GRN_BULK_HEAD(bulk) : NULL);
 | 
						|
    break;
 | 
						|
  default :
 | 
						|
    if (format) {
 | 
						|
      int j;
 | 
						|
      int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
 | 
						|
      grn_id id = GRN_RECORD_VALUE(bulk);
 | 
						|
      grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
 | 
						|
      if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
 | 
						|
        grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", ncolumns);
 | 
						|
        for (j = 0; j < ncolumns; j++) {
 | 
						|
          grn_id range_id;
 | 
						|
          grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
 | 
						|
          GRN_BULK_REWIND(&buf);
 | 
						|
          grn_column_name_(ctx, columns[j], &buf);
 | 
						|
          grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
 | 
						|
          /* column range */
 | 
						|
          range_id = grn_obj_get_range(ctx, columns[j]);
 | 
						|
          if (range_id == GRN_ID_NIL) {
 | 
						|
            GRN_TEXT_PUTS(ctx, outbuf, "null");
 | 
						|
          } else {
 | 
						|
            int name_len;
 | 
						|
            grn_obj *range_obj;
 | 
						|
            char name_buf[GRN_TABLE_MAX_KEY_SIZE];
 | 
						|
 | 
						|
            range_obj = grn_ctx_at(ctx, range_id);
 | 
						|
            name_len = grn_obj_name(ctx, range_obj, name_buf,
 | 
						|
                                    GRN_TABLE_MAX_KEY_SIZE);
 | 
						|
            GRN_BULK_REWIND(&buf);
 | 
						|
            GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
 | 
						|
            grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
 | 
						|
          }
 | 
						|
          grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
        }
 | 
						|
        grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
      }
 | 
						|
      grn_output_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
 | 
						|
      for (j = 0; j < ncolumns; j++) {
 | 
						|
        grn_text_atoj(ctx, outbuf, output_type, columns[j], id);
 | 
						|
      }
 | 
						|
      grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
    } else {
 | 
						|
      grn_obj *table = grn_ctx_at(ctx, bulk->header.domain);
 | 
						|
      grn_id id = GRN_RECORD_VALUE(bulk);
 | 
						|
      if (table && table->header.type != GRN_TABLE_NO_KEY) {
 | 
						|
        grn_obj *accessor = grn_obj_column(ctx, table,
 | 
						|
                                           GRN_COLUMN_NAME_KEY,
 | 
						|
                                           GRN_COLUMN_NAME_KEY_LEN);
 | 
						|
        if (accessor) {
 | 
						|
          if (id == GRN_ID_NIL) {
 | 
						|
            grn_obj_reinit_for(ctx, &buf, accessor);
 | 
						|
          } else {
 | 
						|
            grn_obj_get_value(ctx, accessor, id, &buf);
 | 
						|
          }
 | 
						|
          grn_obj_unlink(ctx, accessor);
 | 
						|
        }
 | 
						|
        grn_output_obj(ctx, outbuf, output_type, &buf, format);
 | 
						|
      } else {
 | 
						|
        grn_output_int64(ctx, outbuf, output_type, id);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_uvector_result_set(grn_ctx *ctx,
 | 
						|
                              grn_obj *outbuf,
 | 
						|
                              grn_content_type output_type,
 | 
						|
                              grn_obj *uvector,
 | 
						|
                              grn_obj_format *format)
 | 
						|
{
 | 
						|
  unsigned int i_hit, n_hits;
 | 
						|
  unsigned int i_column, n_columns;
 | 
						|
  unsigned int n_elements;
 | 
						|
  grn_obj **columns;
 | 
						|
  grn_obj buf;
 | 
						|
  grn_bool with_column_names = GRN_FALSE;
 | 
						|
 | 
						|
  n_hits = grn_vector_size(ctx, uvector);
 | 
						|
 | 
						|
  n_columns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
 | 
						|
  columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
 | 
						|
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
 | 
						|
  if (n_hits > 0 && format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
 | 
						|
    with_column_names = GRN_TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  n_elements = 1; /* for NHITS */
 | 
						|
  if (with_column_names) {
 | 
						|
    n_elements += 1; /* for COLUMNS */
 | 
						|
  }
 | 
						|
  n_elements += n_hits; /* for HITS */
 | 
						|
  grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", n_elements);
 | 
						|
 | 
						|
  grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
 | 
						|
  grn_text_itoa(ctx, outbuf, n_hits);
 | 
						|
  grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
 | 
						|
  if (with_column_names) {
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_columns);
 | 
						|
    for (i_column = 0; i_column < n_columns; i_column++) {
 | 
						|
      grn_id range_id;
 | 
						|
      grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
 | 
						|
 | 
						|
      /* name */
 | 
						|
      GRN_BULK_REWIND(&buf);
 | 
						|
      grn_column_name_(ctx, columns[i_column], &buf);
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
 | 
						|
 | 
						|
      /* type */
 | 
						|
      range_id = grn_obj_get_range(ctx, columns[i_column]);
 | 
						|
      if (range_id == GRN_ID_NIL) {
 | 
						|
        GRN_TEXT_PUTS(ctx, outbuf, "null");
 | 
						|
      } else {
 | 
						|
        int name_len;
 | 
						|
        grn_obj *range_obj;
 | 
						|
        char name_buf[GRN_TABLE_MAX_KEY_SIZE];
 | 
						|
 | 
						|
        range_obj = grn_ctx_at(ctx, range_id);
 | 
						|
        name_len = grn_obj_name(ctx, range_obj, name_buf,
 | 
						|
                                GRN_TABLE_MAX_KEY_SIZE);
 | 
						|
        GRN_BULK_REWIND(&buf);
 | 
						|
        GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
 | 
						|
        grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
 | 
						|
      }
 | 
						|
 | 
						|
      grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
    }
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
 | 
						|
  for (i_hit = 0; i_hit < n_hits++; i_hit++) {
 | 
						|
    grn_id id;
 | 
						|
 | 
						|
    id = grn_uvector_get_element(ctx, uvector, i_hit, NULL);
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "HITS", n_columns);
 | 
						|
    for (i_column = 0; i_column < n_columns; i_column++) {
 | 
						|
      GRN_BULK_REWIND(&buf);
 | 
						|
      grn_obj_get_value(ctx, columns[i_column], id, &buf);
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
 | 
						|
    }
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
 | 
						|
  grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_uvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                   grn_obj *uvector, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_bool output_result_set = GRN_FALSE;
 | 
						|
  grn_bool with_weight = GRN_FALSE;
 | 
						|
  grn_obj *range;
 | 
						|
  grn_bool range_is_type;
 | 
						|
 | 
						|
  if (format) {
 | 
						|
    if (GRN_BULK_VSIZE(&(format->columns)) > 0) {
 | 
						|
      output_result_set = GRN_TRUE;
 | 
						|
    }
 | 
						|
    if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
 | 
						|
      with_weight = GRN_TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (output_result_set) {
 | 
						|
    grn_output_uvector_result_set(ctx, outbuf, output_type, uvector, format);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  range = grn_ctx_at(ctx, uvector->header.domain);
 | 
						|
  range_is_type = (range->header.type == GRN_TYPE);
 | 
						|
  if (range_is_type) {
 | 
						|
    unsigned int i, n;
 | 
						|
    char *raw_elements;
 | 
						|
    unsigned int element_size;
 | 
						|
    grn_obj element;
 | 
						|
 | 
						|
    raw_elements = GRN_BULK_HEAD(uvector);
 | 
						|
    element_size = GRN_TYPE_SIZE(DB_OBJ(range));
 | 
						|
    n = GRN_BULK_VSIZE(uvector) / element_size;
 | 
						|
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
 | 
						|
    GRN_OBJ_INIT(&element, GRN_BULK, 0, uvector->header.domain);
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
      GRN_BULK_REWIND(&element);
 | 
						|
      grn_bulk_write_from(ctx, &element, raw_elements + (element_size * i),
 | 
						|
                          0, element_size);
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, &element, NULL);
 | 
						|
    }
 | 
						|
    GRN_OBJ_FIN(ctx, &element);
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  } else {
 | 
						|
    unsigned int i, n;
 | 
						|
    grn_obj id_value;
 | 
						|
    grn_obj key_value;
 | 
						|
 | 
						|
    GRN_UINT32_INIT(&id_value, 0);
 | 
						|
    GRN_OBJ_INIT(&key_value, GRN_BULK, 0, range->header.domain);
 | 
						|
 | 
						|
    n = grn_vector_size(ctx, uvector);
 | 
						|
    if (with_weight) {
 | 
						|
      grn_output_map_open(ctx, outbuf, output_type, "WEIGHT_VECTOR", n);
 | 
						|
    } else {
 | 
						|
      grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
 | 
						|
    }
 | 
						|
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
      grn_id id;
 | 
						|
      unsigned int weight;
 | 
						|
 | 
						|
      id = grn_uvector_get_element(ctx, uvector, i, &weight);
 | 
						|
      if (range->header.type == GRN_TABLE_NO_KEY) {
 | 
						|
        GRN_UINT32_SET(ctx, &id_value, id);
 | 
						|
        grn_output_obj(ctx, outbuf, output_type, &id_value, NULL);
 | 
						|
      } else {
 | 
						|
        GRN_BULK_REWIND(&key_value);
 | 
						|
        grn_table_get_key2(ctx, range, id, &key_value);
 | 
						|
        grn_output_obj(ctx, outbuf, output_type, &key_value, NULL);
 | 
						|
      }
 | 
						|
 | 
						|
      if (with_weight) {
 | 
						|
        grn_output_uint64(ctx, outbuf, output_type, weight);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (with_weight) {
 | 
						|
      grn_output_map_close(ctx, outbuf, output_type);
 | 
						|
    } else {
 | 
						|
      grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
    }
 | 
						|
 | 
						|
    GRN_OBJ_FIN(ctx, &id_value);
 | 
						|
    GRN_OBJ_FIN(ctx, &key_value);
 | 
						|
  }
 | 
						|
  grn_obj_unlink(ctx, range);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_vector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                  grn_obj *vector, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_bool with_weight = GRN_FALSE;
 | 
						|
 | 
						|
  if (vector->header.domain == GRN_DB_VOID) {
 | 
						|
    ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (format) {
 | 
						|
    if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
 | 
						|
      with_weight = GRN_TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (with_weight) {
 | 
						|
    unsigned int i, n;
 | 
						|
    grn_obj value;
 | 
						|
 | 
						|
    GRN_VOID_INIT(&value);
 | 
						|
    n = grn_vector_size(ctx, vector);
 | 
						|
    grn_output_map_open(ctx, outbuf, output_type, "WEIGHT_VECTOR", n);
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
      const char *_value;
 | 
						|
      unsigned int weight, length;
 | 
						|
      grn_id domain;
 | 
						|
 | 
						|
      length = grn_vector_get_element(ctx, vector, i,
 | 
						|
                                      &_value, &weight, &domain);
 | 
						|
      if (domain != GRN_DB_VOID) {
 | 
						|
        grn_obj_reinit(ctx, &value, domain, 0);
 | 
						|
      } else {
 | 
						|
        grn_obj_reinit(ctx, &value, vector->header.domain, 0);
 | 
						|
      }
 | 
						|
      grn_bulk_write(ctx, &value, _value, length);
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, &value, NULL);
 | 
						|
      grn_output_uint64(ctx, outbuf, output_type, weight);
 | 
						|
    }
 | 
						|
    grn_output_map_close(ctx, outbuf, output_type);
 | 
						|
    GRN_OBJ_FIN(ctx, &value);
 | 
						|
  } else {
 | 
						|
    unsigned int i, n;
 | 
						|
    grn_obj value;
 | 
						|
    GRN_VOID_INIT(&value);
 | 
						|
    n = grn_vector_size(ctx, vector);
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
      const char *_value;
 | 
						|
      unsigned int weight, length;
 | 
						|
      grn_id domain;
 | 
						|
 | 
						|
      length = grn_vector_get_element(ctx, vector, i,
 | 
						|
                                      &_value, &weight, &domain);
 | 
						|
      if (domain != GRN_DB_VOID) {
 | 
						|
        grn_obj_reinit(ctx, &value, domain, 0);
 | 
						|
      } else {
 | 
						|
        grn_obj_reinit(ctx, &value, vector->header.domain, 0);
 | 
						|
      }
 | 
						|
      grn_bulk_write(ctx, &value, _value, length);
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, &value, NULL);
 | 
						|
    }
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
    GRN_OBJ_FIN(ctx, &value);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_pvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
                   grn_obj *pvector, grn_obj_format *format)
 | 
						|
{
 | 
						|
  if (format) {
 | 
						|
    ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
 | 
						|
        "cannot print GRN_PVECTOR using grn_obj_format");
 | 
						|
  } else {
 | 
						|
    unsigned int i, n;
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
 | 
						|
    n = GRN_BULK_VSIZE(pvector) / sizeof(grn_obj *);
 | 
						|
    for (i = 0; i < n; i++) {
 | 
						|
      grn_obj *value;
 | 
						|
 | 
						|
      value = GRN_PTR_VALUE_AT(pvector, i);
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, value, NULL);
 | 
						|
    }
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_result_set_n_hits_v1(grn_ctx *ctx,
 | 
						|
                                grn_obj *outbuf,
 | 
						|
                                grn_content_type output_type,
 | 
						|
                                grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
 | 
						|
  if (output_type == GRN_CONTENT_XML) {
 | 
						|
    grn_text_itoa(ctx, outbuf, format->nhits);
 | 
						|
  } else {
 | 
						|
    grn_output_int32(ctx, outbuf, output_type, format->nhits);
 | 
						|
  }
 | 
						|
  grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_result_set_n_hits_v3(grn_ctx *ctx,
 | 
						|
                                grn_obj *outbuf,
 | 
						|
                                grn_content_type output_type,
 | 
						|
                                grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_output_cstr(ctx, outbuf, output_type, "n_hits");
 | 
						|
  grn_output_int32(ctx, outbuf, output_type, format->nhits);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_result_set_n_hits(grn_ctx *ctx,
 | 
						|
                             grn_obj *outbuf,
 | 
						|
                             grn_content_type output_type,
 | 
						|
                             grn_obj_format *format)
 | 
						|
{
 | 
						|
  if (format->nhits == -1) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_result_set_n_hits_v1(ctx, outbuf, output_type, format);
 | 
						|
  } else {
 | 
						|
    grn_output_result_set_n_hits_v3(ctx, outbuf, output_type, format);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_column_info(grn_ctx *ctx,
 | 
						|
                             grn_obj *outbuf,
 | 
						|
                             grn_content_type output_type,
 | 
						|
                             const char *name,
 | 
						|
                             const char *type)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
 | 
						|
    if (name) {
 | 
						|
      grn_output_cstr(ctx, outbuf, output_type, name);
 | 
						|
    } else {
 | 
						|
      grn_output_null(ctx, outbuf, output_type);
 | 
						|
    }
 | 
						|
    if (type) {
 | 
						|
      grn_output_cstr(ctx, outbuf, output_type, type);
 | 
						|
    } else {
 | 
						|
      grn_output_null(ctx, outbuf, output_type);
 | 
						|
    }
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  } else {
 | 
						|
    grn_output_map_open(ctx, outbuf, output_type, "column", 2);
 | 
						|
    grn_output_cstr(ctx, outbuf, output_type, "name");
 | 
						|
    if (name) {
 | 
						|
      grn_output_cstr(ctx, outbuf, output_type, name);
 | 
						|
    } else {
 | 
						|
      grn_output_null(ctx, outbuf, output_type);
 | 
						|
    }
 | 
						|
    grn_output_cstr(ctx, outbuf, output_type, "type");
 | 
						|
    if (type) {
 | 
						|
      grn_output_cstr(ctx, outbuf, output_type, type);
 | 
						|
    } else {
 | 
						|
      grn_output_null(ctx, outbuf, output_type);
 | 
						|
    }
 | 
						|
    grn_output_map_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline int
 | 
						|
count_n_elements_in_expression(grn_ctx *ctx, grn_obj *expression)
 | 
						|
{
 | 
						|
  int n_elements = 0;
 | 
						|
  grn_bool is_first_comma = GRN_TRUE;
 | 
						|
  grn_expr *expr = (grn_expr *)expression;
 | 
						|
  grn_expr_code *code;
 | 
						|
  grn_expr_code *code_end = expr->codes + expr->codes_curr;
 | 
						|
 | 
						|
  for (code = expr->codes; code < code_end; code++) {
 | 
						|
    if (code->op == GRN_OP_COMMA) {
 | 
						|
      n_elements++;
 | 
						|
      if (is_first_comma) {
 | 
						|
        n_elements++;
 | 
						|
        is_first_comma = GRN_FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return n_elements;
 | 
						|
}
 | 
						|
 | 
						|
static grn_bool
 | 
						|
is_score_accessor(grn_ctx *ctx, grn_obj *obj)
 | 
						|
{
 | 
						|
  grn_accessor *a;
 | 
						|
 | 
						|
  if (obj->header.type != GRN_ACCESSOR) {
 | 
						|
    return GRN_FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  for (a = (grn_accessor *)obj; a->next; a = a->next) {
 | 
						|
  }
 | 
						|
  return a->action == GRN_ACCESSOR_GET_SCORE;
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_column(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                        grn_content_type output_type,
 | 
						|
                        grn_obj *column, grn_obj *buf)
 | 
						|
{
 | 
						|
  grn_id range_id = GRN_ID_NIL;
 | 
						|
 | 
						|
  if (!column) {
 | 
						|
    grn_output_table_column_info(ctx, outbuf, output_type, NULL, NULL);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  GRN_BULK_REWIND(buf);
 | 
						|
  grn_column_name_(ctx, column, buf);
 | 
						|
  GRN_TEXT_PUTC(ctx, buf, '\0');
 | 
						|
 | 
						|
  if (column->header.type == GRN_COLUMN_INDEX) {
 | 
						|
    range_id = GRN_DB_UINT32;
 | 
						|
  } else if (is_score_accessor(ctx, column)) {
 | 
						|
    if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
 | 
						|
      range_id = GRN_DB_INT32;
 | 
						|
    } else {
 | 
						|
      range_id = GRN_DB_FLOAT;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (range_id == GRN_ID_NIL) {
 | 
						|
    range_id = grn_obj_get_range(ctx, column);
 | 
						|
  }
 | 
						|
  if (range_id == GRN_ID_NIL) {
 | 
						|
    grn_output_table_column_info(ctx,
 | 
						|
                                 outbuf,
 | 
						|
                                 output_type,
 | 
						|
                                 GRN_TEXT_VALUE(buf),
 | 
						|
                                 NULL);
 | 
						|
  } else {
 | 
						|
    grn_obj *range_obj;
 | 
						|
    char type_name[GRN_TABLE_MAX_KEY_SIZE];
 | 
						|
    int type_name_len;
 | 
						|
 | 
						|
    range_obj = grn_ctx_at(ctx, range_id);
 | 
						|
    type_name_len = grn_obj_name(ctx,
 | 
						|
                                 range_obj,
 | 
						|
                                 type_name,
 | 
						|
                                 GRN_TABLE_MAX_KEY_SIZE);
 | 
						|
    type_name[type_name_len] = '\0';
 | 
						|
    grn_output_table_column_info(ctx,
 | 
						|
                                 outbuf,
 | 
						|
                                 output_type,
 | 
						|
                                 GRN_TEXT_VALUE(buf),
 | 
						|
                                 type_name);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_column_by_expression(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                                      grn_content_type output_type,
 | 
						|
                                      grn_expr_code *code,
 | 
						|
                                      grn_expr_code *code_end,
 | 
						|
                                      grn_obj *buf)
 | 
						|
{
 | 
						|
  if (code_end <= code) {
 | 
						|
    grn_output_table_column_info(ctx,
 | 
						|
                                 outbuf,
 | 
						|
                                 output_type,
 | 
						|
                                 NULL,
 | 
						|
                                 NULL);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (code_end[-1].op) {
 | 
						|
  case GRN_OP_GET_MEMBER :
 | 
						|
    if ((code_end - code) == 3) {
 | 
						|
      GRN_BULK_REWIND(buf);
 | 
						|
      grn_column_name_(ctx, code[0].value, buf);
 | 
						|
      GRN_TEXT_PUTC(ctx, buf, '[');
 | 
						|
      grn_inspect(ctx, buf, code[1].value);
 | 
						|
      GRN_TEXT_PUTC(ctx, buf, ']');
 | 
						|
      GRN_TEXT_PUTC(ctx, buf, '\0');
 | 
						|
 | 
						|
      grn_output_table_column_info(ctx,
 | 
						|
                                   outbuf,
 | 
						|
                                   output_type,
 | 
						|
                                   GRN_TEXT_VALUE(buf),
 | 
						|
                                   NULL);
 | 
						|
    } else {
 | 
						|
      grn_output_table_column(ctx, outbuf, output_type, code->value, buf);
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  default :
 | 
						|
    grn_output_table_column(ctx, outbuf, output_type, code->value, buf);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_columns_open(grn_ctx *ctx,
 | 
						|
                              grn_obj *outbuf,
 | 
						|
                              grn_content_type output_type,
 | 
						|
                              int n_columns)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_columns);
 | 
						|
  } else {
 | 
						|
    grn_output_cstr(ctx, outbuf, output_type, "columns");
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "columns", n_columns);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_columns_close(grn_ctx *ctx,
 | 
						|
                               grn_obj *outbuf,
 | 
						|
                               grn_content_type output_type)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  } else {
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_columns_by_expression(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                                       grn_content_type output_type,
 | 
						|
                                       grn_obj *table, grn_obj_format *format,
 | 
						|
                                       grn_obj *buf)
 | 
						|
{
 | 
						|
  int n_elements;
 | 
						|
  int previous_comma_offset = -1;
 | 
						|
  grn_bool is_first_comma = GRN_TRUE;
 | 
						|
  grn_bool have_comma = GRN_FALSE;
 | 
						|
  grn_expr *expr = (grn_expr *)format->expression;
 | 
						|
  grn_expr_code *code;
 | 
						|
  grn_expr_code *code_end = expr->codes + expr->codes_curr;
 | 
						|
 | 
						|
  n_elements = count_n_elements_in_expression(ctx, format->expression);
 | 
						|
 | 
						|
  grn_output_table_columns_open(ctx, outbuf, output_type, n_elements);
 | 
						|
 | 
						|
  for (code = expr->codes; code < code_end; code++) {
 | 
						|
    int code_start_offset;
 | 
						|
 | 
						|
    if (code->op != GRN_OP_COMMA) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    have_comma = GRN_TRUE;
 | 
						|
    if (is_first_comma) {
 | 
						|
      unsigned int n_used_codes;
 | 
						|
      int code_end_offset;
 | 
						|
 | 
						|
      n_used_codes = grn_expr_code_n_used_codes(ctx, expr->codes, code - 1);
 | 
						|
      code_end_offset = code - expr->codes - n_used_codes;
 | 
						|
 | 
						|
      grn_output_table_column_by_expression(ctx, outbuf, output_type,
 | 
						|
                                            expr->codes,
 | 
						|
                                            expr->codes + code_end_offset,
 | 
						|
                                            buf);
 | 
						|
      code_start_offset = code_end_offset;
 | 
						|
      is_first_comma = GRN_FALSE;
 | 
						|
    } else {
 | 
						|
      code_start_offset = previous_comma_offset + 1;
 | 
						|
    }
 | 
						|
 | 
						|
    grn_output_table_column_by_expression(ctx, outbuf, output_type,
 | 
						|
                                          expr->codes + code_start_offset,
 | 
						|
                                          code,
 | 
						|
                                          buf);
 | 
						|
    previous_comma_offset = code - expr->codes;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!have_comma && expr->codes_curr > 0) {
 | 
						|
    grn_output_table_column_by_expression(ctx, outbuf, output_type,
 | 
						|
                                          expr->codes,
 | 
						|
                                          code_end,
 | 
						|
                                          buf);
 | 
						|
  }
 | 
						|
 | 
						|
  grn_output_table_columns_close(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_columns_by_columns(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                                    grn_content_type output_type,
 | 
						|
                                    grn_obj *table, grn_obj_format *format,
 | 
						|
                                    grn_obj *buf)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
 | 
						|
  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
 | 
						|
 | 
						|
  grn_output_table_columns_open(ctx, outbuf, output_type, ncolumns);
 | 
						|
  for (i = 0; i < ncolumns; i++) {
 | 
						|
    grn_output_table_column(ctx, outbuf, output_type, columns[i], buf);
 | 
						|
  }
 | 
						|
  grn_output_table_columns_close(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_table_columns(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                         grn_content_type output_type,
 | 
						|
                         grn_obj *table, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_obj buf;
 | 
						|
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
  if (format->expression) {
 | 
						|
    grn_output_table_columns_by_expression(ctx, outbuf, output_type,
 | 
						|
                                           table, format, &buf);
 | 
						|
  } else {
 | 
						|
    grn_output_table_columns_by_columns(ctx, outbuf, output_type,
 | 
						|
                                        table, format, &buf);
 | 
						|
  }
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_record_open(grn_ctx *ctx,
 | 
						|
                              grn_obj *outbuf,
 | 
						|
                              grn_content_type output_type,
 | 
						|
                              int n_columns)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "HIT", n_columns);
 | 
						|
  } else {
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "record", n_columns);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_record_close(grn_ctx *ctx,
 | 
						|
                               grn_obj *outbuf,
 | 
						|
                               grn_content_type output_type)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  } else {
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_record_by_column(grn_ctx *ctx,
 | 
						|
                                  grn_obj *outbuf,
 | 
						|
                                  grn_content_type output_type,
 | 
						|
                                  grn_obj *column,
 | 
						|
                                  grn_id id)
 | 
						|
{
 | 
						|
  grn_text_atoj(ctx, outbuf, output_type, column, id);
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_record_by_expression(grn_ctx *ctx,
 | 
						|
                                      grn_obj *outbuf,
 | 
						|
                                      grn_content_type output_type,
 | 
						|
                                      grn_obj *expression,
 | 
						|
                                      grn_obj *record)
 | 
						|
{
 | 
						|
  grn_expr *expr = (grn_expr *)expression;
 | 
						|
 | 
						|
  if (expr->codes_curr == 1 && expr->codes[0].op == GRN_OP_GET_VALUE) {
 | 
						|
    grn_obj *column = expr->codes[0].value;
 | 
						|
    grn_output_table_record_by_column(ctx,
 | 
						|
                                      outbuf,
 | 
						|
                                      output_type,
 | 
						|
                                      column,
 | 
						|
                                      GRN_RECORD_VALUE(record));
 | 
						|
  } else {
 | 
						|
    grn_obj *result;
 | 
						|
    result = grn_expr_exec(ctx, expression, 0);
 | 
						|
    if (result) {
 | 
						|
      grn_output_obj(ctx, outbuf, output_type, result, NULL);
 | 
						|
    } else {
 | 
						|
      grn_output_cstr(ctx, outbuf, output_type, ctx->errbuf);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_records_by_expression(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                                       grn_content_type output_type,
 | 
						|
                                       grn_table_cursor *tc,
 | 
						|
                                       grn_obj_format *format)
 | 
						|
{
 | 
						|
  int n_elements = 0;
 | 
						|
  grn_id id;
 | 
						|
  grn_obj *record;
 | 
						|
  grn_expr *expr = (grn_expr *)format->expression;
 | 
						|
  grn_expr_code *code;
 | 
						|
  grn_expr_code *code_end = expr->codes + expr->codes_curr;
 | 
						|
 | 
						|
  n_elements = count_n_elements_in_expression(ctx, format->expression);
 | 
						|
  record = grn_expr_get_var_by_offset(ctx, format->expression, 0);
 | 
						|
  while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
 | 
						|
    int previous_comma_offset = -1;
 | 
						|
    grn_bool is_first_comma = GRN_TRUE;
 | 
						|
    grn_bool have_comma = GRN_FALSE;
 | 
						|
    GRN_RECORD_SET(ctx, record, id);
 | 
						|
    grn_output_table_record_open(ctx, outbuf, output_type, n_elements);
 | 
						|
    for (code = expr->codes; code < code_end; code++) {
 | 
						|
      if (code->op == GRN_OP_COMMA) {
 | 
						|
        int code_start_offset = previous_comma_offset + 1;
 | 
						|
        int code_end_offset;
 | 
						|
        int original_codes_curr = expr->codes_curr;
 | 
						|
 | 
						|
        have_comma = GRN_TRUE;
 | 
						|
        if (is_first_comma) {
 | 
						|
          int second_code_offset;
 | 
						|
          unsigned int second_code_n_used_codes;
 | 
						|
          second_code_offset = code - expr->codes - 1;
 | 
						|
          second_code_n_used_codes =
 | 
						|
            grn_expr_code_n_used_codes(ctx,
 | 
						|
                                       expr->codes,
 | 
						|
                                       expr->codes + second_code_offset);
 | 
						|
          expr->codes_curr = second_code_offset - second_code_n_used_codes + 1;
 | 
						|
          grn_output_table_record_by_expression(ctx,
 | 
						|
                                                outbuf,
 | 
						|
                                                output_type,
 | 
						|
                                                format->expression,
 | 
						|
                                                record);
 | 
						|
          code_start_offset = expr->codes_curr;
 | 
						|
          is_first_comma = GRN_FALSE;
 | 
						|
        }
 | 
						|
        code_end_offset = code - expr->codes - code_start_offset;
 | 
						|
        expr->codes += code_start_offset;
 | 
						|
        expr->codes_curr = code_end_offset;
 | 
						|
        grn_output_table_record_by_expression(ctx,
 | 
						|
                                              outbuf,
 | 
						|
                                              output_type,
 | 
						|
                                              format->expression,
 | 
						|
                                              record);
 | 
						|
        expr->codes -= code_start_offset;
 | 
						|
        expr->codes_curr = original_codes_curr;
 | 
						|
        previous_comma_offset = code - expr->codes;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!have_comma && expr->codes_curr > 0) {
 | 
						|
      grn_output_table_record_by_expression(ctx,
 | 
						|
                                            outbuf,
 | 
						|
                                            output_type,
 | 
						|
                                            format->expression,
 | 
						|
                                            record);
 | 
						|
    }
 | 
						|
 | 
						|
    grn_output_table_record_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_records_by_columns(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                                    grn_content_type output_type,
 | 
						|
                                    grn_table_cursor *tc,
 | 
						|
                                    grn_obj_format *format)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  grn_id id;
 | 
						|
  int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
 | 
						|
  grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
 | 
						|
  while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
 | 
						|
    grn_output_table_record_open(ctx, outbuf, output_type, ncolumns);
 | 
						|
    for (i = 0; i < ncolumns; i++) {
 | 
						|
      grn_output_table_record_by_column(ctx,
 | 
						|
                                        outbuf,
 | 
						|
                                        output_type,
 | 
						|
                                        columns[i],
 | 
						|
                                        id);
 | 
						|
    }
 | 
						|
    grn_output_table_record_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_records_open(grn_ctx *ctx,
 | 
						|
                              grn_obj *outbuf,
 | 
						|
                              grn_content_type output_type,
 | 
						|
                              int n_records)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_cstr(ctx, outbuf, output_type, "records");
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "records", n_records);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline void
 | 
						|
grn_output_table_records_close(grn_ctx *ctx,
 | 
						|
                               grn_obj *outbuf,
 | 
						|
                               grn_content_type output_type)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_table_records(grn_ctx *ctx, grn_obj *outbuf,
 | 
						|
                         grn_content_type output_type,
 | 
						|
                         grn_obj *table, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_table_cursor *tc;
 | 
						|
 | 
						|
  grn_output_table_records_open(ctx, outbuf, output_type, format->limit);
 | 
						|
  tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
 | 
						|
                             format->offset, format->limit,
 | 
						|
                             GRN_CURSOR_ASCENDING);
 | 
						|
  if (tc) {
 | 
						|
    if (format->expression) {
 | 
						|
      grn_output_table_records_by_expression(ctx, outbuf, output_type,
 | 
						|
                                             tc, format);
 | 
						|
    } else {
 | 
						|
      grn_output_table_records_by_columns(ctx, outbuf, output_type,
 | 
						|
                                          tc, format);
 | 
						|
    }
 | 
						|
    grn_table_cursor_close(ctx, tc);
 | 
						|
  } else {
 | 
						|
    ERRCLR(ctx);
 | 
						|
  }
 | 
						|
  grn_output_table_records_close(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_result_set_open_v1(grn_ctx *ctx,
 | 
						|
                              grn_obj *outbuf,
 | 
						|
                              grn_content_type output_type,
 | 
						|
                              grn_obj *table,
 | 
						|
                              grn_obj_format *format,
 | 
						|
                              uint32_t n_additional_elements)
 | 
						|
{
 | 
						|
  grn_obj buf;
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
  if (format) {
 | 
						|
    int resultset_size = 1;
 | 
						|
    /* resultset: [NHITS, (COLUMNS), (HITS)] */
 | 
						|
    if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
 | 
						|
      resultset_size++;
 | 
						|
    }
 | 
						|
    resultset_size += format->limit;
 | 
						|
    resultset_size += n_additional_elements;
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", resultset_size);
 | 
						|
    grn_output_result_set_n_hits(ctx, outbuf, output_type, format);
 | 
						|
    if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
 | 
						|
      grn_output_table_columns(ctx, outbuf, output_type, table, format);
 | 
						|
    }
 | 
						|
    grn_output_table_records(ctx, outbuf, output_type, table, format);
 | 
						|
  } else {
 | 
						|
    int i;
 | 
						|
    grn_obj *column = grn_obj_column(ctx, table,
 | 
						|
                                     GRN_COLUMN_NAME_KEY,
 | 
						|
                                     GRN_COLUMN_NAME_KEY_LEN);
 | 
						|
    grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
 | 
						|
                                                 0, -1, GRN_CURSOR_ASCENDING);
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "HIT", -1);
 | 
						|
    if (tc) {
 | 
						|
      grn_id id;
 | 
						|
      for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
 | 
						|
        GRN_BULK_REWIND(&buf);
 | 
						|
        grn_obj_get_value(ctx, column, id, &buf);
 | 
						|
        grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
 | 
						|
      }
 | 
						|
      grn_table_cursor_close(ctx, tc);
 | 
						|
    }
 | 
						|
    grn_obj_unlink(ctx, column);
 | 
						|
  }
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_result_set_close_v1(grn_ctx *ctx,
 | 
						|
                               grn_obj *outbuf,
 | 
						|
                               grn_content_type output_type,
 | 
						|
                               grn_obj *table,
 | 
						|
                               grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_result_set_open_v3(grn_ctx *ctx,
 | 
						|
                              grn_obj *outbuf,
 | 
						|
                              grn_content_type output_type,
 | 
						|
                              grn_obj *result_set,
 | 
						|
                              grn_obj_format *format,
 | 
						|
                              uint32_t n_additional_elements)
 | 
						|
{
 | 
						|
  grn_obj buf;
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
  if (format) {
 | 
						|
    int n_elements = 2;
 | 
						|
    /* result_set: {"n_hits": N, ("columns": COLUMNS,) "records": records} */
 | 
						|
    if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
 | 
						|
      n_elements++;
 | 
						|
    }
 | 
						|
    n_elements += n_additional_elements;
 | 
						|
    grn_output_map_open(ctx, outbuf, output_type, "result_set", n_elements);
 | 
						|
    grn_output_result_set_n_hits(ctx, outbuf, output_type, format);
 | 
						|
    if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
 | 
						|
      grn_output_table_columns(ctx, outbuf, output_type, result_set, format);
 | 
						|
    }
 | 
						|
    grn_output_table_records(ctx, outbuf, output_type, result_set, format);
 | 
						|
  } else {
 | 
						|
    grn_obj *column;
 | 
						|
    int n_records;
 | 
						|
    int n_elements = 1;
 | 
						|
 | 
						|
    column = grn_obj_column(ctx,
 | 
						|
                            result_set,
 | 
						|
                            GRN_COLUMN_NAME_KEY,
 | 
						|
                            GRN_COLUMN_NAME_KEY_LEN);
 | 
						|
    n_elements += n_additional_elements;
 | 
						|
    grn_output_map_open(ctx, outbuf, output_type, "result_set", n_elements);
 | 
						|
    n_records = grn_table_size(ctx, result_set);
 | 
						|
    grn_output_cstr(ctx, outbuf, output_type, "keys");
 | 
						|
    grn_output_array_open(ctx, outbuf, output_type, "keys", n_records);
 | 
						|
    GRN_TABLE_EACH_BEGIN(ctx, result_set, cursor, id) {
 | 
						|
      GRN_BULK_REWIND(&buf);
 | 
						|
      grn_obj_get_value(ctx, column, id, &buf);
 | 
						|
      grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
 | 
						|
    } GRN_TABLE_EACH_END(ctx, cursor);
 | 
						|
    grn_output_array_close(ctx, outbuf, output_type);
 | 
						|
    grn_obj_unlink(ctx, column);
 | 
						|
  }
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_result_set_close_v3(grn_ctx *ctx,
 | 
						|
                               grn_obj *outbuf,
 | 
						|
                               grn_content_type output_type,
 | 
						|
                               grn_obj *result_set,
 | 
						|
                               grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_output_map_close(ctx, outbuf, output_type);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_result_set_open(grn_ctx *ctx,
 | 
						|
                           grn_obj *outbuf,
 | 
						|
                           grn_content_type output_type,
 | 
						|
                           grn_obj *result_set,
 | 
						|
                           grn_obj_format *format,
 | 
						|
                           uint32_t n_additional_elements)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_result_set_open_v1(ctx,
 | 
						|
                                  outbuf,
 | 
						|
                                  output_type,
 | 
						|
                                  result_set,
 | 
						|
                                  format,
 | 
						|
                                  n_additional_elements);
 | 
						|
  } else {
 | 
						|
    grn_output_result_set_open_v3(ctx,
 | 
						|
                                  outbuf,
 | 
						|
                                  output_type,
 | 
						|
                                  result_set,
 | 
						|
                                  format,
 | 
						|
                                  n_additional_elements);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_result_set_close(grn_ctx *ctx,
 | 
						|
                            grn_obj *outbuf,
 | 
						|
                            grn_content_type output_type,
 | 
						|
                            grn_obj *result_set,
 | 
						|
                            grn_obj_format *format)
 | 
						|
{
 | 
						|
  if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
 | 
						|
    grn_output_result_set_close_v1(ctx, outbuf, output_type, result_set, format);
 | 
						|
  } else {
 | 
						|
    grn_output_result_set_close_v3(ctx, outbuf, output_type, result_set, format);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_result_set(grn_ctx *ctx,
 | 
						|
                      grn_obj *outbuf,
 | 
						|
                      grn_content_type output_type,
 | 
						|
                      grn_obj *result_set,
 | 
						|
                      grn_obj_format *format)
 | 
						|
{
 | 
						|
  uint32_t n_additional_elements = 0;
 | 
						|
 | 
						|
  grn_output_result_set_open(ctx,
 | 
						|
                             outbuf,
 | 
						|
                             output_type,
 | 
						|
                             result_set,
 | 
						|
                             format,
 | 
						|
                             n_additional_elements);
 | 
						|
  grn_output_result_set_close(ctx, outbuf, output_type, result_set, format);
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
grn_output_obj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
 | 
						|
               grn_obj *obj, grn_obj_format *format)
 | 
						|
{
 | 
						|
  grn_obj buf;
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
  switch (obj->header.type) {
 | 
						|
  case GRN_VOID :
 | 
						|
    grn_output_void(ctx, outbuf, output_type, obj, format);
 | 
						|
    break;
 | 
						|
  case GRN_BULK :
 | 
						|
    grn_output_bulk(ctx, outbuf, output_type, obj, format);
 | 
						|
    break;
 | 
						|
  case GRN_UVECTOR :
 | 
						|
    grn_output_uvector(ctx, outbuf, output_type, obj, format);
 | 
						|
    break;
 | 
						|
  case GRN_VECTOR :
 | 
						|
    grn_output_vector(ctx, outbuf, output_type, obj, format);
 | 
						|
    break;
 | 
						|
  case GRN_PVECTOR :
 | 
						|
    grn_output_pvector(ctx, outbuf, output_type, obj, format);
 | 
						|
    break;
 | 
						|
  case GRN_TABLE_HASH_KEY :
 | 
						|
  case GRN_TABLE_PAT_KEY :
 | 
						|
  case GRN_TABLE_DAT_KEY :
 | 
						|
  case GRN_TABLE_NO_KEY :
 | 
						|
    /* Deprecated. Use grn_output_result_set() directly. */
 | 
						|
    grn_output_result_set(ctx, outbuf, output_type, obj, format);
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
}
 | 
						|
 | 
						|
typedef enum {
 | 
						|
  XML_START,
 | 
						|
  XML_START_ELEMENT,
 | 
						|
  XML_END_ELEMENT,
 | 
						|
  XML_TEXT
 | 
						|
} xml_status;
 | 
						|
 | 
						|
typedef enum {
 | 
						|
  XML_PLACE_NONE,
 | 
						|
  XML_PLACE_COLUMN,
 | 
						|
  XML_PLACE_HIT
 | 
						|
} xml_place;
 | 
						|
 | 
						|
static char *
 | 
						|
transform_xml_next_column(grn_obj *columns, int n)
 | 
						|
{
 | 
						|
  char *column = GRN_TEXT_VALUE(columns);
 | 
						|
  while (n--) {
 | 
						|
    while (*column) {
 | 
						|
      column++;
 | 
						|
    }
 | 
						|
    column++;
 | 
						|
  }
 | 
						|
  return column;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
transform_xml(grn_ctx *ctx, grn_obj *output, grn_obj *transformed)
 | 
						|
{
 | 
						|
  char *s, *e;
 | 
						|
  xml_status status = XML_START;
 | 
						|
  xml_place place = XML_PLACE_NONE;
 | 
						|
  grn_obj buf, name, columns, *expr;
 | 
						|
  unsigned int len;
 | 
						|
  int offset = 0, limit = 0, record_n = 0;
 | 
						|
  int column_n = 0, column_text_n = 0, result_set_n = -1;
 | 
						|
  grn_bool in_vector = GRN_FALSE;
 | 
						|
  unsigned int vector_element_n = 0;
 | 
						|
  grn_bool in_weight_vector = GRN_FALSE;
 | 
						|
  unsigned int weight_vector_item_n = 0;
 | 
						|
 | 
						|
  s = GRN_TEXT_VALUE(output);
 | 
						|
  e = GRN_BULK_CURR(output);
 | 
						|
  GRN_TEXT_INIT(&buf, 0);
 | 
						|
  GRN_TEXT_INIT(&name, 0);
 | 
						|
  GRN_TEXT_INIT(&columns, 0);
 | 
						|
 | 
						|
  expr = ctx->impl->curr_expr;
 | 
						|
 | 
						|
#define EQUAL_NAME_P(_name) \
 | 
						|
  (GRN_TEXT_LEN(&name) == strlen(_name) && \
 | 
						|
   !memcmp(GRN_TEXT_VALUE(&name), _name, strlen(_name)))
 | 
						|
 | 
						|
  while (s < e) {
 | 
						|
    switch (*s) {
 | 
						|
    case '<' :
 | 
						|
      s++;
 | 
						|
      switch (*s) {
 | 
						|
      case '/' :
 | 
						|
        status = XML_END_ELEMENT;
 | 
						|
        s++;
 | 
						|
        break;
 | 
						|
      default :
 | 
						|
        status = XML_START_ELEMENT;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      GRN_BULK_REWIND(&name);
 | 
						|
      break;
 | 
						|
    case '>' :
 | 
						|
      switch (status) {
 | 
						|
      case XML_START_ELEMENT :
 | 
						|
        if (EQUAL_NAME_P("COLUMN")) {
 | 
						|
          place = XML_PLACE_COLUMN;
 | 
						|
          column_text_n = 0;
 | 
						|
        } else if (EQUAL_NAME_P("HIT")) {
 | 
						|
          place = XML_PLACE_HIT;
 | 
						|
          column_n = 0;
 | 
						|
          if (result_set_n == 0) {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "<HIT NO=\"");
 | 
						|
            grn_text_itoa(ctx, transformed, record_n++);
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "\">\n");
 | 
						|
          } else {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONELEMENT ");
 | 
						|
          }
 | 
						|
        } else if (EQUAL_NAME_P("RESULTSET")) {
 | 
						|
          GRN_BULK_REWIND(&columns);
 | 
						|
          result_set_n++;
 | 
						|
          if (result_set_n == 0) {
 | 
						|
          } else {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONENTRY>\n");
 | 
						|
          }
 | 
						|
        } else if (EQUAL_NAME_P("VECTOR")) {
 | 
						|
          char *c = transform_xml_next_column(&columns, column_n++);
 | 
						|
          in_vector = GRN_TRUE;
 | 
						|
          vector_element_n = 0;
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, c);
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, "\">");
 | 
						|
        } else if (EQUAL_NAME_P("WEIGHT_VECTOR")) {
 | 
						|
          char *c = transform_xml_next_column(&columns, column_n++);
 | 
						|
          in_weight_vector = GRN_TRUE;
 | 
						|
          weight_vector_item_n = 0;
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, c);
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, "\">");
 | 
						|
        }
 | 
						|
        break;
 | 
						|
      case XML_END_ELEMENT :
 | 
						|
        if (EQUAL_NAME_P("HIT")) {
 | 
						|
          place = XML_PLACE_NONE;
 | 
						|
          if (result_set_n == 0) {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "</HIT>\n");
 | 
						|
          } else {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "/>\n");
 | 
						|
          }
 | 
						|
        } else if (EQUAL_NAME_P("RESULTSET")) {
 | 
						|
          place = XML_PLACE_NONE;
 | 
						|
          if (result_set_n == 0) {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed, "</RESULTSET>\n");
 | 
						|
          } else {
 | 
						|
            GRN_TEXT_PUTS(ctx, transformed,
 | 
						|
                          "</NAVIGATIONELEMENTS>\n"
 | 
						|
                          "</NAVIGATIONENTRY>\n");
 | 
						|
          }
 | 
						|
        } else if (EQUAL_NAME_P("RESULT")) {
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed,
 | 
						|
                        "</RESULTPAGE>\n"
 | 
						|
                        "</SEGMENT>\n"
 | 
						|
                        "</SEGMENTS>\n");
 | 
						|
        } else if (EQUAL_NAME_P("VECTOR")) {
 | 
						|
          in_vector = GRN_FALSE;
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
 | 
						|
        } else if (EQUAL_NAME_P("WEIGHT_VECTOR")) {
 | 
						|
          in_weight_vector = GRN_FALSE;
 | 
						|
          GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
 | 
						|
        } else {
 | 
						|
          switch (place) {
 | 
						|
          case XML_PLACE_HIT :
 | 
						|
            if (result_set_n == 0) {
 | 
						|
              if (in_vector) {
 | 
						|
                if (vector_element_n > 0) {
 | 
						|
                  GRN_TEXT_PUTS(ctx, transformed, ", ");
 | 
						|
                }
 | 
						|
                GRN_TEXT_PUT(ctx, transformed,
 | 
						|
                             GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
 | 
						|
                vector_element_n++;
 | 
						|
              } else if (in_weight_vector) {
 | 
						|
                grn_bool is_key;
 | 
						|
                is_key = ((weight_vector_item_n % 2) == 0);
 | 
						|
                if (is_key) {
 | 
						|
                  unsigned int weight_vector_key_n;
 | 
						|
                  weight_vector_key_n = weight_vector_item_n / 2;
 | 
						|
                  if (weight_vector_key_n > 0) {
 | 
						|
                    GRN_TEXT_PUTS(ctx, transformed, ", ");
 | 
						|
                  }
 | 
						|
                } else {
 | 
						|
                  GRN_TEXT_PUTS(ctx, transformed, ":");
 | 
						|
                }
 | 
						|
                GRN_TEXT_PUT(ctx, transformed,
 | 
						|
                             GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
 | 
						|
                weight_vector_item_n++;
 | 
						|
              } else {
 | 
						|
                char *c = transform_xml_next_column(&columns, column_n++);
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, c);
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, "\">");
 | 
						|
                GRN_TEXT_PUT(ctx, transformed,
 | 
						|
                             GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
 | 
						|
              }
 | 
						|
            } else {
 | 
						|
              char *c = transform_xml_next_column(&columns, column_n++);
 | 
						|
              GRN_TEXT_PUTS(ctx, transformed, c);
 | 
						|
              GRN_TEXT_PUTS(ctx, transformed, "=\"");
 | 
						|
              GRN_TEXT_PUT(ctx, transformed,
 | 
						|
                           GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
 | 
						|
              GRN_TEXT_PUTS(ctx, transformed, "\" ");
 | 
						|
            }
 | 
						|
            break;
 | 
						|
          default :
 | 
						|
            if (EQUAL_NAME_P("NHITS")) {
 | 
						|
              if (result_set_n == 0) {
 | 
						|
                uint32_t nhits;
 | 
						|
                grn_obj *offset_value, *limit_value;
 | 
						|
 | 
						|
                nhits = grn_atoui(GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf),
 | 
						|
                                  NULL);
 | 
						|
                offset_value = grn_expr_get_var(ctx, expr,
 | 
						|
                                                "offset", strlen("offset"));
 | 
						|
                limit_value = grn_expr_get_var(ctx, expr,
 | 
						|
                                               "limit", strlen("limit"));
 | 
						|
                if (GRN_TEXT_LEN(offset_value)) {
 | 
						|
                  offset = grn_atoi(GRN_TEXT_VALUE(offset_value),
 | 
						|
                                    GRN_BULK_CURR(offset_value),
 | 
						|
                                    NULL);
 | 
						|
                } else {
 | 
						|
                  offset = 0;
 | 
						|
                }
 | 
						|
                if (GRN_TEXT_LEN(limit_value)) {
 | 
						|
                  limit = grn_atoi(GRN_TEXT_VALUE(limit_value),
 | 
						|
                                   GRN_BULK_CURR(limit_value),
 | 
						|
                                   NULL);
 | 
						|
                } else {
 | 
						|
#define DEFAULT_LIMIT 10
 | 
						|
                  limit = DEFAULT_LIMIT;
 | 
						|
#undef DEFAULT_LIMIT
 | 
						|
                }
 | 
						|
                grn_normalize_offset_and_limit(ctx, nhits, &offset, &limit);
 | 
						|
                record_n = offset + 1;
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed,
 | 
						|
                              "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
 | 
						|
                              "<SEGMENTS>\n"
 | 
						|
                              "<SEGMENT>\n"
 | 
						|
                              "<RESULTPAGE>\n"
 | 
						|
                              "<RESULTSET OFFSET=\"");
 | 
						|
                grn_text_lltoa(ctx, transformed, offset);
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, "\" LIMIT=\"");
 | 
						|
                grn_text_lltoa(ctx, transformed, limit);
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, "\" NHITS=\"");
 | 
						|
                grn_text_lltoa(ctx, transformed, nhits);
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed, "\">\n");
 | 
						|
              } else {
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed,
 | 
						|
                              "<NAVIGATIONELEMENTS COUNT=\"");
 | 
						|
                GRN_TEXT_PUT(ctx, transformed,
 | 
						|
                             GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
 | 
						|
                GRN_TEXT_PUTS(ctx, transformed,
 | 
						|
                              "\">\n");
 | 
						|
              }
 | 
						|
            } else if (EQUAL_NAME_P("TEXT")) {
 | 
						|
              switch (place) {
 | 
						|
              case XML_PLACE_COLUMN :
 | 
						|
                if (column_text_n == 0) {
 | 
						|
                  GRN_TEXT_PUT(ctx, &columns,
 | 
						|
                               GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
 | 
						|
                  GRN_TEXT_PUTC(ctx, &columns, '\0');
 | 
						|
                }
 | 
						|
                column_text_n++;
 | 
						|
                break;
 | 
						|
              default :
 | 
						|
                break;
 | 
						|
              }
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      default :
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      s++;
 | 
						|
      GRN_BULK_REWIND(&buf);
 | 
						|
      status = XML_TEXT;
 | 
						|
      break;
 | 
						|
    default :
 | 
						|
      len = grn_charlen(ctx, s, e);
 | 
						|
      switch (status) {
 | 
						|
      case XML_START_ELEMENT :
 | 
						|
      case XML_END_ELEMENT :
 | 
						|
        GRN_TEXT_PUT(ctx, &name, s, len);
 | 
						|
        break;
 | 
						|
      default :
 | 
						|
        GRN_TEXT_PUT(ctx, &buf, s, len);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      s += len;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
#undef EQUAL_NAME_P
 | 
						|
 | 
						|
  GRN_OBJ_FIN(ctx, &buf);
 | 
						|
  GRN_OBJ_FIN(ctx, &name);
 | 
						|
  GRN_OBJ_FIN(ctx, &columns);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
typedef struct {
 | 
						|
  grn_ctx *ctx;
 | 
						|
  grn_obj *buffer;
 | 
						|
} msgpack_writer_ctx;
 | 
						|
 | 
						|
static inline int
 | 
						|
msgpack_buffer_writer(void* data, const char* buf, msgpack_size_t len)
 | 
						|
{
 | 
						|
  msgpack_writer_ctx *writer_ctx = (msgpack_writer_ctx *)data;
 | 
						|
  return grn_bulk_write(writer_ctx->ctx, writer_ctx->buffer, buf, len);
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#define JSON_CALLBACK_PARAM "callback"
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_envelope_json_v1(grn_ctx *ctx,
 | 
						|
                            grn_rc rc,
 | 
						|
                            grn_obj *head,
 | 
						|
                            grn_obj *body,
 | 
						|
                            grn_obj *foot,
 | 
						|
                            double started,
 | 
						|
                            double elapsed,
 | 
						|
                            const char *file,
 | 
						|
                            int line)
 | 
						|
{
 | 
						|
  size_t indent_level = 0;
 | 
						|
 | 
						|
  json_array_open(ctx, head, &indent_level);
 | 
						|
  {
 | 
						|
    json_array_open(ctx, head, &indent_level);
 | 
						|
    {
 | 
						|
      grn_text_itoa(ctx, head, rc);
 | 
						|
 | 
						|
      json_element_end(ctx, head, indent_level);
 | 
						|
      grn_text_ftoa(ctx, head, started);
 | 
						|
 | 
						|
      json_element_end(ctx, head, indent_level);
 | 
						|
      grn_text_ftoa(ctx, head, elapsed);
 | 
						|
 | 
						|
      if (rc != GRN_SUCCESS) {
 | 
						|
        json_element_end(ctx, head, indent_level);
 | 
						|
        grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
 | 
						|
 | 
						|
        if (ctx->errfunc && ctx->errfile) {
 | 
						|
          grn_obj *command;
 | 
						|
 | 
						|
          json_element_end(ctx, head, indent_level);
 | 
						|
          json_array_open(ctx, head, &indent_level);
 | 
						|
          {
 | 
						|
            json_array_open(ctx, head, &indent_level);
 | 
						|
            {
 | 
						|
              grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
 | 
						|
 | 
						|
              json_element_end(ctx, head, indent_level);
 | 
						|
              grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
 | 
						|
 | 
						|
              json_element_end(ctx, head, indent_level);
 | 
						|
              grn_text_itoa(ctx, head, ctx->errline);
 | 
						|
            }
 | 
						|
            json_array_close(ctx, head, &indent_level);
 | 
						|
 | 
						|
            if (file && (command = GRN_CTX_USER_DATA(ctx)->ptr)) {
 | 
						|
              json_element_end(ctx, head, indent_level);
 | 
						|
              json_array_open(ctx, head, &indent_level);
 | 
						|
              {
 | 
						|
                grn_text_esc(ctx, head, file, strlen(file));
 | 
						|
 | 
						|
                json_element_end(ctx, head, indent_level);
 | 
						|
                grn_text_itoa(ctx, head, line);
 | 
						|
 | 
						|
                json_element_end(ctx, head, indent_level);
 | 
						|
                grn_text_esc(ctx, head,
 | 
						|
                             GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
 | 
						|
              }
 | 
						|
              json_array_close(ctx, head, &indent_level);
 | 
						|
            }
 | 
						|
          }
 | 
						|
          json_array_close(ctx, head, &indent_level);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    json_array_close(ctx, head, &indent_level);
 | 
						|
  }
 | 
						|
 | 
						|
  if (GRN_TEXT_LEN(body)) {
 | 
						|
    json_element_end(ctx, head, indent_level);
 | 
						|
  }
 | 
						|
 | 
						|
  json_array_close(ctx, foot, &indent_level);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_envelope_json(grn_ctx *ctx,
 | 
						|
                         grn_rc rc,
 | 
						|
                         grn_obj *head,
 | 
						|
                         grn_obj *body,
 | 
						|
                         grn_obj *foot,
 | 
						|
                         double started,
 | 
						|
                         double elapsed,
 | 
						|
                         const char *file,
 | 
						|
                         int line)
 | 
						|
{
 | 
						|
  size_t indent_level = 0;
 | 
						|
 | 
						|
  json_map_open(ctx, head, &indent_level);
 | 
						|
  {
 | 
						|
    json_key(ctx, head, "header");
 | 
						|
    json_map_open(ctx, head, &indent_level);
 | 
						|
    {
 | 
						|
      json_key(ctx, head, "return_code");
 | 
						|
      grn_text_itoa(ctx, head, rc);
 | 
						|
 | 
						|
      json_value_end(ctx, head, indent_level);
 | 
						|
      json_key(ctx, head, "start_time");
 | 
						|
      grn_text_ftoa(ctx, head, started);
 | 
						|
 | 
						|
      json_value_end(ctx, head, indent_level);
 | 
						|
      json_key(ctx, head, "elapsed_time");
 | 
						|
      grn_text_ftoa(ctx, head, elapsed);
 | 
						|
 | 
						|
      if (rc != GRN_SUCCESS) {
 | 
						|
        json_value_end(ctx, head, indent_level);
 | 
						|
        json_key(ctx, head, "error");
 | 
						|
        json_map_open(ctx, head, &indent_level);
 | 
						|
        {
 | 
						|
          json_key(ctx, head, "message");
 | 
						|
          grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
 | 
						|
 | 
						|
          if (ctx->errfunc && ctx->errfile) {
 | 
						|
            json_value_end(ctx, head, indent_level);
 | 
						|
            json_key(ctx, head, "function");
 | 
						|
            grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
 | 
						|
 | 
						|
            json_value_end(ctx, head, indent_level);
 | 
						|
            json_key(ctx, head, "file");
 | 
						|
            grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
 | 
						|
 | 
						|
            json_value_end(ctx, head, indent_level);
 | 
						|
            json_key(ctx, head, "line");
 | 
						|
            grn_text_itoa(ctx, head, ctx->errline);
 | 
						|
          }
 | 
						|
 | 
						|
          if (file) {
 | 
						|
            grn_obj *command;
 | 
						|
 | 
						|
            command = GRN_CTX_USER_DATA(ctx)->ptr;
 | 
						|
            if (command) {
 | 
						|
              json_value_end(ctx, head, indent_level);
 | 
						|
              json_key(ctx, head, "input");
 | 
						|
              json_map_open(ctx, head, &indent_level);
 | 
						|
              {
 | 
						|
                json_key(ctx, head, "file");
 | 
						|
                grn_text_esc(ctx, head, file, strlen(file));
 | 
						|
 | 
						|
                json_value_end(ctx, head, indent_level);
 | 
						|
                json_key(ctx, head, "line");
 | 
						|
                grn_text_itoa(ctx, head, line);
 | 
						|
 | 
						|
                json_value_end(ctx, head, indent_level);
 | 
						|
                json_key(ctx, head, "command");
 | 
						|
                grn_text_esc(ctx, head,
 | 
						|
                             GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
 | 
						|
              }
 | 
						|
              json_map_close(ctx, head, &indent_level);
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        json_map_close(ctx, head, &indent_level);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    json_map_close(ctx, head, &indent_level);
 | 
						|
 | 
						|
    if (GRN_TEXT_LEN(body)) {
 | 
						|
      json_value_end(ctx, head, indent_level);
 | 
						|
      json_key(ctx, head, "body");
 | 
						|
    }
 | 
						|
 | 
						|
    json_map_close(ctx, foot, &indent_level);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
static void
 | 
						|
msgpack_pack_cstr(msgpack_packer *packer,
 | 
						|
                  const char *string)
 | 
						|
{
 | 
						|
  size_t size;
 | 
						|
 | 
						|
  size = strlen(string);
 | 
						|
  msgpack_pack_str(packer, size);
 | 
						|
  msgpack_pack_str_body(packer, string, size);
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_envelope_msgpack_v1(grn_ctx *ctx,
 | 
						|
                               grn_rc rc,
 | 
						|
                               grn_obj *head,
 | 
						|
                               grn_obj *body,
 | 
						|
                               grn_obj *foot,
 | 
						|
                               double started,
 | 
						|
                               double elapsed,
 | 
						|
                               const char *file,
 | 
						|
                               int line)
 | 
						|
{
 | 
						|
  msgpack_writer_ctx head_writer_ctx;
 | 
						|
  msgpack_packer header_packer;
 | 
						|
  int header_size;
 | 
						|
 | 
						|
  head_writer_ctx.ctx    = ctx;
 | 
						|
  head_writer_ctx.buffer = head;
 | 
						|
  msgpack_packer_init(&header_packer, &head_writer_ctx, msgpack_buffer_writer);
 | 
						|
 | 
						|
  /* [HEADER, (BODY)] */
 | 
						|
  if (GRN_TEXT_LEN(body) > 0) {
 | 
						|
    msgpack_pack_array(&header_packer, 2);
 | 
						|
  } else {
 | 
						|
    msgpack_pack_array(&header_packer, 1);
 | 
						|
  }
 | 
						|
 | 
						|
  /* HEADER := [rc, started, elapsed, (error, (ERROR DETAIL))] */
 | 
						|
  header_size = 3;
 | 
						|
  if (rc != GRN_SUCCESS) {
 | 
						|
    header_size++;
 | 
						|
    if (ctx->errfunc && ctx->errfile) {
 | 
						|
      header_size++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  msgpack_pack_array(&header_packer, header_size);
 | 
						|
  msgpack_pack_int(&header_packer, rc);
 | 
						|
 | 
						|
  msgpack_pack_double(&header_packer, started);
 | 
						|
  msgpack_pack_double(&header_packer, elapsed);
 | 
						|
 | 
						|
  if (rc != GRN_SUCCESS) {
 | 
						|
    msgpack_pack_str(&header_packer, strlen(ctx->errbuf));
 | 
						|
    msgpack_pack_str_body(&header_packer, ctx->errbuf, strlen(ctx->errbuf));
 | 
						|
    if (ctx->errfunc && ctx->errfile) {
 | 
						|
      grn_obj *command = GRN_CTX_USER_DATA(ctx)->ptr;
 | 
						|
      int      error_detail_size;
 | 
						|
 | 
						|
      /* ERROR DETAIL :    = [[errfunc, errfile, errline,
 | 
						|
         (file, line, command)]] */
 | 
						|
      /* TODO: output backtrace */
 | 
						|
      msgpack_pack_array(&header_packer, 1);
 | 
						|
      error_detail_size    = 3;
 | 
						|
      if (command) {
 | 
						|
        error_detail_size += 3;
 | 
						|
      }
 | 
						|
      msgpack_pack_array(&header_packer, error_detail_size);
 | 
						|
 | 
						|
      msgpack_pack_str(&header_packer, strlen(ctx->errfunc));
 | 
						|
      msgpack_pack_str_body(&header_packer, ctx->errfunc, strlen(ctx->errfunc));
 | 
						|
 | 
						|
      msgpack_pack_str(&header_packer, strlen(ctx->errfile));
 | 
						|
      msgpack_pack_str_body(&header_packer, ctx->errfile, strlen(ctx->errfile));
 | 
						|
 | 
						|
      msgpack_pack_int(&header_packer, ctx->errline);
 | 
						|
 | 
						|
      if (command) {
 | 
						|
        if (file) {
 | 
						|
          msgpack_pack_str(&header_packer, strlen(file));
 | 
						|
          msgpack_pack_str_body(&header_packer, file, strlen(file));
 | 
						|
        } else {
 | 
						|
          msgpack_pack_str(&header_packer, 7);
 | 
						|
          msgpack_pack_str_body(&header_packer, "(stdin)", 7);
 | 
						|
        }
 | 
						|
 | 
						|
        msgpack_pack_int(&header_packer, line);
 | 
						|
 | 
						|
        msgpack_pack_str(&header_packer, GRN_TEXT_LEN(command));
 | 
						|
        msgpack_pack_str_body(&header_packer, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
grn_output_envelope_msgpack(grn_ctx    *ctx,
 | 
						|
                            grn_rc      rc,
 | 
						|
                            grn_obj    *head,
 | 
						|
                            grn_obj    *body,
 | 
						|
                            grn_obj    *foot,
 | 
						|
                            double      started,
 | 
						|
                            double      elapsed,
 | 
						|
                            const char *file,
 | 
						|
                            int         line)
 | 
						|
{
 | 
						|
  msgpack_writer_ctx writer_ctx;
 | 
						|
  msgpack_packer packer;
 | 
						|
  int n_elements;
 | 
						|
 | 
						|
  writer_ctx.ctx = ctx;
 | 
						|
  writer_ctx.buffer = head;
 | 
						|
  msgpack_packer_init(&packer, &writer_ctx, msgpack_buffer_writer);
 | 
						|
 | 
						|
  /*
 | 
						|
   * ENVELOPE := {
 | 
						|
   *   "header": HEADER,
 | 
						|
   *   "body":   BODY    (optional)
 | 
						|
   * }
 | 
						|
   */
 | 
						|
  if (GRN_TEXT_LEN(body) > 0) {
 | 
						|
    n_elements = 2;
 | 
						|
  } else {
 | 
						|
    n_elements = 1;
 | 
						|
  }
 | 
						|
 | 
						|
  msgpack_pack_map(&packer, n_elements);
 | 
						|
  {
 | 
						|
    int n_header_elements = 3;
 | 
						|
 | 
						|
    /*
 | 
						|
     * HEADER := {
 | 
						|
     *   "return_code":  rc,
 | 
						|
     *   "start_time":   started,
 | 
						|
     *   "elapsed_time": elapsed,
 | 
						|
     "   "error": {                   (optional)
 | 
						|
     *      "message":  errbuf,
 | 
						|
     *      "function": errfunc,
 | 
						|
     *      "file":     errfile,
 | 
						|
     *      "line":     errline,
 | 
						|
     *      "input": {                (optional)
 | 
						|
     *        "file":    input_file,
 | 
						|
     *        "line":    line,
 | 
						|
     *        "command": command
 | 
						|
     *      }
 | 
						|
     *   }
 | 
						|
     * }
 | 
						|
     */
 | 
						|
 | 
						|
    if (rc != GRN_SUCCESS) {
 | 
						|
      n_header_elements++;
 | 
						|
    }
 | 
						|
 | 
						|
    msgpack_pack_cstr(&packer, "header");
 | 
						|
    msgpack_pack_map(&packer, n_header_elements);
 | 
						|
    {
 | 
						|
      msgpack_pack_cstr(&packer, "return_code");
 | 
						|
      msgpack_pack_int(&packer, rc);
 | 
						|
 | 
						|
      msgpack_pack_cstr(&packer, "start_time");
 | 
						|
      msgpack_pack_double(&packer, started);
 | 
						|
 | 
						|
      msgpack_pack_cstr(&packer, "elapsed_time");
 | 
						|
      msgpack_pack_double(&packer, elapsed);
 | 
						|
 | 
						|
      if (rc != GRN_SUCCESS) {
 | 
						|
        int n_error_elements = 1;
 | 
						|
        grn_obj *command;
 | 
						|
 | 
						|
        if (ctx->errfunc) {
 | 
						|
          n_error_elements++;
 | 
						|
        }
 | 
						|
        if (ctx->errfile) {
 | 
						|
          n_error_elements += 2;
 | 
						|
        }
 | 
						|
 | 
						|
        command = GRN_CTX_USER_DATA(ctx)->ptr;
 | 
						|
        if (file || command) {
 | 
						|
          n_error_elements++;
 | 
						|
        }
 | 
						|
 | 
						|
        msgpack_pack_cstr(&packer, "error");
 | 
						|
        msgpack_pack_map(&packer, n_error_elements);
 | 
						|
        {
 | 
						|
          msgpack_pack_cstr(&packer, "message");
 | 
						|
          msgpack_pack_cstr(&packer, ctx->errbuf);
 | 
						|
 | 
						|
          if (ctx->errfunc) {
 | 
						|
            msgpack_pack_cstr(&packer, "function");
 | 
						|
            msgpack_pack_cstr(&packer, ctx->errfunc);
 | 
						|
          }
 | 
						|
 | 
						|
          if (ctx->errfile) {
 | 
						|
            msgpack_pack_cstr(&packer, "file");
 | 
						|
            msgpack_pack_cstr(&packer, ctx->errfile);
 | 
						|
 | 
						|
            msgpack_pack_cstr(&packer, "line");
 | 
						|
            msgpack_pack_int(&packer, ctx->errline);
 | 
						|
          }
 | 
						|
 | 
						|
          if (file || command) {
 | 
						|
            int n_input_elements = 0;
 | 
						|
 | 
						|
            if (file) {
 | 
						|
              n_input_elements += 2;
 | 
						|
            }
 | 
						|
            if (command) {
 | 
						|
              n_input_elements++;
 | 
						|
            }
 | 
						|
 | 
						|
            msgpack_pack_cstr(&packer, "input");
 | 
						|
            msgpack_pack_map(&packer, n_input_elements);
 | 
						|
 | 
						|
            if (file) {
 | 
						|
              msgpack_pack_cstr(&packer, "file");
 | 
						|
              msgpack_pack_cstr(&packer, file);
 | 
						|
 | 
						|
              msgpack_pack_cstr(&packer, "line");
 | 
						|
              msgpack_pack_int(&packer, line);
 | 
						|
            }
 | 
						|
 | 
						|
            if (command) {
 | 
						|
              msgpack_pack_cstr(&packer, "command");
 | 
						|
              msgpack_pack_str(&packer, GRN_TEXT_LEN(command));
 | 
						|
              msgpack_pack_str_body(&packer,
 | 
						|
                                    GRN_TEXT_VALUE(command),
 | 
						|
                                    GRN_TEXT_LEN(command));
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (GRN_TEXT_LEN(body) > 0) {
 | 
						|
      msgpack_pack_cstr(&packer, "body");
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
#endif /* GRN_WITH_MESSAGE_PACK */
 | 
						|
 | 
						|
void
 | 
						|
grn_output_envelope(grn_ctx *ctx,
 | 
						|
                    grn_rc rc,
 | 
						|
                    grn_obj *head,
 | 
						|
                    grn_obj *body,
 | 
						|
                    grn_obj *foot,
 | 
						|
                    const char *file,
 | 
						|
                    int line)
 | 
						|
{
 | 
						|
  double started, finished, elapsed;
 | 
						|
 | 
						|
  grn_timeval tv_now;
 | 
						|
  grn_timeval_now(ctx, &tv_now);
 | 
						|
  started = ctx->impl->tv.tv_sec;
 | 
						|
  started += ctx->impl->tv.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
 | 
						|
  finished = tv_now.tv_sec;
 | 
						|
  finished += tv_now.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
 | 
						|
  elapsed = finished - started;
 | 
						|
 | 
						|
  switch (ctx->impl->output.type) {
 | 
						|
  case GRN_CONTENT_JSON:
 | 
						|
    {
 | 
						|
      grn_obj *expr;
 | 
						|
      grn_obj *jsonp_func = NULL;
 | 
						|
 | 
						|
      expr = ctx->impl->curr_expr;
 | 
						|
      if (expr) {
 | 
						|
        jsonp_func = grn_expr_get_var(ctx, expr, JSON_CALLBACK_PARAM,
 | 
						|
                                      strlen(JSON_CALLBACK_PARAM));
 | 
						|
      }
 | 
						|
      if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
 | 
						|
        GRN_TEXT_PUT(ctx, head,
 | 
						|
                     GRN_TEXT_VALUE(jsonp_func), GRN_TEXT_LEN(jsonp_func));
 | 
						|
        GRN_TEXT_PUTC(ctx, head, '(');
 | 
						|
      }
 | 
						|
 | 
						|
      if (grn_ctx_get_command_version(ctx) <= GRN_COMMAND_VERSION_2) {
 | 
						|
        grn_output_envelope_json_v1(ctx, rc,
 | 
						|
                                    head, body, foot,
 | 
						|
                                    started, elapsed,
 | 
						|
                                    file, line);
 | 
						|
      } else {
 | 
						|
        grn_output_envelope_json(ctx, rc,
 | 
						|
                                 head, body, foot,
 | 
						|
                                 started, elapsed,
 | 
						|
                                 file, line);
 | 
						|
      }
 | 
						|
 | 
						|
      if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
 | 
						|
        GRN_TEXT_PUTS(ctx, foot, ");");
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_TSV:
 | 
						|
    grn_text_itoa(ctx, head, rc);
 | 
						|
    GRN_TEXT_PUTC(ctx, head, '\t');
 | 
						|
    grn_text_ftoa(ctx, head, started);
 | 
						|
    GRN_TEXT_PUTC(ctx, head, '\t');
 | 
						|
    grn_text_ftoa(ctx, head, elapsed);
 | 
						|
    if (rc != GRN_SUCCESS) {
 | 
						|
      GRN_TEXT_PUTC(ctx, head, '\t');
 | 
						|
      grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
 | 
						|
      if (ctx->errfunc && ctx->errfile) {
 | 
						|
        /* TODO: output backtrace */
 | 
						|
        GRN_TEXT_PUTC(ctx, head, '\t');
 | 
						|
        grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
 | 
						|
        GRN_TEXT_PUTC(ctx, head, '\t');
 | 
						|
        grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
 | 
						|
        GRN_TEXT_PUTC(ctx, head, '\t');
 | 
						|
        grn_text_itoa(ctx, head, ctx->errline);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    GRN_TEXT_PUTS(ctx, head, "\n");
 | 
						|
    GRN_TEXT_PUTS(ctx, foot, "\nEND");
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_XML:
 | 
						|
    {
 | 
						|
      char buf[GRN_TABLE_MAX_KEY_SIZE];
 | 
						|
      int is_select = 0;
 | 
						|
      if (!rc && ctx->impl->curr_expr) {
 | 
						|
        int len = grn_obj_name(ctx, ctx->impl->curr_expr,
 | 
						|
                               buf, GRN_TABLE_MAX_KEY_SIZE);
 | 
						|
        buf[len] = '\0';
 | 
						|
        is_select = strcmp(buf, "select") == 0;
 | 
						|
      }
 | 
						|
      if (is_select) {
 | 
						|
        grn_obj transformed;
 | 
						|
        GRN_TEXT_INIT(&transformed, 0);
 | 
						|
        transform_xml(ctx, body, &transformed);
 | 
						|
        GRN_TEXT_SET(ctx, body,
 | 
						|
                     GRN_TEXT_VALUE(&transformed), GRN_TEXT_LEN(&transformed));
 | 
						|
        GRN_OBJ_FIN(ctx, &transformed);
 | 
						|
      } else {
 | 
						|
        GRN_TEXT_PUTS(ctx, head, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RESULT CODE=\"");
 | 
						|
        grn_text_itoa(ctx, head, rc);
 | 
						|
        GRN_TEXT_PUTS(ctx, head, "\" UP=\"");
 | 
						|
        grn_text_ftoa(ctx, head, started);
 | 
						|
        GRN_TEXT_PUTS(ctx, head, "\" ELAPSED=\"");
 | 
						|
        grn_text_ftoa(ctx, head, elapsed);
 | 
						|
        GRN_TEXT_PUTS(ctx, head, "\">\n");
 | 
						|
        if (rc != GRN_SUCCESS) {
 | 
						|
          GRN_TEXT_PUTS(ctx, head, "<ERROR>");
 | 
						|
          grn_text_escape_xml(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
 | 
						|
          if (ctx->errfunc && ctx->errfile) {
 | 
						|
            /* TODO: output backtrace */
 | 
						|
            GRN_TEXT_PUTS(ctx, head, "<INFO FUNC=\"");
 | 
						|
            grn_text_escape_xml(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
 | 
						|
            GRN_TEXT_PUTS(ctx, head, "\" FILE=\"");
 | 
						|
            grn_text_escape_xml(ctx, head, ctx->errfile, strlen(ctx->errfile));
 | 
						|
            GRN_TEXT_PUTS(ctx, head, "\" LINE=\"");
 | 
						|
            grn_text_itoa(ctx, head, ctx->errline);
 | 
						|
            GRN_TEXT_PUTS(ctx, head, "\"/>");
 | 
						|
          }
 | 
						|
          GRN_TEXT_PUTS(ctx, head, "</ERROR>");
 | 
						|
        }
 | 
						|
        GRN_TEXT_PUTS(ctx, foot, "\n</RESULT>");
 | 
						|
      }
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_MSGPACK:
 | 
						|
#ifdef GRN_WITH_MESSAGE_PACK
 | 
						|
    if (grn_ctx_get_command_version(ctx) <= GRN_COMMAND_VERSION_2) {
 | 
						|
      grn_output_envelope_msgpack_v1(ctx, rc,
 | 
						|
                                     head, body, foot,
 | 
						|
                                     started, elapsed,
 | 
						|
                                     file, line);
 | 
						|
    } else {
 | 
						|
      grn_output_envelope_msgpack(ctx, rc,
 | 
						|
                                  head, body, foot,
 | 
						|
                                  started, elapsed,
 | 
						|
                                  file, line);
 | 
						|
    }
 | 
						|
#endif /* GRN_WITH_MESSAGE_PACK */
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_GROONGA_COMMAND_LIST :
 | 
						|
    break;
 | 
						|
  case GRN_CONTENT_NONE:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
static inline grn_bool
 | 
						|
is_output_columns_format_v1(grn_ctx *ctx,
 | 
						|
                            const char *output_columns,
 | 
						|
                            unsigned int output_columns_len)
 | 
						|
{
 | 
						|
  const char *current;
 | 
						|
  const char *end;
 | 
						|
  grn_bool in_identifier = GRN_FALSE;
 | 
						|
 | 
						|
  current = output_columns;
 | 
						|
  end = current + output_columns_len;
 | 
						|
  while (current < end) {
 | 
						|
    int char_length;
 | 
						|
 | 
						|
    char_length = grn_charlen(ctx, current, end);
 | 
						|
    if (char_length != 1) {
 | 
						|
      return GRN_FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (current[0]) {
 | 
						|
    case ' ' :
 | 
						|
    case ',' :
 | 
						|
      in_identifier = GRN_FALSE;
 | 
						|
      break;
 | 
						|
    case '_' :
 | 
						|
      in_identifier = GRN_TRUE;
 | 
						|
      break;
 | 
						|
    case '.' :
 | 
						|
    case '-' :
 | 
						|
    case '#' :
 | 
						|
    case '@' :
 | 
						|
      if (!in_identifier) {
 | 
						|
        return GRN_FALSE;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    default :
 | 
						|
      if ('a' <= current[0] && current[0] <= 'z') {
 | 
						|
        in_identifier = GRN_TRUE;
 | 
						|
        break;
 | 
						|
      } else if ('A' <= current[0] && current[0] <= 'Z') {
 | 
						|
        in_identifier = GRN_TRUE;
 | 
						|
        break;
 | 
						|
      } else if ('0' <= current[0] && current[0] <= '9') {
 | 
						|
        in_identifier = GRN_TRUE;
 | 
						|
        break;
 | 
						|
      } else {
 | 
						|
        return GRN_FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    current += char_length;
 | 
						|
  }
 | 
						|
 | 
						|
  return GRN_TRUE;
 | 
						|
}
 | 
						|
 | 
						|
grn_rc
 | 
						|
grn_output_format_set_columns(grn_ctx *ctx, grn_obj_format *format,
 | 
						|
                              grn_obj *table,
 | 
						|
                              const char *columns, int columns_len)
 | 
						|
{
 | 
						|
  grn_rc rc;
 | 
						|
 | 
						|
  if (is_output_columns_format_v1(ctx, columns, columns_len)) {
 | 
						|
    rc = grn_obj_columns(ctx, table, columns, columns_len, &(format->columns));
 | 
						|
  } else {
 | 
						|
    grn_obj *variable;
 | 
						|
    GRN_EXPR_CREATE_FOR_QUERY(ctx, table, format->expression, variable);
 | 
						|
    rc = grn_expr_parse(ctx, format->expression,
 | 
						|
                        columns, columns_len, NULL,
 | 
						|
                        GRN_OP_MATCH, GRN_OP_AND,
 | 
						|
                        GRN_EXPR_SYNTAX_OUTPUT_COLUMNS);
 | 
						|
  }
 | 
						|
 | 
						|
  return rc;
 | 
						|
}
 |