mirror of
https://github.com/MariaDB/server.git
synced 2025-01-23 15:24:16 +01:00
2077 lines
65 KiB
C
2077 lines
65 KiB
C
/* -*- c-basic-offset: 2 -*- */
|
|
/* Copyright(C) 2009-2014 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-1301 USA
|
|
*/
|
|
|
|
#include "grn.h"
|
|
|
|
#include <string.h>
|
|
#include "grn_str.h"
|
|
#include "grn_db.h"
|
|
#include "grn_util.h"
|
|
#include "grn_output.h"
|
|
|
|
#define LEVELS (&ctx->impl->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
|
|
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) { return; }
|
|
GRN_TEXT_PUTC(ctx, outbuf, ((level & 3) == 3) ? ':' : ',');
|
|
// 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_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->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->msgpacker, nelements);
|
|
#endif
|
|
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:
|
|
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 = grn_vector_pop_element(ctx, &ctx->impl->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_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->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->msgpacker, nelements);
|
|
#endif
|
|
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:
|
|
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 = grn_vector_pop_element(ctx, &ctx->impl->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_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->msgpacker, value);
|
|
#endif
|
|
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->msgpacker, value);
|
|
#endif
|
|
break;
|
|
case GRN_CONTENT_NONE:
|
|
break;
|
|
}
|
|
INCR_LENGTH;
|
|
}
|
|
|
|
void
|
|
grn_output_uint64(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_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->msgpacker, value);
|
|
#endif
|
|
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->msgpacker, value);
|
|
#endif
|
|
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_raw(&ctx->impl->msgpacker, value_len);
|
|
msgpack_pack_raw_body(&ctx->impl->msgpacker, value, value_len);
|
|
#endif
|
|
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->msgpacker);
|
|
} else {
|
|
msgpack_pack_false(&ctx->impl->msgpacker);
|
|
}
|
|
#endif
|
|
break;
|
|
case GRN_CONTENT_NONE:
|
|
break;
|
|
}
|
|
INCR_LENGTH;
|
|
}
|
|
|
|
static inline 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->msgpacker);
|
|
#endif
|
|
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->msgpacker, dv);
|
|
#endif
|
|
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_raw(&ctx->impl->msgpacker, GRN_TEXT_LEN(&buf));
|
|
msgpack_pack_raw_body(&ctx->impl->msgpacker,
|
|
GRN_TEXT_VALUE(&buf),
|
|
GRN_TEXT_LEN(&buf));
|
|
grn_obj_close(ctx, &buf);
|
|
} else {
|
|
msgpack_pack_nil(&ctx->impl->msgpacker);
|
|
}
|
|
#endif
|
|
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);
|
|
int32_t int32_score = ri->score;
|
|
GRN_INT32_PUT(ctx, &buf, int32_score);
|
|
}
|
|
buf.header.domain = GRN_DB_INT32;
|
|
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 (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_table_header(grn_ctx *ctx, grn_obj *outbuf,
|
|
grn_content_type output_type,
|
|
grn_obj *table, grn_obj_format *format)
|
|
{
|
|
if (format->nhits != -1) {
|
|
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 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 inline int
|
|
count_used_n_codes(grn_ctx *ctx, grn_expr_code *start, grn_expr_code *target)
|
|
{
|
|
int n_codes;
|
|
int i, n_args;
|
|
grn_bool have_proc_push_code = GRN_FALSE;
|
|
grn_expr_code *sub_code;
|
|
|
|
if (start == target) {
|
|
return 0;
|
|
}
|
|
|
|
n_args = target->nargs;
|
|
if (target->op == GRN_OP_CALL) {
|
|
if (!target->value) {
|
|
have_proc_push_code = GRN_TRUE;
|
|
}
|
|
} else {
|
|
if (target->value) {
|
|
n_args--;
|
|
if (n_args == 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
n_codes = 1;
|
|
sub_code = target - 1;
|
|
for (i = 0; i < n_args; i++) {
|
|
int sub_n_codes;
|
|
sub_n_codes = count_used_n_codes(ctx, start, sub_code);
|
|
n_codes += sub_n_codes;
|
|
sub_code -= sub_n_codes;
|
|
if (sub_code < start) {
|
|
/* TODO: report error */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (have_proc_push_code) {
|
|
n_codes++;
|
|
sub_code--;
|
|
if (sub_code < start) {
|
|
/* TODO: report error */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return n_codes;
|
|
}
|
|
|
|
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_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
|
|
if (column) {
|
|
grn_id range_id = GRN_ID_NIL;
|
|
GRN_BULK_REWIND(buf);
|
|
grn_column_name_(ctx, column, buf);
|
|
grn_output_obj(ctx, outbuf, output_type, buf, NULL);
|
|
if (column->header.type == GRN_COLUMN_INDEX) {
|
|
range_id = GRN_DB_UINT32;
|
|
} else if (is_score_accessor(ctx, column)) {
|
|
range_id = GRN_DB_INT32;
|
|
}
|
|
if (range_id == GRN_ID_NIL) {
|
|
range_id = grn_obj_get_range(ctx, column);
|
|
}
|
|
if (range_id == GRN_ID_NIL) {
|
|
grn_output_cstr(ctx, outbuf, output_type, "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);
|
|
}
|
|
} else {
|
|
grn_output_cstr(ctx, outbuf, output_type, "");
|
|
grn_output_cstr(ctx, outbuf, output_type, "");
|
|
}
|
|
grn_output_array_close(ctx, outbuf, output_type);
|
|
}
|
|
|
|
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_array_open(ctx, outbuf, output_type, "COLUMN", 2);
|
|
grn_output_null(ctx, outbuf, output_type);
|
|
grn_output_null(ctx, outbuf, output_type);
|
|
grn_output_array_close(ctx, outbuf, output_type);
|
|
return;
|
|
}
|
|
|
|
switch (code_end[-1].op) {
|
|
case GRN_OP_GET_MEMBER :
|
|
if ((code_end - code) == 3) {
|
|
grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
|
|
|
|
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_output_obj(ctx, outbuf, output_type, buf, NULL);
|
|
grn_output_null(ctx, outbuf, output_type);
|
|
|
|
grn_output_array_close(ctx, outbuf, output_type);
|
|
} 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_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_array_open(ctx, outbuf, output_type, "COLUMNS", 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) {
|
|
int n_used_codes;
|
|
int code_end_offset;
|
|
|
|
n_used_codes = count_used_n_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_array_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_array_open(ctx, outbuf, output_type, "COLUMNS", ncolumns);
|
|
for (i = 0; i < ncolumns; i++) {
|
|
grn_output_table_column(ctx, outbuf, output_type, columns[i], buf);
|
|
}
|
|
grn_output_array_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_by_expression(grn_ctx *ctx, grn_obj *outbuf,
|
|
grn_content_type output_type,
|
|
grn_obj *expression)
|
|
{
|
|
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_array_open(ctx, outbuf, output_type, "HIT", 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;
|
|
int second_code_n_used_code;
|
|
second_code_offset = code - expr->codes - 1;
|
|
second_code_n_used_code =
|
|
count_used_n_codes(ctx,
|
|
expr->codes,
|
|
expr->codes + second_code_offset);
|
|
expr->codes_curr = second_code_offset - second_code_n_used_code + 1;
|
|
grn_output_table_record_by_expression(ctx, outbuf, output_type,
|
|
format->expression);
|
|
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);
|
|
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);
|
|
}
|
|
|
|
grn_output_array_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_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
|
|
for (i = 0; i < ncolumns; i++) {
|
|
grn_text_atoj(ctx, outbuf, output_type, columns[i], id);
|
|
}
|
|
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_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);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
grn_output_table(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) {
|
|
int resultset_size = 1;
|
|
/* resultset: [NHITS, (COLUMNS), (HITS)] */
|
|
if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
|
|
resultset_size++;
|
|
}
|
|
resultset_size += format->limit;
|
|
grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", resultset_size);
|
|
grn_output_table_header(ctx, outbuf, output_type, table, 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);
|
|
grn_output_array_close(ctx, outbuf, output_type);
|
|
} 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_output_array_close(ctx, outbuf, output_type);
|
|
grn_obj_unlink(ctx, column);
|
|
}
|
|
GRN_OBJ_FIN(ctx, &buf);
|
|
}
|
|
|
|
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 :
|
|
grn_output_table(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, unsigned int 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"
|
|
|
|
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_obj *expr = NULL;
|
|
grn_obj *jsonp_func = NULL;
|
|
|
|
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:
|
|
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, '(');
|
|
}
|
|
GRN_TEXT_PUTS(ctx, head, "[[");
|
|
grn_text_itoa(ctx, head, rc);
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_ftoa(ctx, head, started);
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_ftoa(ctx, head, elapsed);
|
|
if (rc != GRN_SUCCESS) {
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
|
|
if (ctx->errfunc && ctx->errfile) {
|
|
grn_obj *command;
|
|
/* TODO: output backtrace */
|
|
GRN_TEXT_PUTS(ctx, head, ",[[");
|
|
grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_itoa(ctx, head, ctx->errline);
|
|
GRN_TEXT_PUTS(ctx, head, "]");
|
|
if (file && (command = GRN_CTX_USER_DATA(ctx)->ptr)) {
|
|
GRN_TEXT_PUTS(ctx, head, ",[");
|
|
grn_text_esc(ctx, head, file, strlen(file));
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_itoa(ctx, head, line);
|
|
GRN_TEXT_PUTC(ctx, head, ',');
|
|
grn_text_esc(ctx, head, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
|
|
GRN_TEXT_PUTS(ctx, head, "]");
|
|
}
|
|
GRN_TEXT_PUTS(ctx, head, "]");
|
|
}
|
|
}
|
|
GRN_TEXT_PUTC(ctx, head, ']');
|
|
if (GRN_TEXT_LEN(body)) { GRN_TEXT_PUTC(ctx, head, ','); }
|
|
GRN_TEXT_PUTC(ctx, foot, ']');
|
|
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
|
|
{
|
|
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);
|
|
|
|
/* [HEAD, (BODY)] */
|
|
if (GRN_TEXT_LEN(body) > 0) {
|
|
msgpack_pack_array(&header_packer, 2);
|
|
} else {
|
|
msgpack_pack_array(&header_packer, 1);
|
|
}
|
|
|
|
/* HEAD := [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_raw(&header_packer, strlen(ctx->errbuf));
|
|
msgpack_pack_raw_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_raw(&header_packer, strlen(ctx->errfunc));
|
|
msgpack_pack_raw_body(&header_packer, ctx->errfunc, strlen(ctx->errfunc));
|
|
|
|
msgpack_pack_raw(&header_packer, strlen(ctx->errfile));
|
|
msgpack_pack_raw_body(&header_packer, ctx->errfile, strlen(ctx->errfile));
|
|
|
|
msgpack_pack_int(&header_packer, ctx->errline);
|
|
|
|
if (command) {
|
|
if (file) {
|
|
msgpack_pack_raw(&header_packer, strlen(file));
|
|
msgpack_pack_raw_body(&header_packer, file, strlen(file));
|
|
} else {
|
|
msgpack_pack_raw(&header_packer, 7);
|
|
msgpack_pack_raw_body(&header_packer, "(stdin)", 7);
|
|
}
|
|
|
|
msgpack_pack_int(&header_packer, line);
|
|
|
|
msgpack_pack_raw(&header_packer, GRN_TEXT_LEN(command));
|
|
msgpack_pack_raw_body(&header_packer, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
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)
|
|
{
|
|
unsigned int i;
|
|
|
|
/* TODO: REMOVE ME. If new output_columns handler is marked as stable,
|
|
this check is removed. We need more error checks. */
|
|
if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
|
|
return GRN_TRUE;
|
|
}
|
|
|
|
for (i = 0; i < output_columns_len; i++) {
|
|
switch (output_columns[i]) {
|
|
case ',' :
|
|
case '(' :
|
|
case '[' :
|
|
return GRN_FALSE;
|
|
default :
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|