[Groonga-commit] groonga/groonga at 0e5e39f [master] Support sum in grn_table_group()

Back to archive index

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 



More information about the Groonga-commit mailing list
Back to archive index