"Fossies" - the Fresh Open Source Software Archive

Member "groonga-10.0.8/lib/accessor.c" (29 Oct 2020, 28493 Bytes) of package /linux/misc/groonga-10.0.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "accessor.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 10.0.7_vs_10.0.8.

    1 /* -*- c-basic-offset: 2 -*- */
    2 /*
    3   Copyright(C) 2018  Brazil
    4   Copyright(C) 2019-2020  Sutou Kouhei <kou@clear-code.com>
    5 
    6   This library is free software; you can redistribute it and/or
    7   modify it under the terms of the GNU Lesser General Public
    8   License version 2.1 as published by the Free Software Foundation.
    9 
   10   This library is distributed in the hope that it will be useful,
   11   but WITHOUT ANY WARRANTY; without even the implied warranty of
   12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13   Lesser General Public License for more details.
   14 
   15   You should have received a copy of the GNU Lesser General Public
   16   License along with this library; if not, write to the Free Software
   17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
   18 */
   19 
   20 #include "grn.h"
   21 #include "grn_db.h"
   22 #include "grn_ii.h"
   23 #include "grn_report.h"
   24 #include "grn_posting.h"
   25 
   26 static grn_rc
   27 grn_accessor_resolve_one_index_column(grn_ctx *ctx, grn_accessor *accessor,
   28                                       grn_obj *current_res, grn_obj **next_res)
   29 {
   30   grn_rc rc = GRN_SUCCESS;
   31   grn_obj *column = NULL;
   32   grn_id next_res_domain_id = GRN_ID_NIL;
   33 
   34   {
   35     grn_obj *index;
   36     grn_obj source_ids;
   37     unsigned int i, n_ids;
   38 
   39     index = accessor->obj;
   40     next_res_domain_id = index->header.domain;
   41 
   42     GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
   43     grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
   44     n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
   45     for (i = 0; i < n_ids; i++) {
   46       grn_id source_id;
   47       grn_obj *source;
   48 
   49       source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
   50       source = grn_ctx_at(ctx, source_id);
   51       if (DB_OBJ(source)->range == next_res_domain_id) {
   52         column = source;
   53         break;
   54       }
   55       grn_obj_unlink(ctx, source);
   56     }
   57 
   58     if (!column) {
   59       return GRN_INVALID_ARGUMENT;
   60     }
   61   }
   62 
   63   {
   64     grn_rc rc;
   65     grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
   66     *next_res = grn_table_create(ctx, NULL, 0, NULL,
   67                                  GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
   68                                  next_res_domain, NULL);
   69     rc = ctx->rc;
   70     grn_obj_unlink(ctx, next_res_domain);
   71     if (!*next_res) {
   72       return rc;
   73     }
   74   }
   75 
   76   {
   77     grn_obj_flags column_value_flags = 0;
   78     grn_obj column_value;
   79     grn_posting_internal add_posting = {0};
   80 
   81     if (column->header.type == GRN_COLUMN_VAR_SIZE) {
   82       column_value_flags |= GRN_OBJ_VECTOR;
   83     }
   84     GRN_VALUE_FIX_SIZE_INIT(&column_value,
   85                             column_value_flags,
   86                             next_res_domain_id);
   87 
   88     add_posting.sid = 0;
   89     add_posting.pos = 0;
   90     add_posting.weight_float = 0;
   91 
   92     GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
   93       void *key;
   94       void *value;
   95       grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
   96 
   97       grn_id *tid = key;
   98       grn_rset_recinfo *recinfo = value;
   99 
  100       add_posting.weight_float = recinfo->score;
  101 
  102       GRN_BULK_REWIND(&column_value);
  103       grn_obj_get_value(ctx, column, *tid, &column_value);
  104 
  105       int n_elements = GRN_BULK_VSIZE(&column_value) / sizeof(grn_id);
  106       for (int i = 0; i < n_elements; i++) {
  107         add_posting.rid = GRN_RECORD_VALUE_AT(&column_value, i);
  108         rc = grn_ii_posting_add_float(ctx,
  109                                       (grn_posting *)(&add_posting),
  110                                       (grn_hash *)*next_res,
  111                                       GRN_OP_OR);
  112         if (rc != GRN_SUCCESS) {
  113           break;
  114         }
  115       }
  116       if (rc != GRN_SUCCESS) {
  117         break;
  118       }
  119     } GRN_HASH_EACH_END(ctx, cursor);
  120 
  121     GRN_OBJ_FIN(ctx, &column_value);
  122   }
  123 
  124   if (rc != GRN_SUCCESS) {
  125     grn_obj_unlink(ctx, *next_res);
  126   }
  127 
  128   return rc;
  129 }
  130 
  131 static grn_rc
  132 grn_accessor_resolve_one_table(grn_ctx *ctx, grn_accessor *accessor,
  133                                grn_obj *current_res, grn_obj **next_res)
  134 {
  135   grn_rc rc = GRN_SUCCESS;
  136   grn_obj *table;
  137 
  138   table = accessor->obj;
  139   *next_res = grn_table_create(ctx, NULL, 0, NULL,
  140                                GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
  141                                table, NULL);
  142   if (!*next_res) {
  143     return ctx->rc;
  144   }
  145 
  146   grn_report_table(ctx,
  147                    "[accessor][resolve]",
  148                    "",
  149                    table);
  150 
  151   {
  152     grn_posting_internal posting = {0};
  153 
  154     GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
  155       void *key;
  156       void *value;
  157       grn_id *record_id;
  158       grn_rset_recinfo *recinfo;
  159       grn_id next_record_id;
  160 
  161       grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
  162       record_id = key;
  163       recinfo = value;
  164       next_record_id = grn_table_get(ctx,
  165                                      table,
  166                                      record_id,
  167                                      sizeof(grn_id));
  168       if (next_record_id == GRN_ID_NIL) {
  169         continue;
  170       }
  171 
  172       posting.rid = next_record_id;
  173       posting.weight_float = recinfo->score;
  174       rc = grn_ii_posting_add_float(ctx,
  175                                     (grn_posting *)(&posting),
  176                                     (grn_hash *)*next_res,
  177                                     GRN_OP_OR);
  178       if (rc != GRN_SUCCESS) {
  179         break;
  180       }
  181     } GRN_HASH_EACH_END(ctx, cursor);
  182   }
  183 
  184   if (rc != GRN_SUCCESS) {
  185     grn_obj_unlink(ctx, *next_res);
  186   }
  187 
  188   return rc;
  189 }
  190 
  191 static grn_rc
  192 grn_accessor_resolve_one_data_column_sequential(grn_ctx *ctx,
  193                                                 grn_accessor *accessor,
  194                                                 grn_obj *current_res,
  195                                                 grn_obj **next_res)
  196 {
  197   grn_obj *column = accessor->obj;
  198   grn_report_column(ctx,
  199                     "[accessor][resolve][data-column]",
  200                     "",
  201                     column);
  202 
  203   grn_id next_res_domain_id = column->header.domain;
  204   grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
  205   *next_res = grn_table_create(ctx, NULL, 0, NULL,
  206                                GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
  207                                next_res_domain, NULL);
  208   if (!*next_res) {
  209     return ctx->rc;
  210   }
  211 
  212   {
  213     grn_obj value;
  214     GRN_VOID_INIT(&value);
  215     GRN_TABLE_EACH_BEGIN(ctx, next_res_domain, cursor, id) {
  216       GRN_BULK_REWIND(&value);
  217       grn_obj_get_value(ctx, column, id, &value);
  218       bool found = false;
  219       switch (value.header.type) {
  220       case GRN_BULK :
  221         found = (grn_table_get(ctx,
  222                                current_res,
  223                                GRN_BULK_HEAD(&value),
  224                                GRN_BULK_VSIZE(&value)) != GRN_ID_NIL);
  225 
  226         break;
  227       case GRN_UVECTOR :
  228         {
  229           size_t i, n_elements;
  230           n_elements = GRN_BULK_VSIZE(&value) / sizeof(grn_id);
  231           for (i = 0; i < n_elements; i++) {
  232             grn_id id = GRN_RECORD_VALUE_AT(&value, i);
  233             found = (grn_table_get(ctx,
  234                                    current_res,
  235                                    &id,
  236                                    sizeof(grn_id)) != GRN_ID_NIL);
  237             if (found) {
  238               break;
  239             }
  240           }
  241         }
  242         break;
  243       default :
  244         break;
  245       }
  246       if (found) {
  247         grn_posting_internal posting = {0};
  248         posting.rid = id;
  249         grn_ii_posting_add_float(ctx,
  250                                  (grn_posting *)(&posting),
  251                                  (grn_hash *)*next_res,
  252                                  GRN_OP_OR);
  253       }
  254     } GRN_TABLE_EACH_END(ctx, cursor);
  255     GRN_OBJ_FIN(ctx, &value);
  256   }
  257 
  258   return ctx->rc;
  259 }
  260 
  261 static grn_rc
  262 grn_accessor_resolve_one_data_column_index(grn_ctx *ctx,
  263                                            grn_index_datum *index_datum,
  264                                            grn_obj *current_res,
  265                                            grn_obj **next_res)
  266 {
  267   if (index_datum->index->header.domain != current_res->header.domain) {
  268     char index_name[GRN_TABLE_MAX_KEY_SIZE];
  269     int index_name_size;
  270     grn_obj *expected;
  271     char expected_name[GRN_TABLE_MAX_KEY_SIZE];
  272     int expected_name_size;
  273 
  274     index_name_size = grn_obj_name(ctx,
  275                                    index_datum->index,
  276                                    index_name,
  277                                    GRN_TABLE_MAX_KEY_SIZE);
  278     expected = grn_ctx_at(ctx, current_res->header.domain);
  279     expected_name_size = grn_obj_name(ctx,
  280                                       expected,
  281                                       expected_name,
  282                                       GRN_TABLE_MAX_KEY_SIZE);
  283     ERR(GRN_INVALID_ARGUMENT,
  284         "[accessor][resolve][data-column] lexicon mismatch index: "
  285         "<%.*s> "
  286         "expected:<%.*s>",
  287         index_name_size,
  288         index_name,
  289         expected_name_size,
  290         expected_name);
  291     return ctx->rc;
  292   }
  293 
  294   grn_report_index(ctx,
  295                    "[accessor][resolve][data-column]",
  296                    "",
  297                    index_datum->index);
  298   {
  299     grn_rc rc;
  300     grn_id next_res_domain_id = DB_OBJ(index_datum->index)->range;
  301     grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
  302     *next_res = grn_table_create(ctx, NULL, 0, NULL,
  303                                  GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
  304                                  next_res_domain, NULL);
  305     rc = ctx->rc;
  306     grn_obj_unlink(ctx, next_res_domain);
  307     if (!*next_res) {
  308       return rc;
  309     }
  310   }
  311 
  312   {
  313     grn_rc rc = GRN_SUCCESS;
  314     grn_obj *index_column = index_datum->index;
  315     grn_obj *index_cursor = grn_index_cursor_open(ctx,
  316                                                   NULL,
  317                                                   index_column,
  318                                                   GRN_ID_NIL,
  319                                                   GRN_ID_MAX,
  320                                                   0);
  321     if (!index_cursor) {
  322       grn_obj_unlink(ctx, *next_res);
  323       return ctx->rc;
  324     }
  325     if (index_datum->section > 0) {
  326       rc = grn_index_cursor_set_section_id(ctx,
  327                                            index_cursor,
  328                                            index_datum->section);
  329     }
  330     if (rc != GRN_SUCCESS) {
  331       grn_obj_close(ctx, index_cursor);
  332       grn_obj_unlink(ctx, *next_res);
  333       return ctx->rc;
  334     }
  335 
  336     GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
  337       void *key;
  338       void *value;
  339       grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
  340 
  341       grn_id *term_id = key;
  342       grn_rset_recinfo *recinfo = value;
  343 
  344       rc = grn_index_cursor_set_term_id(ctx, index_cursor, *term_id);
  345       if (rc == GRN_SUCCESS) {
  346         rc = grn_result_set_add_index_cursor(ctx,
  347                                              (grn_hash *)(*next_res),
  348                                              index_cursor,
  349                                              recinfo->score,
  350                                              1,
  351                                              GRN_OP_OR);
  352       }
  353 
  354       if (rc != GRN_SUCCESS) {
  355         break;
  356       }
  357     } GRN_HASH_EACH_END(ctx, cursor);
  358     grn_obj_close(ctx, index_cursor);
  359 
  360     if (rc != GRN_SUCCESS) {
  361       grn_obj_unlink(ctx, *next_res);
  362     }
  363 
  364     return rc;
  365   }
  366 }
  367 
  368 static grn_rc
  369 grn_accessor_resolve_one_data_column(grn_ctx *ctx, grn_accessor *accessor,
  370                                      grn_obj *current_res, grn_obj **next_res)
  371 {
  372   grn_rc rc = GRN_SUCCESS;
  373   grn_index_datum index_datum;
  374   unsigned int n_index_data;
  375 
  376   n_index_data = grn_column_get_all_index_data(ctx,
  377                                                accessor->obj,
  378                                                &index_datum,
  379                                                1);
  380   if (n_index_data == 0) {
  381     rc = grn_accessor_resolve_one_data_column_sequential(ctx,
  382                                                          accessor,
  383                                                          current_res,
  384                                                          next_res);
  385   } else {
  386     rc = grn_accessor_resolve_one_data_column_index(ctx,
  387                                                     &index_datum,
  388                                                     current_res,
  389                                                     next_res);
  390     grn_obj_unref(ctx, index_datum.index);
  391   }
  392 
  393   return rc;
  394 }
  395 
  396 grn_rc
  397 grn_accessor_resolve(grn_ctx *ctx, grn_obj *accessor, int depth,
  398                      grn_obj *base_res, grn_obj *res,
  399                      grn_operator op)
  400 {
  401   grn_rc rc = GRN_SUCCESS;
  402   grn_accessor *a;
  403   grn_obj accessor_stack;
  404   int i, n_accessors;
  405   grn_obj *current_res = base_res;
  406 
  407   GRN_PTR_INIT(&accessor_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
  408   n_accessors = 0;
  409   for (a = (grn_accessor *)accessor; a; a = a->next) {
  410     if (depth == n_accessors) {
  411       break;
  412     }
  413     GRN_PTR_PUT(ctx, &accessor_stack, a);
  414     n_accessors++;
  415   }
  416 
  417   for (i = n_accessors; i > 0; i--) {
  418     grn_obj *next_res = NULL;
  419 
  420     a = (grn_accessor *)GRN_PTR_VALUE_AT(&accessor_stack, i - 1);
  421     if (a->obj->header.type == GRN_COLUMN_INDEX) {
  422       rc = grn_accessor_resolve_one_index_column(ctx, a,
  423                                                  current_res, &next_res);
  424     } else if (grn_obj_is_table(ctx, a->obj)) {
  425       rc = grn_accessor_resolve_one_table(ctx, a,
  426                                           current_res, &next_res);
  427     } else {
  428       rc = grn_accessor_resolve_one_data_column(ctx, a,
  429                                                 current_res, &next_res);
  430     }
  431 
  432     if (current_res != base_res) {
  433       grn_obj_unlink(ctx, current_res);
  434     }
  435 
  436     if (rc != GRN_SUCCESS) {
  437       break;
  438     }
  439 
  440     current_res = next_res;
  441   }
  442 
  443   if (rc == GRN_SUCCESS && current_res != base_res) {
  444     GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
  445       void *key;
  446       void *value;
  447       grn_id *record_id;
  448       grn_rset_recinfo *recinfo;
  449       grn_posting_internal posting = {0};
  450 
  451       grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
  452       record_id = key;
  453       recinfo = value;
  454       posting.rid = *record_id;
  455       posting.sid = 1;
  456       posting.pos = 0;
  457       posting.weight_float = recinfo->score;
  458       grn_ii_posting_add_float(ctx,
  459                                (grn_posting *)(&posting),
  460                                (grn_hash *)res,
  461                                op);
  462     } GRN_HASH_EACH_END(ctx, cursor);
  463     grn_obj_unlink(ctx, current_res);
  464     grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
  465   } else {
  466     if (rc == GRN_SUCCESS) {
  467       rc = GRN_INVALID_ARGUMENT;
  468     }
  469   }
  470 
  471   GRN_OBJ_FIN(ctx, &accessor_stack);
  472   return rc;
  473 }
  474 
  475 grn_id
  476 grn_accessor_resolve_id(grn_ctx *ctx, grn_obj *accessor, grn_id id)
  477 {
  478   GRN_API_ENTER;
  479 
  480   grn_accessor *a;
  481   for (a = (grn_accessor *)accessor;
  482        a->next;
  483        a = a->next) {
  484     switch (a->action) {
  485     case GRN_ACCESSOR_GET_KEY :
  486       {
  487         grn_id next_id;
  488         int key_size = grn_table_get_key(ctx,
  489                                          a->obj,
  490                                          id,
  491                                          &next_id,
  492                                          sizeof(grn_id));
  493         if (key_size != sizeof(grn_id)) {
  494           GRN_API_RETURN(id);
  495         }
  496         id = next_id;
  497       }
  498       break;
  499     case GRN_ACCESSOR_GET_VALUE :
  500       {
  501         grn_obj value;
  502         GRN_VOID_INIT(&value);
  503         grn_obj_get_value(ctx, a->obj, id, &value);
  504         if (GRN_BULK_VSIZE(&value) < sizeof(grn_id)) {
  505           GRN_OBJ_FIN(ctx, &value);
  506           GRN_API_RETURN(id);
  507         }
  508         id = GRN_RECORD_VALUE(&value);
  509         GRN_OBJ_FIN(ctx, &value);
  510       }
  511       break;
  512     default :
  513       GRN_API_RETURN(id);
  514     }
  515   }
  516 
  517   GRN_API_RETURN(id);
  518 }
  519 
  520 grn_rc
  521 grn_accessor_execute(grn_ctx *ctx,
  522                      grn_obj *accessor,
  523                      grn_accessor_execute_func execute,
  524                      void *execute_data,
  525                      grn_operator execute_op,
  526                      grn_obj *res,
  527                      grn_operator logical_op)
  528 {
  529   GRN_API_ENTER;
  530 
  531   if (!grn_obj_is_accessor(ctx, accessor)) {
  532     grn_obj inspected;
  533     GRN_TEXT_INIT(&inspected, 0);
  534     grn_inspect(ctx, &inspected, accessor);
  535     ERR(GRN_INVALID_ARGUMENT,
  536         "[accessor][execute] must be accessor: %.*s",
  537         (int)GRN_TEXT_LEN(&inspected),
  538         GRN_TEXT_VALUE(&inspected));
  539     GRN_OBJ_FIN(ctx, &inspected);
  540     GRN_API_RETURN(ctx->rc);
  541   }
  542 
  543   int depth = 0;
  544   grn_accessor *a;
  545   for (a = (grn_accessor *)accessor; a->next; a = a->next) {
  546     depth++;
  547   }
  548 
  549   grn_index_datum index_data;
  550   unsigned int n_index_datum;
  551   grn_obj *index;
  552   n_index_datum = grn_column_find_index_data(ctx,
  553                                              a->obj,
  554                                              execute_op,
  555                                              &index_data,
  556                                              1);
  557   if (n_index_datum == 0) {
  558     index = (grn_obj *)a;
  559   } else {
  560     index = index_data.index;
  561   }
  562 
  563   grn_rc rc;
  564   if (depth == 0) {
  565     rc = execute(ctx,
  566                  index,
  567                  execute_op,
  568                  res,
  569                  logical_op,
  570                  execute_data);
  571   } else {
  572     grn_obj *base_table = NULL;
  573     if (grn_obj_is_table(ctx, a->obj)) {
  574       base_table = a->obj;
  575     } else {
  576       base_table = grn_ctx_at(ctx, a->obj->header.domain);
  577     }
  578 
  579     grn_obj *base_res =
  580       grn_table_create(ctx, NULL, 0, NULL,
  581                        GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
  582                        base_table, NULL);
  583     rc = execute(ctx,
  584                  index,
  585                  execute_op,
  586                  base_res,
  587                  GRN_OP_OR,
  588                  execute_data);
  589     if (rc == GRN_SUCCESS) {
  590       rc = grn_accessor_resolve(ctx,
  591                                 accessor,
  592                                 depth,
  593                                 base_res,
  594                                 res,
  595                                 logical_op);
  596     }
  597     grn_obj_close(ctx, base_res);
  598   }
  599 
  600   if (n_index_datum > 0) {
  601     grn_obj_unref(ctx, index_data.index);
  602   }
  603 
  604   GRN_API_RETURN(rc);
  605 }
  606 
  607 typedef struct {
  608   grn_obj *accessor;
  609   grn_obj *query;
  610   grn_search_optarg *optarg;
  611   grn_obj *index;
  612   bool index_need_unref;
  613   grn_operator operator;
  614   grn_obj query_casted;
  615   const char *query_raw;
  616   uint32_t query_raw_len;
  617   uint32_t n_base_records;
  618   uint32_t n_target_records;
  619   uint32_t depth;
  620 } grn_accessor_estimate_size_for_query_data;
  621 
  622 static void
  623 grn_accessor_estimate_size_for_query_data_fin(
  624   grn_ctx *ctx,
  625   grn_accessor_estimate_size_for_query_data *data)
  626 {
  627   if (data->index_need_unref) {
  628     grn_obj_unref(ctx, data->index);
  629   }
  630   GRN_OBJ_FIN(ctx, &(data->query_casted));
  631 }
  632 
  633 static void
  634 grn_accessor_estimate_size_for_query_cast_failed(
  635   grn_ctx *ctx,
  636   grn_accessor_estimate_size_for_query_data *data)
  637 {
  638   grn_obj detail;
  639   GRN_TEXT_INIT(&detail, 0);
  640   GRN_TEXT_PUTS(ctx, &detail, "<");
  641   grn_inspect(ctx, &detail, data->query);
  642   GRN_TEXT_PUTS(ctx, &detail, "> -> ");
  643   grn_obj *domain = grn_ctx_at(ctx, data->query_casted.header.domain);
  644   grn_inspect(ctx, &detail, domain);
  645   grn_obj_unlink(ctx, domain);
  646   GRN_TEXT_PUTS(ctx, &detail, ": ");
  647   grn_inspect(ctx, &detail, data->accessor);
  648   ERR(GRN_INVALID_ARGUMENT,
  649       "[accessor][estimate-size][query][cast] "
  650       "failed: %.*s",
  651       (int)GRN_TEXT_LEN(&detail),
  652       GRN_TEXT_VALUE(&detail));
  653   GRN_OBJ_FIN(ctx, &detail);
  654 }
  655 
  656 static bool
  657 grn_accessor_estimate_size_for_query_prepare(
  658   grn_ctx *ctx,
  659   grn_accessor_estimate_size_for_query_data *data)
  660 {
  661   grn_accessor *a = (grn_accessor *)(data->accessor);
  662   if (grn_obj_is_table(ctx, a->obj)) {
  663     data->n_target_records = grn_table_size(ctx, a->obj);
  664   } else {
  665     grn_obj *target_table = grn_ctx_at(ctx, a->obj->header.domain);
  666     data->n_target_records = grn_table_size(ctx, target_table);
  667     grn_obj_unlink(ctx, target_table);
  668   }
  669 
  670   if (data->n_target_records == 0) {
  671     return false;
  672   }
  673 
  674   for (; a->next; a = a->next) {
  675     data->depth++;
  676   }
  677 
  678   if (grn_obj_is_table(ctx, a->obj)) {
  679     data->n_base_records = grn_table_size(ctx, a->obj);
  680   } else {
  681     grn_obj *base_table = grn_ctx_at(ctx, a->obj->header.domain);
  682     data->n_base_records = grn_table_size(ctx, base_table);
  683     grn_obj_unlink(ctx, base_table);
  684   }
  685 
  686   if (data->optarg) {
  687     if (data->optarg->mode == GRN_OP_EXACT) {
  688       data->operator = GRN_OP_MATCH;
  689     } else {
  690       data->operator = data->optarg->mode;
  691     }
  692   }
  693   grn_index_datum index_data;
  694   unsigned int n_index_datum;
  695   n_index_datum = grn_column_find_index_data(ctx,
  696                                              a->obj,
  697                                              data->operator,
  698                                              &index_data,
  699                                              1);
  700   if (n_index_datum == 0) {
  701     if (!grn_obj_is_table(ctx, a->obj)) {
  702       return false;
  703     }
  704     data->index = a->obj;
  705   } else {
  706     data->index = index_data.index;
  707     data->index_need_unref = true;
  708   }
  709 
  710   grn_obj *lexicon;
  711   bool lexicon_need_unref = false;
  712   if (grn_obj_is_table(ctx, data->index)) {
  713     lexicon = data->index;
  714   } else {
  715     lexicon = grn_ctx_at(ctx, data->index->header.domain);
  716     lexicon_need_unref = true;
  717   }
  718 
  719   if (data->query->header.domain == lexicon->header.domain) {
  720     data->query_raw = GRN_BULK_HEAD(data->query);
  721     data->query_raw_len = GRN_BULK_VSIZE(data->query);
  722   } else {
  723     grn_obj_reinit_for(ctx, &(data->query_casted), lexicon);
  724     grn_rc rc = grn_obj_cast(ctx, data->query, &(data->query_casted), false);
  725     if (rc == GRN_SUCCESS) {
  726       data->query_raw = GRN_BULK_HEAD(&(data->query_casted));
  727       data->query_raw_len = GRN_BULK_VSIZE(&(data->query_casted));
  728     } else {
  729       grn_accessor_estimate_size_for_query_cast_failed(ctx, data);
  730     }
  731   }
  732 
  733   if (lexicon_need_unref) {
  734     grn_obj_unref(ctx, lexicon);
  735   }
  736 
  737   return ctx->rc == GRN_SUCCESS;
  738 }
  739 
  740 uint32_t
  741 grn_accessor_estimate_size_for_query(grn_ctx *ctx,
  742                                      grn_obj *accessor,
  743                                      grn_obj *query,
  744                                      grn_search_optarg *optarg)
  745 {
  746   GRN_API_ENTER;
  747 
  748   if (!grn_obj_is_accessor(ctx, accessor)) {
  749     grn_obj inspected;
  750     GRN_TEXT_INIT(&inspected, 0);
  751     grn_inspect(ctx, &inspected, accessor);
  752     ERR(GRN_INVALID_ARGUMENT,
  753         "[accessor][estimate-size][query] must be accessor: %.*s",
  754         (int)GRN_TEXT_LEN(&inspected),
  755         GRN_TEXT_VALUE(&inspected));
  756     GRN_OBJ_FIN(ctx, &inspected);
  757     GRN_API_RETURN(0);
  758   }
  759 
  760   if (!query) {
  761     GRN_API_RETURN(0);
  762   }
  763 
  764   grn_accessor_estimate_size_for_query_data data;
  765   data.accessor = accessor;
  766   data.query = query;
  767   data.optarg = optarg;
  768   data.index = NULL;
  769   data.index_need_unref = false;
  770   data.operator = GRN_OP_MATCH;
  771   GRN_VOID_INIT(&(data.query_casted));
  772   data.query_raw = NULL;
  773   data.query_raw_len = 0;
  774   data.n_target_records = 0;
  775   data.depth = 0;
  776 
  777   if (!grn_accessor_estimate_size_for_query_prepare(ctx, &data)) {
  778     grn_accessor_estimate_size_for_query_data_fin(ctx, &data);
  779     GRN_API_RETURN(0);
  780   }
  781 
  782   uint32_t estimated_size = 0;
  783   if (data.n_base_records == 0) {
  784     estimated_size = 0;
  785   } else {
  786     uint32_t base_estimated_size;
  787     if (grn_obj_is_table(ctx, data.index)) {
  788       if (data.operator == GRN_OP_EQUAL) {
  789         if (grn_table_get(ctx,
  790                           data.index,
  791                           data.query_raw,
  792                           data.query_raw_len)) {
  793           base_estimated_size = 1;
  794         } else {
  795           base_estimated_size = 0;
  796         }
  797       } else {
  798         /* TODO */
  799         base_estimated_size = data.n_base_records;
  800       }
  801     } else {
  802       base_estimated_size =
  803         grn_ii_estimate_size_for_query(ctx,
  804                                        (grn_ii *)(data.index),
  805                                        data.query_raw,
  806                                        data.query_raw_len,
  807                                        optarg);
  808     }
  809     if (base_estimated_size >= data.n_base_records) {
  810       estimated_size = data.n_target_records;
  811     } else {
  812       estimated_size =
  813         data.n_target_records *
  814         (base_estimated_size / (double)(data.n_base_records));
  815     }
  816   }
  817 
  818   grn_accessor_estimate_size_for_query_data_fin(ctx, &data);
  819 
  820   GRN_API_RETURN(estimated_size);
  821 }
  822 
  823 grn_rc
  824 grn_accessor_name(grn_ctx *ctx, grn_obj *accessor, grn_obj *name)
  825 {
  826   grn_accessor *accessor_;
  827   GRN_API_ENTER;
  828 
  829   if (!grn_obj_is_accessor(ctx, accessor)) {
  830     grn_obj inspected;
  831     GRN_TEXT_INIT(&inspected, 0);
  832     grn_inspect(ctx, &inspected, accessor);
  833     ERR(GRN_INVALID_ARGUMENT,
  834         "[accessor][name] must be accessor: %.*s",
  835         (int)GRN_TEXT_LEN(&inspected),
  836         GRN_TEXT_VALUE(&inspected));
  837     GRN_OBJ_FIN(ctx, &inspected);
  838     GRN_API_RETURN(ctx->rc);
  839   }
  840 
  841   for (accessor_ = (grn_accessor *)accessor;
  842        accessor_;
  843        accessor_ = accessor_->next) {
  844     grn_bool show_obj_name = GRN_FALSE;
  845     grn_bool show_obj_domain_name = GRN_FALSE;
  846 
  847     if (accessor_ != (grn_accessor *)accessor) {
  848       GRN_TEXT_PUTS(ctx, name, ".");
  849     }
  850     switch (accessor_->action) {
  851     case GRN_ACCESSOR_GET_ID :
  852       GRN_TEXT_PUT(ctx,
  853                    name,
  854                    GRN_COLUMN_NAME_ID,
  855                    GRN_COLUMN_NAME_ID_LEN);
  856       show_obj_name = GRN_TRUE;
  857       break;
  858     case GRN_ACCESSOR_GET_KEY :
  859       GRN_TEXT_PUT(ctx,
  860                    name,
  861                    GRN_COLUMN_NAME_KEY,
  862                    GRN_COLUMN_NAME_KEY_LEN);
  863       show_obj_name = GRN_TRUE;
  864       break;
  865     case GRN_ACCESSOR_GET_VALUE :
  866       GRN_TEXT_PUT(ctx,
  867                    name,
  868                    GRN_COLUMN_NAME_VALUE,
  869                    GRN_COLUMN_NAME_VALUE_LEN);
  870       show_obj_name = GRN_TRUE;
  871       break;
  872     case GRN_ACCESSOR_GET_SCORE :
  873       GRN_TEXT_PUT(ctx,
  874                    name,
  875                    GRN_COLUMN_NAME_SCORE,
  876                    GRN_COLUMN_NAME_SCORE_LEN);
  877       break;
  878     case GRN_ACCESSOR_GET_NSUBRECS :
  879       GRN_TEXT_PUT(ctx,
  880                    name,
  881                    GRN_COLUMN_NAME_NSUBRECS,
  882                    GRN_COLUMN_NAME_NSUBRECS_LEN);
  883       break;
  884     case GRN_ACCESSOR_GET_MAX :
  885       GRN_TEXT_PUT(ctx,
  886                    name,
  887                    GRN_COLUMN_NAME_MAX,
  888                    GRN_COLUMN_NAME_MAX_LEN);
  889       break;
  890     case GRN_ACCESSOR_GET_MIN :
  891       GRN_TEXT_PUT(ctx,
  892                    name,
  893                    GRN_COLUMN_NAME_MIN,
  894                    GRN_COLUMN_NAME_MIN_LEN);
  895       break;
  896     case GRN_ACCESSOR_GET_SUM :
  897       GRN_TEXT_PUT(ctx,
  898                    name,
  899                    GRN_COLUMN_NAME_SUM,
  900                    GRN_COLUMN_NAME_SUM_LEN);
  901       break;
  902     case GRN_ACCESSOR_GET_AVG :
  903       GRN_TEXT_PUT(ctx,
  904                    name,
  905                    GRN_COLUMN_NAME_AVG,
  906                    GRN_COLUMN_NAME_AVG_LEN);
  907       break;
  908     case GRN_ACCESSOR_GET_MEAN :
  909       GRN_TEXT_PUT(ctx,
  910                    name,
  911                    GRN_COLUMN_NAME_MEAN,
  912                    GRN_COLUMN_NAME_MEAN_LEN);
  913       break;
  914     case GRN_ACCESSOR_GET_COLUMN_VALUE :
  915       grn_column_name_(ctx, accessor_->obj, name);
  916       show_obj_domain_name = GRN_TRUE;
  917       break;
  918     case GRN_ACCESSOR_GET_DB_OBJ :
  919       grn_text_printf(ctx, name, "(_db)");
  920       break;
  921     case GRN_ACCESSOR_LOOKUP :
  922       grn_text_printf(ctx, name, "(_lookup)");
  923       break;
  924     case GRN_ACCESSOR_FUNCALL :
  925       grn_text_printf(ctx, name, "(_funcall)");
  926       break;
  927     default :
  928       grn_text_printf(ctx, name, "(unknown:%u)", accessor_->action);
  929       break;
  930     }
  931 
  932     if (show_obj_name || show_obj_domain_name) {
  933       grn_obj *target = accessor_->obj;
  934       char target_name[GRN_TABLE_MAX_KEY_SIZE];
  935       int target_name_size;
  936 
  937       if (show_obj_domain_name) {
  938         target = grn_ctx_at(ctx, target->header.domain);
  939       }
  940 
  941       target_name_size = grn_obj_name(ctx,
  942                                       target,
  943                                       target_name,
  944                                       GRN_TABLE_MAX_KEY_SIZE);
  945       GRN_TEXT_PUTS(ctx, name, "(");
  946       if (target_name_size == 0) {
  947         GRN_TEXT_PUTS(ctx, name, "anonymous");
  948       } else {
  949         GRN_TEXT_PUT(ctx, name, target_name, target_name_size);
  950       }
  951       GRN_TEXT_PUTS(ctx, name, ")");
  952       if (show_obj_domain_name && target) {
  953         grn_obj_unref(ctx, target);
  954       }
  955     }
  956   }
  957 
  958   GRN_API_RETURN(GRN_SUCCESS);
  959 }