protected void explain(String prefix, List<String> planSteps) { StringBuilder buf = new StringBuilder(prefix); ScanRanges scanRanges = context.getScanRanges(); boolean hasSkipScanFilter = false; if (scanRanges.isEverything()) { buf.append("FULL SCAN "); } else { hasSkipScanFilter = explainSkipScan(buf); } buf.append("OVER " + tableRef.getTable().getName().getString()); if (!scanRanges.isPointLookup()) { appendKeyRanges(buf); } planSteps.add(buf.toString()); Scan scan = context.getScan(); Filter filter = scan.getFilter(); PageFilter pageFilter = null; if (filter != null) { int offset = 0; boolean hasFirstKeyOnlyFilter = false; String filterDesc = ""; if (hasSkipScanFilter) { if (filter instanceof FilterList) { List<Filter> filterList = ((FilterList) filter).getFilters(); if (filterList.get(0) instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; offset = 1; } if (filterList.size() > offset + 1) { filterDesc = filterList.get(offset + 1).toString(); if (filterList.size() > offset + 2) { pageFilter = (PageFilter) filterList.get(offset + 2); } } } } else if (filter instanceof FilterList) { List<Filter> filterList = ((FilterList) filter).getFilters(); if (filterList.get(0) instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; offset = 1; } if (filterList.size() > offset) { filterDesc = filterList.get(offset).toString(); if (filterList.size() > offset + 1) { pageFilter = (PageFilter) filterList.get(offset + 1); } } } else { if (filter instanceof FirstKeyOnlyFilter) { hasFirstKeyOnlyFilter = true; } else { filterDesc = filter.toString(); } } if (filterDesc.length() > 0) { planSteps.add( " SERVER FILTER BY " + (hasFirstKeyOnlyFilter ? "FIRST KEY ONLY AND " : "") + filterDesc); } else if (hasFirstKeyOnlyFilter) { planSteps.add(" SERVER FILTER BY FIRST KEY ONLY"); } if (pageFilter != null) { planSteps.add(" SERVER " + pageFilter.getPageSize() + " ROW LIMIT"); } } groupBy.explain(planSteps); }