Beispiel #1
0
static grn_rc
grn_ctx_init_internal(grn_ctx *ctx, int flags)
{
  if (!ctx) { return GRN_INVALID_ARGUMENT; }
  // if (ctx->stat != GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
  ERRCLR(ctx);
  ctx->flags = flags;
  if (grn_ctx_per_db) {
    ctx->flags |= GRN_CTX_PER_DB;
  }
  ctx->stat = GRN_CTX_INITED;
  ctx->encoding = grn_gctx.encoding;
  ctx->seqno = 0;
  ctx->seqno2 = 0;
  ctx->subno = 0;
  ctx->impl = NULL;
  ctx->user_data.ptr = NULL;
  CRITICAL_SECTION_ENTER(grn_glock);
  ctx->next = grn_gctx.next;
  ctx->prev = &grn_gctx;
  grn_gctx.next->prev = ctx;
  grn_gctx.next = ctx;
  CRITICAL_SECTION_LEAVE(grn_glock);
  ctx->errline = 0;
  ctx->errfile = "";
  ctx->errfunc = "";
  ctx->trace[0] = NULL;
  ctx->errbuf[0] = '\0';
  return GRN_SUCCESS;
}
Beispiel #2
0
grn_rc
grn_ctx_init(grn_ctx *ctx, int flags)
{
  if (!ctx) { return GRN_INVALID_ARGUMENT; }
  // if (ctx->stat != GRN_QL_FIN) { return GRN_INVALID_ARGUMENT; }
  ERRCLR(ctx);
  ctx->flags = flags;
  ctx->stat = GRN_QL_WAIT_EXPR;
  ctx->encoding = grn_gctx.encoding;
  ctx->seqno = 0;
  ctx->seqno2 = 0;
  ctx->subno = 0;
  ctx->impl = NULL;
  if (flags & GRN_CTX_USE_QL) {
    grn_ctx_ql_init(ctx, flags);
    if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; }
  }
  MUTEX_LOCK(grn_glock);
  ctx->next = grn_gctx.next;
  ctx->prev = &grn_gctx;
  grn_gctx.next->prev = ctx;
  grn_gctx.next = ctx;
  MUTEX_UNLOCK(grn_glock);
  return ctx->rc;
}
Beispiel #3
0
grn_rc
grn_com_event_poll(grn_ctx *ctx, grn_com_event *ev, int timeout)
{
  int nevents;
  grn_com *com;
#ifdef USE_SELECT
  uint32_t dummy;
  grn_sock *pfd;
  int nfds = 0;
  fd_set rfds;
  fd_set wfds;
  struct timeval tv;
  if (timeout >= 0) {
    tv.tv_sec = timeout / 1000;
    tv.tv_usec = (timeout % 1000) * 1000;
  }
  FD_ZERO(&rfds);
  FD_ZERO(&wfds);
  ctx->errlvl = GRN_OK;
  ctx->rc = GRN_SUCCESS;
  {
    grn_hash_cursor *cursor;
    cursor = grn_hash_cursor_open(ctx, ev->hash, NULL, 0, NULL, 0, 0, -1, 0);
    if (cursor) {
      grn_id id;
      while ((id = grn_hash_cursor_next(ctx, cursor))) {
        grn_hash_cursor_get_key_value(ctx,
                                      cursor,
                                      (void **)(&pfd),
                                      &dummy,
                                      (void **)(&com));
        if ((com->events & GRN_COM_POLLIN)) { FD_SET(*pfd, &rfds); }
        if ((com->events & GRN_COM_POLLOUT)) { FD_SET(*pfd, &wfds); }
# ifndef WIN32
        if (*pfd > nfds) { nfds = *pfd; }
# endif /* WIN32 */
      }
      grn_hash_cursor_close(ctx, cursor);
    }
  }
  nevents = select(nfds + 1, &rfds, &wfds, NULL, (timeout >= 0) ? &tv : NULL);
  if (nevents < 0) {
    SOERR("select");
    if (ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) { ERRCLR(ctx); }
    return ctx->rc;
  }
  if (timeout < 0 && !nevents) { GRN_LOG(ctx, GRN_LOG_NOTICE, "select returns 0 events"); }
  GRN_HASH_EACH(ctx, ev->hash, eh, &pfd, &dummy, &com, {
    if (FD_ISSET(*pfd, &rfds)) { grn_com_receiver(ctx, com); }
  });
Beispiel #4
0
static void
grn_com_receiver(grn_ctx *ctx, grn_com *com)
{
  grn_com_event *ev = com->ev;
  ERRCLR(ctx);
  if (ev->acceptor == com) {
    grn_com *ncs;
    grn_sock fd = accept(com->fd, NULL, NULL);
    if (fd == -1) {
      if (errno == EMFILE) {
        grn_com_event_stop_accept(ctx, ev);
      } else {
        SOERR("accept");
      }
      return;
    }
    if (grn_com_event_add(ctx, ev, fd, GRN_COM_POLLIN, (grn_com **)&ncs)) {
      grn_sock_close(fd);
      return;
    }
    ncs->has_sid = 0;
    ncs->closed = 0;
    ncs->opaque = NULL;
    GRN_COM_QUEUE_INIT(&ncs->new_);
    // GRN_LOG(ctx, GRN_LOG_NOTICE, "accepted (%d)", fd);
    return;
  } else {
    grn_msg *msg = (grn_msg *)grn_msg_open(ctx, com, &ev->recv_old);
    grn_com_recv(ctx, msg->u.peer, &msg->header, (grn_obj *)msg);
    if (msg->u.peer /* is_edge_request(msg)*/) {
      grn_memcpy(&msg->edge_id, &ev->curr_edge_id, sizeof(grn_com_addr));
      if (!com->has_sid) {
        com->has_sid = 1;
        com->sid = ev->curr_edge_id.sid++;
      }
      msg->edge_id.sid = com->sid;
    }
    msg->acceptor = ev->acceptor;
    ev->msg_handler(ctx, (grn_obj *)msg);
  }
}
Beispiel #5
0
static void
grn_db_reindex(grn_ctx *ctx, grn_obj *db)
{
  grn_table_cursor *cursor;
  grn_id id;

  cursor = grn_table_cursor_open(ctx, db,
                                 NULL, 0, NULL, 0,
                                 0, -1,
                                 GRN_CURSOR_BY_ID);
  if (!cursor) {
    return;
  }

  while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
    grn_obj *object;

    object = grn_ctx_at(ctx, id);
    if (!object) {
      ERRCLR(ctx);
      continue;
    }

    switch (object->header.type) {
    case GRN_TABLE_HASH_KEY :
    case GRN_TABLE_PAT_KEY :
    case GRN_TABLE_DAT_KEY :
      grn_obj_reindex(ctx, object);
      break;
    default:
      break;
    }

    grn_obj_unlink(ctx, object);

    if (ctx->rc != GRN_SUCCESS) {
      break;
    }
  }
  grn_table_cursor_close(ctx, cursor);
}
Beispiel #6
0
static void
brace_close(grn_ctx *ctx, grn_loader *loader)
{
  grn_id id = GRN_ID_NIL;
  grn_obj *value, *value_begin, *value_end;
  grn_obj *id_value = NULL, *key_value = NULL;
  uint32_t begin;

  GRN_UINT32_POP(&loader->level, begin);
  value_begin = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
  value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
  GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACE);
  GRN_UINT32_SET(ctx, value_begin, loader->values_size - begin - 1);
  value_begin++;
  if (GRN_BULK_VSIZE(&loader->level) > sizeof(uint32_t) * loader->emit_level) {
    return;
  }
  if (!loader->table) {
    goto exit;
  }

  /* Scan values to find _id or _key. */
  for (value = value_begin; value + 1 < value_end;
       value = values_next(ctx, value)) {
    const char *name = GRN_TEXT_VALUE(value);
    unsigned int name_size = GRN_TEXT_LEN(value);
    if (value->header.domain != GRN_DB_TEXT) {
      grn_obj buffer;
      GRN_TEXT_INIT(&buffer, 0);
      grn_inspect(ctx, &buffer, value);
      GRN_LOG(ctx, GRN_LOG_ERROR,
              "column name must be string: <%.*s>",
              (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
      GRN_OBJ_FIN(ctx, &buffer);
      goto exit;
    }
    value++;
    if (name_equal(name, name_size, GRN_COLUMN_NAME_ID)) {
      if (id_value || key_value) {
        if (loader->table->header.type == GRN_TABLE_NO_KEY) {
          GRN_LOG(ctx, GRN_LOG_ERROR, "duplicated '_id' column");
          goto exit;
        } else {
          GRN_LOG(ctx, GRN_LOG_ERROR,
                  "duplicated key columns: %s and %s",
                  id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
                  GRN_COLUMN_NAME_ID);
          goto exit;
        }
      }
      id_value = value;
    } else if (name_equal(name, name_size, GRN_COLUMN_NAME_KEY)) {
      if (id_value || key_value) {
        GRN_LOG(ctx, GRN_LOG_ERROR,
                "duplicated key columns: %s and %s",
                id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
                GRN_COLUMN_NAME_KEY);
        goto exit;
      }
      key_value = value;
    }
  }

  switch (loader->table->header.type) {
  case GRN_TABLE_HASH_KEY :
  case GRN_TABLE_PAT_KEY :
  case GRN_TABLE_DAT_KEY :
    /* The target table requires _id or _key. */
    if (!id_value && !key_value) {
      GRN_LOG(ctx, GRN_LOG_ERROR, "neither _key nor _id is assigned");
      goto exit;
    }
    break;
  default :
    /* The target table does not have _key. */
    if (key_value) {
      GRN_LOG(ctx, GRN_LOG_ERROR, "nonexistent key value");
      goto exit;
    }
    break;
  }

  if (id_value) {
    id = parse_id_value(ctx, id_value);
    if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
      if (ctx->rc == GRN_SUCCESS) {
        id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
      }
    }
  } else if (key_value) {
    id = loader_add(ctx, key_value);
  } else {
    id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
  }
  if (id == GRN_ID_NIL) {
    /* Target record is not available. */
    goto exit;
  }

  for (value = value_begin; value + 1 < value_end;
       value = values_next(ctx, value)) {
    grn_obj *col;
    const char *name = GRN_TEXT_VALUE(value);
    unsigned int name_size = GRN_TEXT_LEN(value);
    value++;
    if (value == id_value || value == key_value) {
      /* Skip _id and _key, because it's already used to get id. */
      continue;
    }
    col = grn_obj_column(ctx, loader->table, name, name_size);
    if (!col) {
      GRN_LOG(ctx, GRN_LOG_ERROR, "invalid column('%.*s')",
              (int)name_size, name);
      /* Automatic column creation is disabled. */
      /*
      if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
        grn_obj *v = value + 1;
        col = grn_column_create(ctx, loader->table, name, name_size,
                                NULL, GRN_OBJ_PERSISTENT|GRN_OBJ_COLUMN_VECTOR,
                                grn_ctx_at(ctx, v->header.domain));
      } else {
        col = grn_column_create(ctx, loader->table, name, name_size,
                                NULL, GRN_OBJ_PERSISTENT,
                                grn_ctx_at(ctx, value->header.domain));
      }
      */
    } else {
      if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
        set_vector(ctx, col, id, value);
      } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
        set_weight_vector(ctx, col, id, value);
      } else {
        grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
      }
      if (ctx->rc != GRN_SUCCESS) {
        grn_loader_save_error(ctx, loader);
        report_set_column_value_failure(ctx, key_value,
                                        name, name_size, value);
        loader->n_column_errors++;
        ERRCLR(ctx);
      }
      grn_obj_unlink(ctx, col);
    }
  }
  if (loader->each) {
    value = grn_expr_get_var_by_offset(ctx, loader->each, 0);
    GRN_RECORD_SET(ctx, value, id);
    grn_expr_exec(ctx, loader->each, 0);
  }
  loader->nrecords++;
exit:
  if (ctx->rc != GRN_SUCCESS) {
    loader->n_record_errors++;
  }
  if (loader->output_ids) {
    GRN_UINT32_PUT(ctx, &(loader->ids), id);
  }
  if (loader->output_errors) {
    GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
    grn_vector_add_element(ctx,
                           &(loader->error_messages),
                           ctx->errbuf,
                           strlen(ctx->errbuf),
                           0,
                           GRN_DB_TEXT);
  }
  loader->values_size = begin;
  ERRCLR(ctx);
}
Beispiel #7
0
static void
bracket_close(grn_ctx *ctx, grn_loader *loader)
{
  grn_id id = GRN_ID_NIL;
  grn_obj *value, *value_end, *id_value = NULL, *key_value = NULL;
  grn_obj *col, **cols; /* Columns except _id and _key. */
  uint32_t i, begin;
  uint32_t ncols;   /* Number of columns except _id and _key. */
  uint32_t nvalues; /* Number of values in brackets. */
  uint32_t depth;
  grn_bool is_record_load = GRN_FALSE;

  cols = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
  ncols = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
  GRN_UINT32_POP(&loader->level, begin);
  value = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
  value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
  GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET);
  GRN_UINT32_SET(ctx, value, loader->values_size - begin - 1);
  value++;
  depth = GRN_BULK_VSIZE(&loader->level);
  if (depth > sizeof(uint32_t) * loader->emit_level) {
    return;
  }
  if (depth == 0 || !loader->table ||
      loader->columns_status == GRN_LOADER_COLUMNS_BROKEN) {
    goto exit;
  }
  nvalues = values_len(ctx, value, value_end);

  if (loader->columns_status == GRN_LOADER_COLUMNS_UNSET) {
    /*
     * Target columns and _id or _key are not specified yet and values are
     * handled as column names and "_id" or "_key".
     */
    for (i = 0; i < nvalues; i++) {
      const char *col_name;
      unsigned int col_name_size;
      if (value->header.domain != GRN_DB_TEXT) {
        grn_obj buffer;
        GRN_TEXT_INIT(&buffer, 0);
        grn_inspect(ctx, &buffer, value);
        ERR(GRN_INVALID_ARGUMENT,
            "column name must be string: <%.*s>",
            (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
        grn_loader_save_error(ctx, loader);
        GRN_OBJ_FIN(ctx, &buffer);
        loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
        goto exit;
      }
      col_name = GRN_TEXT_VALUE(value);
      col_name_size = GRN_TEXT_LEN(value);
      col = grn_obj_column(ctx, loader->table, col_name, col_name_size);
      if (!col) {
        ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>",
            col_name_size, col_name);
        grn_loader_save_error(ctx, loader);
        loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
        goto exit;
      }
      if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_ID)) {
        grn_obj_unlink(ctx, col);
        if (loader->id_offset != -1 || loader->key_offset != -1) {
          /* _id and _key must not appear more than once. */
          if (loader->id_offset != -1) {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_ID, i,
                GRN_COLUMN_NAME_ID, loader->id_offset);
          } else {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_ID, i,
                GRN_COLUMN_NAME_KEY, loader->key_offset);
          }
          grn_loader_save_error(ctx, loader);
          loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
          goto exit;
        }
        loader->id_offset = i;
      } else if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_KEY)) {
        grn_obj_unlink(ctx, col);
        if (loader->id_offset != -1 || loader->key_offset != -1) {
          /* _id and _key must not appear more than once. */
          if (loader->id_offset != -1) {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_KEY, i,
                GRN_COLUMN_NAME_ID, loader->id_offset);
          } else {
            ERR(GRN_INVALID_ARGUMENT,
                "duplicated id and key columns: <%s> at %d and <%s> at %d",
                GRN_COLUMN_NAME_KEY, i,
                GRN_COLUMN_NAME_KEY, loader->key_offset);
          }
          grn_loader_save_error(ctx, loader);
          loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
          goto exit;
        }
        loader->key_offset = i;
      } else {
        GRN_PTR_PUT(ctx, &loader->columns, col);
      }
      value++;
    }
    switch (loader->table->header.type) {
    case GRN_TABLE_HASH_KEY :
    case GRN_TABLE_PAT_KEY :
    case GRN_TABLE_DAT_KEY :
      if (loader->id_offset == -1 && loader->key_offset == -1) {
        ERR(GRN_INVALID_ARGUMENT, "missing id or key column");
        grn_loader_save_error(ctx, loader);
        loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
        goto exit;
      }
      break;
    }
    loader->columns_status = GRN_LOADER_COLUMNS_SET;
    goto exit;
  }

  is_record_load = GRN_TRUE;

  /* Target columns and _id or _key are already specified. */
  if (!nvalues) {
    /*
     * Accept empty arrays because a dump command may output a load command
     * which contains empty arrays for a table with deleted records.
     */
    id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
  } else {
    uint32_t expected_nvalues = ncols;
    if (loader->id_offset != -1 || loader->key_offset != -1) {
      expected_nvalues++;
    }
    if (nvalues != expected_nvalues) {
      ERR(GRN_INVALID_ARGUMENT,
          "unexpected #values: expected:%u, actual:%u",
          expected_nvalues, nvalues);
      grn_loader_save_error(ctx, loader);
      goto exit;
    }
    if (loader->id_offset != -1) {
      id_value = value + loader->id_offset;
      id = parse_id_value(ctx, id_value);
      if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
        id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
      }
    } else if (loader->key_offset != -1) {
      key_value = value + loader->key_offset;
      id = loader_add(ctx, key_value);
    } else {
      id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
    }
  }
  if (id == GRN_ID_NIL) {
    /* Target record is not available. */
    goto exit;
  }

  for (i = 0; i < nvalues; i++, value = values_next(ctx, value)) {
    if (i == loader->id_offset || i == loader->key_offset) {
       /* Skip _id and _key, because it's already used to get id. */
       continue;
    }
    col = *cols;
    if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
      set_vector(ctx, col, id, value);
    } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
      set_weight_vector(ctx, col, id, value);
    } else {
      grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
    }
    if (ctx->rc != GRN_SUCCESS) {
      char column_name[GRN_TABLE_MAX_KEY_SIZE];
      unsigned int column_name_size;
      grn_loader_save_error(ctx, loader);
      column_name_size = grn_obj_name(ctx, col, column_name,
                                      GRN_TABLE_MAX_KEY_SIZE);
      report_set_column_value_failure(ctx, key_value,
                                      column_name, column_name_size,
                                      value);
      loader->n_column_errors++;
      ERRCLR(ctx);
    }
    cols++;
  }
  if (loader->each) {
    grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->each, 0);
    GRN_RECORD_SET(ctx, v, id);
    grn_expr_exec(ctx, loader->each, 0);
  }
  loader->nrecords++;
exit:
  if (is_record_load) {
    if (ctx->rc != GRN_SUCCESS) {
      loader->n_record_errors++;
    }
    if (loader->output_ids) {
      GRN_UINT32_PUT(ctx, &(loader->ids), id);
    }
    if (loader->output_errors) {
      GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
      grn_vector_add_element(ctx,
                             &(loader->error_messages),
                             ctx->errbuf,
                             strlen(ctx->errbuf),
                             0,
                             GRN_DB_TEXT);
    }
  }
  loader->values_size = begin;
  ERRCLR(ctx);
}
Beispiel #8
0
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_BULK :
    switch (obj->header.domain) {
    case GRN_DB_VOID :
      grn_output_void(ctx, outbuf, output_type, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
      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(obj), GRN_BULK_VSIZE(obj));
      break;
    case GRN_DB_BOOL :
      grn_output_bool(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_UINT8_VALUE(obj) : 0);
      break;
    case GRN_DB_INT8 :
      grn_output_int32(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_INT8_VALUE(obj) : 0);
      break;
    case GRN_DB_UINT8 :
      grn_output_int32(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_UINT8_VALUE(obj) : 0);
      break;
    case GRN_DB_INT16 :
      grn_output_int32(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_INT16_VALUE(obj) : 0);
      break;
    case GRN_DB_UINT16 :
      grn_output_int32(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_UINT16_VALUE(obj) : 0);
      break;
    case GRN_DB_INT32 :
      grn_output_int32(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_INT32_VALUE(obj) : 0);
      break;
    case GRN_DB_UINT32 :
      grn_output_int64(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_UINT32_VALUE(obj) : 0);
      break;
    case GRN_DB_INT64 :
      grn_output_int64(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_INT64_VALUE(obj) : 0);
      break;
    case GRN_DB_UINT64 :
      grn_output_uint64(ctx, outbuf, output_type,
                        GRN_BULK_VSIZE(obj) ? GRN_UINT64_VALUE(obj) : 0);
      break;
    case GRN_DB_FLOAT :
      grn_output_float(ctx, outbuf, output_type,
                       GRN_BULK_VSIZE(obj) ? GRN_FLOAT_VALUE(obj) : 0);
      break;
    case GRN_DB_TIME :
      grn_output_time(ctx, outbuf, output_type,
                      GRN_BULK_VSIZE(obj) ? GRN_INT64_VALUE(obj) : 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(obj) ? (grn_geo_point *)GRN_BULK_HEAD(obj) : NULL);
      break;
    default :
      if (format) {
        int j;
        int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
        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_o(ctx, outbuf, output_type, columns[j], obj);
        }
        grn_output_array_close(ctx, outbuf, output_type);
      } else {
        grn_obj *table = grn_ctx_at(ctx, obj->header.domain);
        grn_id id = *((grn_id *)GRN_BULK_HEAD(obj));
        if (table && table->header.type != GRN_TABLE_NO_KEY) {
          grn_obj *accessor = grn_obj_column(ctx, table, "_key", 4);
          if (accessor) {
            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;
    }
    break;
  case GRN_UVECTOR :
    if (format) {
      int i, j;
      grn_id *v = (grn_id *)GRN_BULK_HEAD(obj), *ve = (grn_id *)GRN_BULK_CURR(obj);
      int ncolumns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
      grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
      grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", -1);
      grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
      grn_text_itoa(ctx, outbuf, ve - v);
      grn_output_array_close(ctx, outbuf, output_type);
      if (v < ve) {
        if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
          grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", -1);
          for (j = 0; j < ncolumns; j++) {
            grn_id range_id;
            grn_output_array_open(ctx, outbuf, output_type, "COLUMN", -1);
            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);
        }
        for (i = 0;; i++) {
          grn_output_array_open(ctx, outbuf, output_type, "HITS", -1);
          for (j = 0; j < ncolumns; j++) {
            GRN_BULK_REWIND(&buf);
            grn_obj_get_value(ctx, columns[j], *v, &buf);
            grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
          }
          grn_output_array_close(ctx, outbuf, output_type);
          v++;
          if (v < ve) {

          } else {
            break;
          }
        }
      }
      grn_output_array_close(ctx, outbuf, output_type);
    } else {
      grn_obj *range = grn_ctx_at(ctx, obj->header.domain);
      if (range && range->header.type == GRN_TYPE) {
        int value_size = ((struct _grn_type *)range)->obj.range;
        char *v = (char *)GRN_BULK_HEAD(obj),
             *ve = (char *)GRN_BULK_CURR(obj);
        grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
        if (v < ve) {
          for (;;) {
            grn_obj value;
            GRN_OBJ_INIT(&value, GRN_BULK, 0, obj->header.domain);
            grn_bulk_write_from(ctx, &value, v, 0, value_size);
            grn_output_obj(ctx, outbuf, output_type, &value, NULL);

            v += value_size;
            if (v < ve) {

            } else {
              break;
            }
          }
        }
        grn_output_array_close(ctx, outbuf, output_type);
      } else {
        grn_id *v = (grn_id *)GRN_BULK_HEAD(obj),
               *ve = (grn_id *)GRN_BULK_CURR(obj);
        grn_output_array_open(ctx, outbuf, output_type, "VECTOR", ve - v);
        if (v < ve) {
          grn_obj key;
          GRN_OBJ_INIT(&key, GRN_BULK, 0, range->header.domain);
          for (;;) {
            if (range->header.type != GRN_TABLE_NO_KEY) {
              grn_table_get_key2(ctx, range, *v, &key);
              grn_output_obj(ctx, outbuf, output_type, &key, NULL);
              GRN_BULK_REWIND(&key);
            } else {
              grn_obj id;
              GRN_UINT32_INIT(&id, 0);
              GRN_UINT32_SET(ctx, &id, *v);
              grn_output_obj(ctx, outbuf, output_type, &id, NULL);
              GRN_OBJ_FIN(ctx, &id);
            }
            v++;
            if (v < ve) {

            } else {
              break;
            }
          }
          GRN_OBJ_FIN(ctx, &key);
        }
        grn_output_array_close(ctx, outbuf, output_type);
      }
    }
    break;
  case GRN_VECTOR :
    if (obj->header.domain == GRN_DB_VOID) {
      ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
    }
    if (format) {
      ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
          "cannot print GRN_VECTOR using grn_obj_format");
    } else {
      unsigned int i, n;
      grn_obj value;
      GRN_VOID_INIT(&value);
      n = grn_vector_size(ctx, obj);
      grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
      for (i = 0; i < n; i++) {
        const char *_value;
        unsigned int weight, length;
        grn_id domain;

        length = grn_vector_get_element(ctx, obj, i,
                                        &_value, &weight, &domain);
        if (domain != GRN_DB_VOID) {
          grn_obj_reinit(ctx, &value, domain, 0);
        } else {
          grn_obj_reinit(ctx, &value, obj->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);
    }
    break;
  case GRN_PVECTOR :
    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(obj) / sizeof(grn_obj *);
      for (i = 0; i < n; i++) {
        grn_obj *value;

        value = GRN_PTR_VALUE_AT(obj, i);
        grn_output_obj(ctx, outbuf, output_type, value, NULL);
      }
      grn_output_array_close(ctx, outbuf, output_type);
    }
    break;
  case GRN_TABLE_HASH_KEY :
  case GRN_TABLE_PAT_KEY :
  case GRN_TABLE_NO_KEY :
  case GRN_TABLE_VIEW :
    if (format) {
      int i, j;
      int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
      grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
      grn_table_cursor *tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
                                                   format->offset, format->limit,
                                                   GRN_CURSOR_ASCENDING);
      int resultset_size = -1;
      if (!tc) { ERRCLR(ctx); }
#ifdef HAVE_MESSAGE_PACK
      resultset_size = 1; /* [NHITS, (COLUMNS), (HITS)] */
      if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
        resultset_size++;
      }
      resultset_size += format->limit;
