📄 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;// 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; 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, boolean outerjoin) { filterTable = t; tableAlias = alias == null ? t.getName().name : alias; 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; currentJoinData = filterTable.getEmptyRowData(); } } 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 + -