1 /* -*- c-basic-offset: 2 -*- */ 2 /* 3 Copyright(C) 2010-2013 Kentoku SHIBA 4 Copyright(C) 2011-2017 Kouhei Sutou <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 as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA 19 */ 20 21 #include "mrn_count_skip_checker.hpp" 22 23 #include <item_sum.h> 24 25 // for debug 26 #define MRN_CLASS_NAME "mrn::CountSkipChecker" 27 28 namespace mrn { CountSkipChecker(grn_ctx * ctx,TABLE * table,SELECT_LEX * select_lex,KEY * key_info,key_part_map target_key_part_map,bool is_storage_mode)29 CountSkipChecker::CountSkipChecker(grn_ctx *ctx, 30 TABLE *table, 31 SELECT_LEX *select_lex, 32 KEY *key_info, 33 key_part_map target_key_part_map, 34 bool is_storage_mode) 35 : ctx_(ctx), 36 table_(table), 37 select_lex_(select_lex), 38 key_info_(key_info), 39 target_key_part_map_(target_key_part_map), 40 is_storage_mode_(is_storage_mode) { 41 } 42 ~CountSkipChecker()43 CountSkipChecker::~CountSkipChecker() { 44 } 45 check()46 bool CountSkipChecker::check() { 47 MRN_DBUG_ENTER_METHOD(); 48 49 if (select_lex_->item_list.elements != 1) { 50 GRN_LOG(ctx_, GRN_LOG_DEBUG, 51 "[mroonga][count-skip][false] not only one item: %u", 52 select_lex_->item_list.elements); 53 DBUG_RETURN(false); 54 } 55 if (select_lex_->group_list.elements > 0) { 56 GRN_LOG(ctx_, GRN_LOG_DEBUG, 57 "[mroonga][count-skip][false] have groups: %u", 58 select_lex_->group_list.elements); 59 DBUG_RETURN(false); 60 } 61 if (MRN_SELECT_LEX_GET_HAVING_COND(select_lex_)) { 62 GRN_LOG(ctx_, GRN_LOG_DEBUG, 63 "[mroonga][count-skip][false] have HAVING"); 64 DBUG_RETURN(false); 65 } 66 if (select_lex_->table_list.elements != 1) { 67 GRN_LOG(ctx_, GRN_LOG_DEBUG, 68 "[mroonga][count-skip][false] not only one table: %u", 69 select_lex_->table_list.elements); 70 DBUG_RETURN(false); 71 } 72 73 Item *info = static_cast<Item *>(select_lex_->item_list.first_node()->info); 74 if (info->type() != Item::SUM_FUNC_ITEM) { 75 GRN_LOG(ctx_, GRN_LOG_DEBUG, 76 "[mroonga][count-skip][false] item isn't sum function: %u", 77 info->type()); 78 DBUG_RETURN(false); 79 } 80 Item_sum *sum_item = static_cast<Item_sum *>(info); 81 if (sum_item->sum_func() != Item_sum::COUNT_FUNC) { 82 GRN_LOG(ctx_, GRN_LOG_DEBUG, 83 "[mroonga][count-skip][false] not COUNT: %u", 84 sum_item->sum_func()); 85 DBUG_RETURN(false); 86 } 87 if (ITEM_SUM_GET_NEST_LEVEL(sum_item) != 0 || 88 ITEM_SUM_GET_AGGR_LEVEL(sum_item) != 0 || 89 ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item) != -1 || 90 sum_item->max_sum_func_level != -1) { 91 GRN_LOG(ctx_, GRN_LOG_DEBUG, 92 "[mroonga][count-skip][false] not simple COUNT(*): %d:%d:%d:%d", 93 ITEM_SUM_GET_NEST_LEVEL(sum_item), 94 ITEM_SUM_GET_AGGR_LEVEL(sum_item), 95 ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item), 96 sum_item->max_sum_func_level); 97 DBUG_RETURN(false); 98 } 99 100 Item *where = MRN_SELECT_LEX_GET_WHERE_COND(select_lex_); 101 if (!where) { 102 if (is_storage_mode_) { 103 GRN_LOG(ctx_, GRN_LOG_DEBUG, 104 "[mroonga][count-skip][true] no condition"); 105 DBUG_RETURN(true); 106 } else { 107 GRN_LOG(ctx_, GRN_LOG_DEBUG, 108 "[mroonga][count-skip][false] no condition with wrapper mode"); 109 DBUG_RETURN(false); 110 } 111 } 112 113 bool skippable = is_skippable(where); 114 DBUG_RETURN(skippable); 115 } 116 is_skippable(Item * where)117 bool CountSkipChecker::is_skippable(Item *where) { 118 MRN_DBUG_ENTER_METHOD(); 119 120 bool skippable = false; 121 switch (where->type()) { 122 case Item::COND_ITEM: 123 { 124 Item_cond *cond_item = static_cast<Item_cond *>(where); 125 skippable = is_skippable(cond_item); 126 if (skippable) { 127 GRN_LOG(ctx_, GRN_LOG_DEBUG, 128 "[mroonga][count-skip][true] skippable multiple conditions"); 129 } 130 } 131 break; 132 case Item::FUNC_ITEM: 133 { 134 Item_func *func_item = static_cast<Item_func *>(where); 135 if (func_item->functype() == Item_func::FT_FUNC) { 136 if (select_lex_->select_n_where_fields == 1) { 137 GRN_LOG(ctx_, GRN_LOG_DEBUG, 138 "[mroonga][count-skip][true] " 139 "only one full text search condition"); 140 DBUG_RETURN(true); 141 } else { 142 GRN_LOG(ctx_, GRN_LOG_DEBUG, 143 "[mroonga][count-skip][false] " 144 "full text search condition and more conditions: %u", 145 select_lex_->select_n_where_fields); 146 DBUG_RETURN(false); 147 } 148 } else { 149 skippable = is_skippable(func_item); 150 if (skippable) { 151 GRN_LOG(ctx_, GRN_LOG_DEBUG, 152 "[mroonga][count-skip][true] skippable condition"); 153 } 154 } 155 } 156 break; 157 default: 158 GRN_LOG(ctx_, GRN_LOG_DEBUG, 159 "[mroonga][count-skip][false] unsupported top level item: %u", 160 where->type()); 161 break; 162 } 163 164 DBUG_RETURN(skippable); 165 } 166 is_skippable(Item_cond * cond_item)167 bool CountSkipChecker::is_skippable(Item_cond *cond_item) { 168 MRN_DBUG_ENTER_METHOD(); 169 170 List_iterator<Item> iterator(*(cond_item->argument_list())); 171 Item *sub_item; 172 while ((sub_item = iterator++)) { 173 if (sub_item->type() != Item::FUNC_ITEM) { 174 GRN_LOG(ctx_, GRN_LOG_DEBUG, 175 "[mroonga][count-skip][false] " 176 "sub condition isn't function item: %u", 177 sub_item->type()); 178 DBUG_RETURN(false); 179 } 180 if (!is_skippable(static_cast<Item_func *>(sub_item))) { 181 DBUG_RETURN(false); 182 } 183 } 184 DBUG_RETURN(true); 185 } 186 is_skippable(Item_func * func_item)187 bool CountSkipChecker::is_skippable(Item_func *func_item) { 188 MRN_DBUG_ENTER_METHOD(); 189 190 switch (func_item->functype()) { 191 case Item_func::EQ_FUNC: 192 case Item_func::EQUAL_FUNC: 193 case Item_func::NE_FUNC: 194 case Item_func::LT_FUNC: 195 case Item_func::LE_FUNC: 196 case Item_func::GE_FUNC: 197 case Item_func::GT_FUNC: 198 { 199 Item **arguments = func_item->arguments(); 200 Item *left_item = arguments[0]; 201 if (left_item->type() != Item::FIELD_ITEM) { 202 GRN_LOG(ctx_, GRN_LOG_DEBUG, 203 "[mroonga][count-skip][false] not field: %u:%u", 204 func_item->functype(), 205 left_item->type()); 206 DBUG_RETURN(false); 207 } 208 209 bool skippable = is_skippable(static_cast<Item_field *>(left_item)); 210 DBUG_RETURN(skippable); 211 } 212 break; 213 case Item_func::BETWEEN: 214 { 215 Item **arguments = func_item->arguments(); 216 Item *target_item = arguments[0]; 217 if (target_item->type() != Item::FIELD_ITEM) { 218 GRN_LOG(ctx_, GRN_LOG_DEBUG, 219 "[mroonga][count-skip][false] BETWEEN target isn't field: %u", 220 target_item->type()); 221 DBUG_RETURN(false); 222 } 223 224 bool skippable = is_skippable(static_cast<Item_field *>(target_item)); 225 DBUG_RETURN(skippable); 226 } 227 break; 228 case Item_func::MULT_EQUAL_FUNC: 229 #ifdef MRN_HAVE_ITEM_EQUAL_FIELDS_ITERATOR 230 { 231 Item_equal *equal_item = static_cast<Item_equal *>(func_item); 232 Item_equal_fields_iterator iterator(*equal_item); 233 Item *field_item; 234 while ((field_item = iterator++)) { 235 bool skippable = is_skippable(static_cast<Item_field *>(field_item)); 236 if (!skippable) { 237 DBUG_RETURN(skippable); 238 } 239 } 240 DBUG_RETURN(true); 241 } 242 #endif 243 break; 244 default: 245 break; 246 } 247 248 GRN_LOG(ctx_, GRN_LOG_DEBUG, 249 "[mroonga][count-skip][false] unsupported function item: %u", 250 func_item->functype()); 251 DBUG_RETURN(false); 252 } 253 is_skippable(Item_field * field_item)254 bool CountSkipChecker::is_skippable(Item_field *field_item) { 255 MRN_DBUG_ENTER_METHOD(); 256 257 Field *field = field_item->field; 258 if (!field) { 259 GRN_LOG(ctx_, GRN_LOG_DEBUG, 260 "[mroonga][count-skip][false] field is missing"); 261 DBUG_RETURN(false); 262 } 263 264 if (field->table != table_) { 265 GRN_LOG(ctx_, GRN_LOG_DEBUG, 266 "[mroonga][count-skip][false] external table's field"); 267 DBUG_RETURN(false); 268 } 269 270 if (!key_info_) { 271 GRN_LOG(ctx_, GRN_LOG_DEBUG, 272 "[mroonga][count-skip][false] no active index: <%s>:<%s>", 273 *(field->table_name), 274 field->field_name.str); 275 DBUG_RETURN(false); 276 } 277 278 uint i; 279 KEY_PART_INFO *key_part = key_info_->key_part; 280 for (i = 0; i < KEY_N_KEY_PARTS(key_info_); i++) { 281 if (key_part[i].field == field) { 282 if ((target_key_part_map_ >> i) & 1) { 283 DBUG_RETURN(true); 284 } else { 285 GRN_LOG(ctx_, GRN_LOG_DEBUG, 286 "[mroonga][count-skip][false] " 287 "field's index are out of key part map: %u:%lu: <%s>:<%s>", 288 i, 289 target_key_part_map_, 290 *(field->table_name), 291 field->field_name.str); 292 DBUG_RETURN(false); 293 } 294 } 295 } 296 297 GRN_LOG(ctx_, GRN_LOG_DEBUG, 298 "[mroonga][count-skip][false] field isn't indexed: <%s>:<%s>", 299 *(field->table_name), 300 field->field_name.str); 301 DBUG_RETURN(false); 302 } 303 } 304