#endif
      grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", resultset_size);
      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);
      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);
      }
      if (tc) {
        grn_obj id;
        GRN_TEXT_INIT(&id, 0);
        for (i = 0; !grn_table_cursor_next_o(ctx, tc, &id); i++) {
          grn_output_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
          for (j = 0; j < ncolumns; j++) {
            grn_text_atoj_o(ctx, outbuf, output_type, columns[j], &id);
          }
          grn_output_array_close(ctx, outbuf, output_type);
        }
        GRN_OBJ_FIN(ctx, &id);
        grn_table_cursor_close(ctx, tc);
      }
      grn_output_array_close(ctx, outbuf, output_type);
    } else {
      int i;
      grn_obj *column = grn_obj_column(ctx, obj, "_key", 4);
      grn_table_cursor *tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
                                                   0, -1, GRN_CURSOR_ASCENDING);
      grn_output_array_open(ctx, outbuf, output_type, "HIT", -1);
      if (tc) {
        grn_obj id;
        GRN_TEXT_INIT(&id, 0);
        for (i = 0; !grn_table_cursor_next_o(ctx, tc, &id); i++) {
          /* todo:
          grn_text_atoj_o(ctx, outbuf, output_type, column, &id);
          */
          GRN_BULK_REWIND(&buf);
          grn_obj_get_value_o(ctx, column, &id, &buf);
          grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
        }
        GRN_OBJ_FIN(ctx, &id);
        grn_table_cursor_close(ctx, tc);
      }
      grn_output_array_close(ctx, outbuf, output_type);
      grn_obj_unlink(ctx, column);
    }
    break;
  }
  GRN_OBJ_FIN(ctx, &buf);
}