Kouhei Sutou
null+****@clear*****
Mon Jan 19 16:27:18 JST 2015
Kouhei Sutou 2015-01-19 16:27:18 +0900 (Mon, 19 Jan 2015) New Revision: 0e5e39fc3ca8d9cc4972febb7a7c8d12d8d41835 https://github.com/groonga/groonga/commit/0e5e39fc3ca8d9cc4972febb7a7c8d12d8d41835 Message: Support sum in grn_table_group() You can use it in select such as: select \ --drilldown[lable].calc_type SUM \ --drilldown[lable].calc_target target_column Added files: test/command/suite/select/drilldown/labeled/calc_types/sum.expected test/command/suite/select/drilldown/labeled/calc_types/sum.test Modified files: include/groonga/groonga.h lib/db.c lib/grn_ctx.h lib/grn_db.h lib/output.c lib/proc.c Modified: include/groonga/groonga.h (+4 -0) =================================================================== --- include/groonga/groonga.h 2015-01-19 15:19:02 +0900 (4304c5d) +++ include/groonga/groonga.h 2015-01-19 16:27:18 +0900 (1673733) @@ -719,6 +719,8 @@ struct _grn_table_group_result { int limit; grn_table_group_flags flags; grn_operator op; + unsigned int max_n_subrecs; + grn_obj *calc_target; }; GRN_API grn_rc grn_table_group(grn_ctx *ctx, grn_obj *table, @@ -751,6 +753,8 @@ GRN_API unsigned int grn_table_size(grn_ctx *ctx, grn_obj *table); #define GRN_COLUMN_NAME_SCORE_LEN (sizeof(GRN_COLUMN_NAME_SCORE) - 1) #define GRN_COLUMN_NAME_NSUBRECS "_nsubrecs" #define GRN_COLUMN_NAME_NSUBRECS_LEN (sizeof(GRN_COLUMN_NAME_NSUBRECS) - 1) +#define GRN_COLUMN_NAME_SUM "_sum" +#define GRN_COLUMN_NAME_SUM_LEN (sizeof(GRN_COLUMN_NAME_SUM) - 1) GRN_API grn_obj *grn_column_create(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size, Modified: lib/db.c (+262 -29) =================================================================== --- lib/db.c 2015-01-19 15:19:02 +0900 (d2f5212) +++ lib/db.c 2015-01-19 16:27:18 +0900 (dc2c40c) @@ -1,5 +1,5 @@ /* -*- c-basic-offset: 2 -*- */ -/* Copyright(C) 2009-2014 Brazil +/* Copyright(C) 2009-2015 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -644,6 +644,7 @@ grn_proc_create(grn_ctx *ctx, const char *name, int name_size, grn_proc_type typ static void calc_rec_size(grn_obj_flags flags, uint32_t max_n_subrecs, uint32_t range_size, + uint32_t additional_value_size, uint8_t *subrec_size, uint8_t *subrec_offset, uint32_t *key_size, uint32_t *value_size) { @@ -687,6 +688,7 @@ calc_rec_size(grn_obj_flags flags, uint32_t max_n_subrecs, uint32_t range_size, } else { *value_size = range_size; } + *value_size += additional_value_size; } static void _grn_obj_remove(grn_ctx *ctx, grn_obj *obj); @@ -739,7 +741,9 @@ static grn_obj * grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name, unsigned int name_size, const char *path, grn_obj_flags flags, grn_obj *key_type, - grn_obj *value_type, uint32_t max_n_subrecs) + grn_obj *value_type, + uint32_t max_n_subrecs, + uint32_t additional_value_size) { grn_id id; grn_id domain = GRN_ID_NIL, range = GRN_ID_NIL; @@ -873,8 +877,8 @@ grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name, return NULL; } } - calc_rec_size(flags, max_n_subrecs, range_size, &subrec_size, - &subrec_offset, &key_size, &value_size); + calc_rec_size(flags, max_n_subrecs, range_size, additional_value_size, + &subrec_size, &subrec_offset, &key_size, &value_size); switch (flags & GRN_OBJ_TABLE_TYPE_MASK) { case GRN_OBJ_TABLE_HASH_KEY : res = (grn_obj *)grn_hash_create(ctx, path, key_size, value_size, flags); @@ -897,6 +901,7 @@ grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name, DB_OBJ(res)->max_n_subrecs = max_n_subrecs; DB_OBJ(res)->subrec_size = subrec_size; DB_OBJ(res)->subrec_offset = subrec_offset; + DB_OBJ(res)->flags.group = 0; if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) { _grn_obj_remove(ctx, res); res = NULL; @@ -915,7 +920,8 @@ grn_table_create(grn_ctx *ctx, const char *name, unsigned int name_size, grn_obj *res; GRN_API_ENTER; res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path, - flags, key_type, value_type, 0); + flags, key_type, value_type, + 0, 0); GRN_API_RETURN(res); } @@ -936,7 +942,7 @@ grn_table_create_for_group(grn_ctx *ctx, const char *name, GRN_OBJ_WITH_SUBREC| GRN_OBJ_UNIT_USERDEF_DOCUMENT, key_type, value_type, - max_n_subrecs); + max_n_subrecs, 0); grn_obj_unlink(ctx, key_type); } } else { @@ -946,7 +952,7 @@ grn_table_create_for_group(grn_ctx *ctx, const char *name, GRN_OBJ_WITH_SUBREC| GRN_OBJ_UNIT_USERDEF_DOCUMENT, NULL, value_type, - max_n_subrecs); + max_n_subrecs, 0); } GRN_API_RETURN(res); } @@ -3044,9 +3050,91 @@ grn_obj_search(grn_ctx *ctx, grn_obj *obj, grn_obj *query, #define GRN_TABLE_GROUP_FILTER_PREFIX 0 #define GRN_TABLE_GROUP_FILTER_SUFFIX (1L<<2) +inline static void +grn_table_group_add_subrec(grn_ctx *ctx, + grn_obj *table, + grn_rset_recinfo *ri, int score, + grn_rset_posinfo *pi, int dir, + grn_obj *calc_target) +{ + grn_table_group_flags flags; + byte *values; + grn_obj value; + grn_obj value_int64; + grn_obj value_float; + + if (!(DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC)) { + return; + } + + grn_table_add_subrec_inline(table, ri, score, pi, dir); + + flags = DB_OBJ(table)->flags.group; + + if (!(flags & (GRN_TABLE_GROUP_CALC_MAX | + GRN_TABLE_GROUP_CALC_MIN | + GRN_TABLE_GROUP_CALC_SUM | + GRN_TABLE_GROUP_CALC_AVG))) { + return; + } + + values = (((byte *)ri->subrecs) + + GRN_RSET_SUBRECS_SIZE(DB_OBJ(table)->subrec_size, + DB_OBJ(table)->max_n_subrecs)); + + GRN_VOID_INIT(&value); + GRN_INT64_INIT(&value_int64, 0); + GRN_FLOAT_INIT(&value_float, 0); + + grn_obj_get_value(ctx, calc_target, pi->rid, &value); + if (flags & (GRN_TABLE_GROUP_CALC_MAX | + GRN_TABLE_GROUP_CALC_MIN | + GRN_TABLE_GROUP_CALC_SUM)) { + grn_obj_cast(ctx, &value, &value_int64, GRN_FALSE); + } + if (flags & GRN_TABLE_GROUP_CALC_AVG) { + grn_obj_cast(ctx, &value, &value_float, GRN_FALSE); + } + + if (flags & GRN_TABLE_GROUP_CALC_MAX) { + int64_t current_max = *((int64_t *)values); + int64_t value_raw = GRN_INT64_VALUE(&value_int64); + if (ri->n_subrecs == 1 || value_raw > current_max) { + *((int64_t *)values) = value_raw; + } + values += GRN_RSET_MAX_SIZE; + } + if (flags & GRN_TABLE_GROUP_CALC_MIN) { + int64_t current_min = *((int64_t *)values); + int64_t value_raw = GRN_INT64_VALUE(&value_int64); + if (ri->n_subrecs == 1 || value_raw < current_min) { + *((int64_t *)values) = value_raw; + } + values += GRN_RSET_MIN_SIZE; + } + if (flags & GRN_TABLE_GROUP_CALC_SUM) { + int64_t value_raw = GRN_INT64_VALUE(&value_int64); + *((int64_t *)values) += value_raw; + values += GRN_RSET_SUM_SIZE; + } + if (flags & GRN_TABLE_GROUP_CALC_AVG) { + double current_average = *((double *)values); + int64_t value_raw = GRN_FLOAT_VALUE(&value_float); + *((double *)values) += (value_raw - current_average) / ri->n_subrecs; + values += GRN_RSET_AVG_SIZE; + } + + GRN_OBJ_FIN(ctx, &value_float); + GRN_OBJ_FIN(ctx, &value_int64); + GRN_OBJ_FIN(ctx, &value); +} + static grn_bool -accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key, grn_obj *res) +accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key, + grn_table_group_result *result) { + grn_obj *res = result->table; + grn_obj *calc_target = result->calc_target; if (key->header.type == GRN_ACCESSOR) { grn_accessor *a = (grn_accessor *)key; if (a->action == GRN_ACCESSOR_GET_KEY && @@ -3081,8 +3169,10 @@ accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key, grn_obj *res } if ((!idp || *((grn_id *)v)) && grn_table_add_v_inline(ctx, res, v, element_size, &value, NULL)) { - grn_table_add_subrec_inline(res, value, ri ? ri->score : 0, - (grn_rset_posinfo *)&id, 0); + grn_table_group_add_subrec(ctx, res, value, + ri ? ri->score : 0, + (grn_rset_posinfo *)&id, 0, + calc_target); } } GRN_RA_CACHE_FIN(ra, &cache); @@ -3107,8 +3197,10 @@ accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key, grn_obj *res while (len) { if ((*v != GRN_ID_NIL) && grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) { - grn_table_add_subrec_inline(res, value, ri ? ri->score : 0, - (grn_rset_posinfo *)&id, 0); + grn_table_group_add_subrec(ctx, res, value, + ri ? ri->score : 0, + (grn_rset_posinfo *)&id, 0, + calc_target); } v++; len -= sizeof(grn_id); @@ -3134,10 +3226,12 @@ accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key, grn_obj *res static void grn_table_group_single_key_records(grn_ctx *ctx, grn_obj *table, - grn_obj *key, grn_obj *res) + grn_obj *key, grn_table_group_result *result) { grn_obj bulk; grn_table_cursor *tc; + grn_obj *res = result->table; + grn_obj *calc_target = result->calc_target; GRN_TEXT_INIT(&bulk, 0); if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) { @@ -3162,8 +3256,10 @@ grn_table_group_single_key_records(grn_ctx *ctx, grn_obj *table, if ((*v != GRN_ID_NIL) && grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) { - grn_table_add_subrec_inline(res, value, ri ? ri->score : 0, - (grn_rset_posinfo *)&id, 0); + grn_table_group_add_subrec(ctx, res, value, + ri ? ri->score : 0, + (grn_rset_posinfo *)&id, 0, + calc_target); } v++; } @@ -3193,8 +3289,10 @@ grn_table_group_single_key_records(grn_ctx *ctx, grn_obj *table, grn_table_add_v_inline(ctx, res, GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk), &value, NULL)) { - grn_table_add_subrec_inline(res, value, ri ? ri->score : 0, - (grn_rset_posinfo *)&id, 0); + grn_table_group_add_subrec(ctx, res, value, + ri ? ri->score : 0, + (grn_rset_posinfo *)&id, 0, + calc_target); } } break; @@ -3357,8 +3455,10 @@ grn_table_group_multi_keys_add_record(grn_ctx *ctx, if (grn_table_add_v_inline(ctx, rp->table, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk), &value, NULL)) { - grn_table_add_subrec_inline(rp->table, value, ri ? ri->score : 0, - (grn_rset_posinfo *)&id, 0); + grn_table_group_add_subrec(ctx, rp->table, value, + ri ? ri->score : 0, + (grn_rset_posinfo *)&id, 0, + rp->calc_target); } } } @@ -3588,14 +3688,47 @@ grn_table_group(grn_ctx *ctx, grn_obj *table, } for (r = 0, rp = results; r < n_results; r++, rp++) { if (!rp->table) { - ERR(GRN_INVALID_ARGUMENT, "table missing in (%d)", r); - goto exit; + grn_obj_flags flags; + grn_obj *key_type = NULL; + uint32_t additional_value_size = 0; + + flags = GRN_TABLE_HASH_KEY| + GRN_OBJ_WITH_SUBREC| + GRN_OBJ_UNIT_USERDEF_DOCUMENT; + if (n_keys == 1) { + key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, keys[0].key)); + } else { + flags |= GRN_OBJ_KEY_VAR_SIZE; + } + if (rp->flags & GRN_TABLE_GROUP_CALC_MAX) { + additional_value_size += GRN_RSET_MAX_SIZE; + } + if (rp->flags & GRN_TABLE_GROUP_CALC_MIN) { + additional_value_size += GRN_RSET_MIN_SIZE; + } + if (rp->flags & GRN_TABLE_GROUP_CALC_SUM) { + additional_value_size += GRN_RSET_SUM_SIZE; + } + if (rp->flags & GRN_TABLE_GROUP_CALC_AVG) { + additional_value_size += GRN_RSET_AVG_SIZE; + } + rp->table = grn_table_create_with_max_n_subrecs(ctx, NULL, 0, NULL, + flags, + key_type, table, + rp->max_n_subrecs, + additional_value_size); + if (key_type) { + grn_obj_unlink(ctx, key_type); + } + if (!rp->table) { + goto exit; + } + DB_OBJ(rp->table)->flags.group = rp->flags; } } if (n_keys == 1 && n_results == 1) { - if (!accelerated_table_group(ctx, table, keys->key, results->table)) { - grn_table_group_single_key_records(ctx, table, - keys->key, results->table); + if (!accelerated_table_group(ctx, table, keys->key, results)) { + grn_table_group_single_key_records(ctx, table, keys->key, results); } } else { grn_bool have_vector = GRN_FALSE; @@ -4617,6 +4750,7 @@ grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int case GRN_ACCESSOR_GET_VALUE : case GRN_ACCESSOR_GET_SCORE : case GRN_ACCESSOR_GET_NSUBRECS : + case GRN_ACCESSOR_GET_SUM : obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range); break; case GRN_ACCESSOR_GET_COLUMN_VALUE : @@ -4785,11 +4919,9 @@ grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int } } break; - case 's' : /* score */ - if (len != GRN_COLUMN_NAME_SCORE_LEN || - memcmp(name, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN)) { - goto exit; - } + case 's' : /* score, sum */ + if (len == GRN_COLUMN_NAME_SCORE_LEN && + memcmp(name, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) { for (rp = &res; !done; rp = &(*rp)->next) { *rp = accessor_new(ctx); (*rp)->obj = obj; @@ -4822,6 +4954,45 @@ grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int } } } + } else if (len == GRN_COLUMN_NAME_SUM_LEN && + memcmp(name, + GRN_COLUMN_NAME_SUM, + GRN_COLUMN_NAME_SUM_LEN) == 0) { + for (rp = &res; !done; rp = &(*rp)->next) { + *rp = accessor_new(ctx); + (*rp)->obj = obj; + if (GRN_TABLE_IS_GROUPED(obj)) { + (*rp)->action = GRN_ACCESSOR_GET_SUM; + done++; + } else { + switch (obj->header.type) { + case GRN_TABLE_PAT_KEY : + case GRN_TABLE_DAT_KEY : + case GRN_TABLE_HASH_KEY : + (*rp)->action = GRN_ACCESSOR_GET_KEY; + break; + case GRN_TABLE_NO_KEY : + if (obj->header.domain) { + (*rp)->action = GRN_ACCESSOR_GET_VALUE; + break; + } + /* fallthru */ + default : + /* lookup failed */ + grn_obj_close(ctx, (grn_obj *)res); + res = NULL; + goto exit; + } + if (!(obj = grn_ctx_at(ctx, obj->header.domain))) { + grn_obj_close(ctx, (grn_obj *)res); + res = NULL; + goto exit; + } + } + } + } else { + goto exit; + } break; case 'n' : /* nsubrecs */ if (len != GRN_COLUMN_NAME_NSUBRECS_LEN || @@ -5001,6 +5172,9 @@ grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj, case GRN_ACCESSOR_GET_NSUBRECS : *range_id = GRN_DB_INT32; break; + case GRN_ACCESSOR_GET_SUM : + *range_id = GRN_DB_INT64; + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : grn_obj_get_range_info(ctx, a->obj, range_id, range_flags); break; @@ -5038,6 +5212,7 @@ grn_obj_is_persistent(grn_ctx *ctx, grn_obj *obj) switch (a->action) { case GRN_ACCESSOR_GET_SCORE : case GRN_ACCESSOR_GET_NSUBRECS : + case GRN_ACCESSOR_GET_SUM : res = 0; break; case GRN_ACCESSOR_GET_ID : @@ -5524,6 +5699,20 @@ grn_accessor_get_value_(grn_ctx *ctx, grn_accessor *a, grn_id id, uint32_t *size *size = sizeof(int); } break; + case GRN_ACCESSOR_GET_SUM : + if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) { + value = ((const char *)(((grn_rset_recinfo *)value)->subrecs) + + GRN_RSET_SUBRECS_SIZE(DB_OBJ(a->obj)->subrec_size, + DB_OBJ(a->obj)->max_n_subrecs)); + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MAX) { + value += GRN_RSET_MAX_SIZE; + } + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MIN) { + value += GRN_RSET_MIN_SIZE; + } + *size = GRN_RSET_SUM_SIZE; + } + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : /* todo : support vector */ value = grn_obj_get_value_(ctx, a->obj, id, size); @@ -5617,6 +5806,25 @@ grn_accessor_get_value(grn_ctx *ctx, grn_accessor *a, grn_id id, grn_obj *value) } value->header.domain = GRN_DB_INT32; break; + case GRN_ACCESSOR_GET_SUM : + if (id) { + grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs); + byte *values; + values = ((char *)(ri->subrecs) + + GRN_RSET_SUBRECS_SIZE(DB_OBJ(a->obj)->subrec_size, + DB_OBJ(a->obj)->max_n_subrecs)); + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MAX) { + values += GRN_RSET_MAX_SIZE; + } + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MIN) { + values += GRN_RSET_MIN_SIZE; + } + GRN_INT64_PUT(ctx, value, *((int64_t *)values)); + } else { + GRN_INT64_PUT(ctx, value, 0); + } + value->header.domain = GRN_DB_INT64; + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : /* todo : support vector */ grn_obj_get_value(ctx, a->obj, id, value); @@ -5705,6 +5913,23 @@ grn_accessor_set_value(grn_ctx *ctx, grn_accessor *a, grn_id id, vp = &ri->n_subrecs; } break; + case GRN_ACCESSOR_GET_SUM : + grn_obj_get_value(ctx, a->obj, id, &buf); + { + grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf); + char *values; + values = ((char *)(ri->subrecs) + + GRN_RSET_SUBRECS_SIZE(DB_OBJ(a->obj)->subrec_size, + DB_OBJ(a->obj)->max_n_subrecs)); + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MAX) { + values += GRN_RSET_MAX_SIZE; + } + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MIN) { + values += GRN_RSET_MIN_SIZE; + } + vp = values; + } + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : /* todo : support vector */ if (a->next) { @@ -9030,6 +9255,9 @@ grn_column_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size) case GRN_ACCESSOR_GET_NSUBRECS : name = GRN_COLUMN_NAME_NSUBRECS; break; + case GRN_ACCESSOR_GET_SUM : + name = GRN_COLUMN_NAME_SUM; + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : case GRN_ACCESSOR_GET_DB_OBJ : case GRN_ACCESSOR_LOOKUP : @@ -9093,6 +9321,11 @@ grn_column_name_(grn_ctx *ctx, grn_obj *obj, grn_obj *buf) GRN_COLUMN_NAME_NSUBRECS, GRN_COLUMN_NAME_NSUBRECS_LEN); break; + case GRN_ACCESSOR_GET_SUM : + GRN_TEXT_PUT(ctx, buf, + GRN_COLUMN_NAME_SUM, + GRN_COLUMN_NAME_SUM_LEN); + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : grn_column_name_(ctx, a->obj, buf); if (a->next) { GRN_TEXT_PUTC(ctx, buf, '.'); } Modified: lib/grn_ctx.h (+3 -0) =================================================================== --- lib/grn_ctx.h 2015-01-19 15:19:02 +0900 (391f72b) +++ lib/grn_ctx.h 2015-01-19 16:27:18 +0900 (dbf461e) @@ -558,6 +558,9 @@ typedef struct { uint8_t subrec_offset; uint8_t record_unit; uint8_t subrec_unit; + union { + grn_table_group_flags group; + } flags; // grn_obj_flags flags; } grn_db_obj; Modified: lib/grn_db.h (+9 -0) =================================================================== --- lib/grn_db.h 2015-01-19 15:19:02 +0900 (da4704f) +++ lib/grn_db.h 2015-01-19 16:27:18 +0900 (3b38691) @@ -47,6 +47,12 @@ typedef struct { #define GRN_RSET_UTIL_BIT (0x80000000) +#define GRN_RSET_N_SUBRECS_SIZE (sizeof(int)) +#define GRN_RSET_MAX_SIZE (sizeof(int64_t)) +#define GRN_RSET_MIN_SIZE (sizeof(int64_t)) +#define GRN_RSET_SUM_SIZE (sizeof(int64_t)) +#define GRN_RSET_AVG_SIZE (sizeof(double)) + #define GRN_RSET_SCORE_SIZE (sizeof(int)) #define GRN_RSET_N_SUBRECS(ri) ((ri)->n_subrecs & ~GRN_RSET_UTIL_BIT) @@ -58,6 +64,8 @@ typedef struct { ((int *)((byte *)subrecs + n * GRN_RSET_SUBREC_SIZE(size))) #define GRN_RSET_SUBRECS_COPY(subrecs,size,n,src) \ (memcpy(GRN_RSET_SUBRECS_NTH(subrecs, size, n), src, GRN_RSET_SUBREC_SIZE(size))) +#define GRN_RSET_SUBRECS_SIZE(subrec_size,n) \ + (GRN_RSET_SUBREC_SIZE(subrec_size) * n) #define GRN_JSON_LOAD_OPEN_BRACKET 0x40000000 #define GRN_JSON_LOAD_OPEN_BRACE 0x40000001 @@ -246,6 +254,7 @@ enum { GRN_ACCESSOR_GET_VALUE, GRN_ACCESSOR_GET_SCORE, GRN_ACCESSOR_GET_NSUBRECS, + GRN_ACCESSOR_GET_SUM, GRN_ACCESSOR_GET_COLUMN_VALUE, GRN_ACCESSOR_GET_DB_OBJ, GRN_ACCESSOR_LOOKUP, Modified: lib/output.c (+17 -0) =================================================================== --- lib/output.c 2015-01-19 15:19:02 +0900 (1674977) +++ lib/output.c 2015-01-19 16:27:18 +0900 (97a9ce2) @@ -533,6 +533,23 @@ grn_text_atoj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, } buf.header.domain = GRN_DB_INT32; break; + case GRN_ACCESSOR_GET_SUM : + { + grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs); + byte *values; + values = ((char *)(ri->subrecs) + + GRN_RSET_SUBRECS_SIZE(DB_OBJ(a->obj)->subrec_size, + DB_OBJ(a->obj)->max_n_subrecs)); + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MAX) { + values += GRN_RSET_MAX_SIZE; + } + if (DB_OBJ(a->obj)->flags.group & GRN_TABLE_GROUP_CALC_MIN) { + values += GRN_RSET_MIN_SIZE; + } + GRN_INT64_PUT(ctx, &buf, *((int64_t *)values)); + } + buf.header.domain = GRN_DB_INT64; + break; case GRN_ACCESSOR_GET_COLUMN_VALUE : if ((a->obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) { if (a->next) { Modified: lib/proc.c (+89 -18) =================================================================== --- lib/proc.c 2015-01-19 15:19:02 +0900 (d6b42e9) +++ lib/proc.c 2015-01-19 16:27:18 +0900 (456527e) @@ -1,6 +1,6 @@ /* -*- c-basic-offset: 2 -*- */ /* - Copyright(C) 2009-2014 Brazil + Copyright(C) 2009-2015 Brazil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -584,8 +584,52 @@ typedef struct { unsigned int output_columns_len; int offset; int limit; + grn_table_group_flags calc_types; + const char *calc_target_name; + unsigned int calc_target_name_len; } drilldown_info; +static grn_table_group_flags +grn_parse_table_group_calc_types(grn_ctx *ctx, + const char *calc_types, + unsigned int calc_types_len) +{ + grn_table_group_flags flags = 0; + const char *calc_types_end = calc_types + calc_types_len; + + while (calc_types < calc_types_end) { + if (*calc_types == '|' || *calc_types == ' ') { + calc_types += 1; + continue; + } + +#define CHECK_TABLE_GROUP_CALC_TYPE(name)\ + if (((calc_types_end - calc_types) >= (sizeof(#name) - 1)) &&\ + (!memcmp(calc_types, #name, sizeof(#name) - 1))) {\ + flags |= GRN_TABLE_GROUP_CALC_ ## name;\ + calc_types += sizeof(#name);\ + continue;\ + } + + CHECK_TABLE_GROUP_CALC_TYPE(COUNT); + CHECK_TABLE_GROUP_CALC_TYPE(MAX); + CHECK_TABLE_GROUP_CALC_TYPE(MIN); + CHECK_TABLE_GROUP_CALC_TYPE(SUM); + CHECK_TABLE_GROUP_CALC_TYPE(AVG); + +#define GRN_TABLE_GROUP_CALC_NONE 0 + CHECK_TABLE_GROUP_CALC_TYPE(NONE); +#undef GRN_TABLE_GROUP_CALC_NONE + + ERR(GRN_INVALID_ARGUMENT, "invalid table group calc type: <%.*s>", + (int)(calc_types_end - calc_types), calc_types); + return 0; +#undef CHECK_TABLE_GROUP_CALC_TYPE + } + + return flags; +} + static void drilldown_info_fill(grn_ctx *ctx, drilldown_info *drilldown, @@ -593,7 +637,9 @@ drilldown_info_fill(grn_ctx *ctx, grn_obj *sortby, grn_obj *output_columns, grn_obj *offset, - grn_obj *limit) + grn_obj *limit, + grn_obj *calc_types, + grn_obj *calc_target) { if (keys) { drilldown->keys = GRN_TEXT_VALUE(keys); @@ -636,6 +682,23 @@ drilldown_info_fill(grn_ctx *ctx, } else { drilldown->limit = DEFAULT_DRILLDOWN_LIMIT; } + + if (calc_types && GRN_TEXT_LEN(calc_types)) { + drilldown->calc_types = + grn_parse_table_group_calc_types(ctx, + GRN_TEXT_VALUE(calc_types), + GRN_TEXT_LEN(calc_types)); + } else { + drilldown->calc_types = 0; + } + + if (calc_target && GRN_TEXT_LEN(calc_target)) { + drilldown->calc_target_name = GRN_TEXT_VALUE(calc_target); + drilldown->calc_target_name_len = GRN_TEXT_LEN(calc_target); + } else { + drilldown->calc_target_name = NULL; + drilldown->calc_target_name_len = 0; + } } static void @@ -725,7 +788,7 @@ grn_select_drilldowns(grn_ctx *ctx, grn_obj *table, int offset; int limit; grn_table_group_result result = { - NULL, 0, 0, 1, GRN_TABLE_GROUP_CALC_COUNT, 0 + NULL, 0, 0, 1, GRN_TABLE_GROUP_CALC_COUNT, 0, 0, NULL }; keys = grn_table_sort_key_from_str(ctx, @@ -736,23 +799,22 @@ grn_select_drilldowns(grn_ctx *ctx, grn_obj *table, continue; } - if (n_keys == 1) { - result.table = grn_table_create_for_group(ctx, NULL, 0, NULL, - keys[0].key, table, 0); - } else { - result.table = grn_table_create_for_group(ctx, NULL, 0, NULL, - NULL, table, 1); - } - - if (!result.table) { - grn_table_sort_key_close(ctx, keys, n_keys); - continue; - } - GRN_OUTPUT_STR(drilldown->label, drilldown->label_len); result.key_begin = 0; result.key_end = n_keys - 1; + if (n_keys > 1) { + result.max_n_subrecs = 1; + } + if (drilldown->calc_target_name) { + result.calc_target = grn_obj_column(ctx, table, + drilldown->calc_target_name, + drilldown->calc_target_name_len); + } + if (result.calc_target) { + result.flags |= drilldown->calc_types; + } + grn_table_group(ctx, table, keys, n_keys, &result, 1); n_hits = grn_table_size(ctx, result.table); @@ -790,6 +852,9 @@ grn_select_drilldowns(grn_ctx *ctx, grn_obj *table, } grn_table_sort_key_close(ctx, keys, n_keys); + if (result.calc_target) { + grn_obj_unlink(ctx, result.calc_target); + } grn_obj_unlink(ctx, result.table); GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE, @@ -1191,7 +1256,8 @@ proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data) drilldown->label = NULL; drilldown->label_len = 0; drilldown_info_fill(ctx, drilldown, - VAR(9), VAR(10), VAR(11), VAR(12), VAR(13)); + VAR(9), VAR(10), VAR(11), VAR(12), VAR(13), + NULL, NULL); n_drilldowns++; } else { unsigned int i; @@ -1207,6 +1273,8 @@ proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data) grn_obj *output_columns; grn_obj *offset; grn_obj *limit; + grn_obj *calc_types; + grn_obj *calc_target; label_len = grn_vector_get_element(ctx, &drilldown_labels, i, &label, NULL, NULL); @@ -1223,11 +1291,14 @@ proc_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data) GET_VAR(output_columns); GET_VAR(offset); GET_VAR(limit); + GET_VAR(calc_types); + GET_VAR(calc_target); #undef GET_VAR drilldown_info_fill(ctx, drilldown, - keys, sortby, output_columns, offset, limit); + keys, sortby, output_columns, offset, limit, + calc_types, calc_target); } } if (grn_select(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)), Added: test/command/suite/select/drilldown/labeled/calc_types/sum.expected (+78 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/drilldown/labeled/calc_types/sum.expected 2015-01-19 16:27:18 +0900 (72e8f12) @@ -0,0 +1,78 @@ +table_create Tags TABLE_PAT_KEY ShortText +[[0,0.0,0.0],true] +table_create Memos TABLE_HASH_KEY ShortText +[[0,0.0,0.0],true] +column_create Memos tag COLUMN_SCALAR Tags +[[0,0.0,0.0],true] +column_create Memos value COLUMN_SCALAR Int64 +[[0,0.0,0.0],true] +load --table Memos +[ +{"_key": "Groonga is fast!", "tag": "Groonga", "value": 10}, +{"_key": "Mroonga is fast!", "tag": "Mroonga", "value": 20}, +{"_key": "Groonga sticker!", "tag": "Groonga", "value": 40}, +{"_key": "Rroonga is fast!", "tag": "Rroonga", "value": 80} +] +[[0,0.0,0.0],4] +select Memos --limit 0 --drilldown[tag].keys tag --drilldown[tag].calc_types SUM --drilldown[tag].calc_target value --drilldown[tag].output_columns _key,_sum +[ + [ + 0, + 0.0, + 0.0 + ], + [ + [ + [ + 4 + ], + [ + [ + "_id", + "UInt32" + ], + [ + "_key", + "ShortText" + ], + [ + "tag", + "Tags" + ], + [ + "value", + "Int64" + ] + ] + ], + { + "tag": [ + [ + 3 + ], + [ + [ + "_key", + "ShortText" + ], + [ + "_sum", + "Int64" + ] + ], + [ + "Groonga", + 50 + ], + [ + "Mroonga", + 20 + ], + [ + "Rroonga", + 80 + ] + ] + } + ] +] Added: test/command/suite/select/drilldown/labeled/calc_types/sum.test (+20 -0) 100644 =================================================================== --- /dev/null +++ test/command/suite/select/drilldown/labeled/calc_types/sum.test 2015-01-19 16:27:18 +0900 (c0ab9e5) @@ -0,0 +1,20 @@ +table_create Tags TABLE_PAT_KEY ShortText + +table_create Memos TABLE_HASH_KEY ShortText +column_create Memos tag COLUMN_SCALAR Tags +column_create Memos value COLUMN_SCALAR Int64 + +load --table Memos +[ +{"_key": "Groonga is fast!", "tag": "Groonga", "value": 10}, +{"_key": "Mroonga is fast!", "tag": "Mroonga", "value": 20}, +{"_key": "Groonga sticker!", "tag": "Groonga", "value": 40}, +{"_key": "Rroonga is fast!", "tag": "Rroonga", "value": 80} +] + +select Memos \ + --limit 0 \ + --drilldown[tag].keys tag \ + --drilldown[tag].calc_types SUM \ + --drilldown[tag].calc_target value \ + --drilldown[tag].output_columns _key,_sum -------------- next part -------------- HTML����������������������������...Download