📄 tablefilter.java
字号:
/* Copyright (c) 1995-2000, The Hypersonic SQL Group. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the Hypersonic SQL Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software consists of voluntary contributions made by many individuals * on behalf of the Hypersonic SQL Group. * * * For work added by the HSQL Development Group: * * Copyright (c) 2001-2005, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */package org.hsqldb;import org.hsqldb.index.RowIterator;import org.hsqldb.lib.ArrayUtil;import org.hsqldb.lib.HashMappedList;// fredt@users 20030813 - patch 1.7.2 - fix for column comparison within same table bugs #572075 and 722443// fredt@users 20031012 - patch 1.7.2 - better OUTER JOIN implementation// fredt@users 20031026 - patch 1.7.2 - more efficient findfirst - especially for multi-column equijoins// implemented optimisations similart to patch 465542 by hjbush@users/** * This class iterates over table rows to select the rows that fulfil join * or other conditions. It uses indexes if they are availabe. * * Extended in successive versions of HSQLDB. * * @author Thomas Mueller (Hypersonic SQL Group) * @version 1.8.0 * @since Hypersonic SQL */final class TableFilter { static final int CONDITION_NONE = -1; // not a condition expression static final int CONDITION_UNORDERED = 0; // not candidate for eStart or eEnd static final int CONDITION_START_END = 1; // candidate for eStart and eEnd static final int CONDITION_START = 2; // candidate for eStart static final int CONDITION_END = 3; // candidate for eEnd static final int CONDITION_OUTER = 4; // add to this Table filterTable; private String tableAlias; HashMappedList columnAliases; Index filterIndex; private Object[] emptyData; boolean[] usedColumns; private Expression eStart, eEnd; // Expression eAnd; // boolean isOuterJoin; // table joined with OUTER JOIN boolean isAssigned; // conditions have been assigned to this boolean isMultiFindFirst; // findFirst() uses multi-column index Expression[] findFirstExpressions; // expressions for column values // private RowIterator it; Object[] currentData; Row currentRow; // Object[] currentJoinData; // addendum to the result of findFirst() and next() with isOuterJoin==true // when the result is false, it indicates if a non-join condition caused the failure boolean nonJoinIsNull; // indicates current data is empty data produced for an outer join boolean isCurrentOuter; /** * Constructor declaration * * * @param t * @param alias * @param outerjoin */ TableFilter(Table t, String alias, HashMappedList columnList, boolean outerjoin) { filterTable = t; tableAlias = alias == null ? t.getName().name : alias; columnAliases = columnList; isOuterJoin = outerjoin; emptyData = filterTable.getEmptyRowData(); usedColumns = filterTable.getNewColumnCheckList(); } /** * Returns the alias or the table name. * Never returns null; * @return */ String getName() { return tableAlias; } /** * Retrieves this object's filter Table object. * * @return this object's filter Table object */ Table getTable() { return filterTable; } /** * Retrieves a CONDITION_XXX code indicating how a condition * expression can be used for a TableFilter. * * @param exprType an expression type code * @return */ static int getConditionType(Expression e) { int exprType = e.getType(); switch (exprType) { case Expression.NOT_EQUAL : case Expression.LIKE : return CONDITION_UNORDERED; case Expression.IN : { return e.isQueryCorrelated ? CONDITION_NONE : CONDITION_UNORDERED; } case Expression.IS_NULL : case Expression.EQUAL : { return CONDITION_START_END; } case Expression.BIGGER : case Expression.BIGGER_EQUAL : { return CONDITION_START; } case Expression.SMALLER : case Expression.SMALLER_EQUAL : { return CONDITION_END; } default : { // not a condition so forget it return CONDITION_NONE; } } } // TODO: Optimize // // The current way always chooses eStart, eEnd conditions // using first encountered eligible index // // We should check if current index offers better selectivity/access // path than previously assigned iIndex. // // EXAMPLE 1: // // CREATE TABLE t (c1 int, c2 int primary key) // CREATE INDEX I1 ON t(c1) // SELECT // * // FROM // t // WHERE // c1 = | < | <= | >= | > ... // AND // c2 = | < | <= | >= | > ... // // currently always chooses iIndex / condition (c1/I1), over // index / condition (c2/pk), whereas index / condition (c2/pk) // may well be better, especially if condition on c2 is equality // (condition_start_end) and conditionon(s) on c1 involve range // (condition_start, condition_end, or some composite). // // Currently, the developer/client software must somehow know facts // both about the table, the query and the way HSQLDB forms its // plans and, based on this knowlege, perhaps decide to reverse // order by explicitly issuing instead: // // SELECT // * // FROM // t // WHERE // c2 = | < | <= | >= | > ... // AND // c1 = | < | <= | >= | > ... // // to get optimal index choice. // // The same thing applies to and is even worse for joins. // // Consider the following (highly artificial, but easy to // understand) case: // // CREATE TABLE T1(ID INTEGER PRIMARY KEY, C1 INTEGER) // CREATE INDEX I1 ON T1(C1) // CREATE TABLE T2(ID INTEGER PRIMARY KEY, C1 INTEGER) // CREATE INDEX I2 ON T2(C1) // // select * from t1, t2 where t1.c1 = t2.c1 and t1.id = t2.id // // Consider the worst value distribution where t1 and t2 are both // 10,000 rows, c1 selectivity is nil (all values are identical) // for both tables, and, say, id values span the range 0..9999 // for both tables. // // Then time to completion on 500 MHz Athlon testbed using memory // tables is: // // 10000 row(s) in 309114 ms // // whereas for: // // select * from t1, t2 where t1.id = t2.id and t1.c1 = t2.c1 // // time to completion is: // // 10000 row(s) in 471 ms // // Hence, the unoptimized query takes 656 times as long as the // optimized one!!! // // EXAMPLE 2: // // If there are, say, two non-unique candidate indexes, // and some range or equality predicates against // them, preference should be given to the one with // better selectivity (if the total row count of the // table is large, otherwise the overhead of making // the choice is probably large w.r.t. any possible // savings). Might require maintaining some basic // statistics or performing appropriate index probes // at the time the plan is being generated. /** * Chooses certain query conditions and assigns a copy of them to this * filter. The original condition is set to Expression.TRUE once assigned. * * @param condition * * @throws HsqlException */ void setConditions(Session session, Expression condition) throws HsqlException { setCondition(session, condition); if (filterIndex == null) { filterIndex = filterTable.getPrimaryIndex(); } if (filterIndex.getVisibleColumns() == 1 || eStart == null || eAnd == null || eStart.exprType != Expression.EQUAL) { return; } boolean[] check = filterTable.getNewColumnCheckList(); Expression[] expr = new Expression[check.length]; int colindex = eStart.getArg().getColumnNr(); check[colindex] = true; expr[colindex] = eStart.getArg2(); eAnd.getEquiJoinColumns(this, check, expr); if (ArrayUtil.containsAllTrueElements(check, filterIndex.colCheck)) { isMultiFindFirst = true; findFirstExpressions = expr; } } private void setCondition(Session session, Expression e) throws HsqlException { int type = e.getType(); Expression e1 = e.getArg(); Expression e2 = e.getArg2(); isAssigned = true; if (type == Expression.AND) { setCondition(session, e1); setCondition(session, e2); return; } if (type == Expression.OR && isOuterJoin && e.isInJoin && e.outerFilter == this) { addAndCondition(e); e.setTrue(); return; } int conditionType = getConditionType(e); if (conditionType == CONDITION_NONE) { // not a condition expression return; }// fredt@users 20030813 - patch 1.7.2 - fix for column comparison within same table bugs #572075 and 722443 if (e1.getFilter() == this && e2.getFilter() == this) { conditionType = CONDITION_UNORDERED; } else if (e1.getFilter() == this) { if (!e.isInJoin && isOuterJoin) { // do not use a where condition on the second table in outer joins return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -