Package org.hsqldb

Source Code of org.hsqldb.QueryExpression

/* Copyright (c) 2001-2009, 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.HsqlNameManager.HsqlName;
import org.hsqldb.ParserDQL.CompileContext;
import org.hsqldb.index.Index;
import org.hsqldb.lib.ArrayListIdentity;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.HashMappedList;
import org.hsqldb.lib.HsqlList;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.lib.OrderedIntHashSet;
import org.hsqldb.lib.Set;
import org.hsqldb.navigator.RowSetNavigatorData;
import org.hsqldb.result.Result;
import org.hsqldb.result.ResultMetaData;
import org.hsqldb.types.Type;

/**
* Implementation of an SQL query expression
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.9.0
*/

/**
* @todo 1.9.0 - review these
* - work out usage of getMainSelect etc and add relevant methods
* - Result metadata for the final result of QueryExpression
*
*/
public class QueryExpression {

    public static final int NOUNION       = 0,
                            UNION         = 1,
                            UNION_ALL     = 2,
                            INTERSECT     = 3,
                            INTERSECT_ALL = 4,
                            EXCEPT_ALL    = 5,
                            EXCEPT        = 6,
                            UNION_TERM    = 7;

    //
    int                     columnCount;
    private QueryExpression leftQueryExpression;
    private QueryExpression rightQueryExpression;
    SortAndSlice            sortAndSlice;
    private int             unionType;
    private boolean         unionCorresponding;
    private OrderedHashSet  unionCorrespondingColumns;
    int[]                   unionColumnMap;
    Type[]                  unionColumnTypes;
    boolean                 isFullOrder;

    //
    HsqlList unresolvedExpressions;

    //
    boolean isResolved;

    //
    int persistenceScope = TableBase.SCOPE_STATEMENT;

    //
    int columnMode = TableBase.COLUMNS_REFERENCED;

    //
    ResultMetaData resultMetaData;
    boolean[]      accessibleColumns;

    //
    View    view;
    boolean isUpdatable;
    boolean isInsertable;
    boolean isCheckable;
    boolean isTopLevel;

    //
    public TableBase resultTable;
    public Index     mainIndex;
    public Index     fullIndex;
    public Index     orderIndex;

    //
    CompileContext compileContext;

    QueryExpression(CompileContext compileContext) {
        this.compileContext = compileContext;
        sortAndSlice        = SortAndSlice.noSort;
    }

    public QueryExpression(CompileContext compileContext,
                           QueryExpression leftQueryExpression) {

        this(compileContext);

        sortAndSlice             = SortAndSlice.noSort;
        this.leftQueryExpression = leftQueryExpression;
    }

    void addUnion(QueryExpression queryExpression, int unionType) {

        sortAndSlice              = SortAndSlice.noSort;
        this.rightQueryExpression = queryExpression;
        this.unionType            = unionType;

        setFullOrder();
    }

    void addSortAndSlice(SortAndSlice sortAndSlice) {
        this.sortAndSlice      = sortAndSlice;
        sortAndSlice.sortUnion = true;
    }

    public void setUnionCorresoponding() {
        unionCorresponding = true;
    }

    public void setUnionCorrespondingColumns(OrderedHashSet names) {
        unionCorrespondingColumns = names;
    }

    public void setFullOrder() {

        isFullOrder = true;

        if (leftQueryExpression == null) {
            return;
        }

        leftQueryExpression.setFullOrder();
        rightQueryExpression.setFullOrder();
    }

    public void resolve(Session session) {

        resolveReferences(session);
        ExpressionColumn.checkColumnsResolved(unresolvedExpressions);
        resolveTypes(session);
    }

    public void resolve(Session session, RangeVariable[] outerRanges) {

        resolveReferences(session);

        if (unresolvedExpressions != null) {
            for (int i = 0; i < unresolvedExpressions.size(); i++) {
                Expression e    = (Expression) unresolvedExpressions.get(i);
                HsqlList   list = e.resolveColumnReferences(outerRanges, null);

                ExpressionColumn.checkColumnsResolved(list);
            }
        }

        resolveTypes(session);
    }

    public void resolveReferences(Session session) {

        leftQueryExpression.resolveReferences(session);
        rightQueryExpression.resolveReferences(session);
        addUnresolvedExpressions(leftQueryExpression.unresolvedExpressions);
        addUnresolvedExpressions(rightQueryExpression.unresolvedExpressions);

        if (!unionCorresponding) {
            columnCount = leftQueryExpression.getColumnCount();

            int rightCount = rightQueryExpression.getColumnCount();

            if (columnCount != rightCount) {
                throw Error.error(ErrorCode.X_42594);
            }

            unionColumnTypes = new Type[columnCount];
            leftQueryExpression.unionColumnMap =
                rightQueryExpression.unionColumnMap = new int[columnCount];

            ArrayUtil.fillSequence(leftQueryExpression.unionColumnMap);
            resolveColumnRefernecesInUnionOrderBy();

            return;
        }

        String[] leftNames  = leftQueryExpression.getColumnNames();
        String[] rightNames = rightQueryExpression.getColumnNames();

        if (unionCorrespondingColumns == null) {
            unionCorrespondingColumns = new OrderedHashSet();

            OrderedIntHashSet leftColumns  = new OrderedIntHashSet();
            OrderedIntHashSet rightColumns = new OrderedIntHashSet();

            for (int i = 0; i < leftNames.length; i++) {
                String name  = leftNames[i];
                int    index = ArrayUtil.find(rightNames, name);

                if (name.length() > 0 && index != -1) {
                    leftColumns.add(i);
                    rightColumns.add(index);
                    unionCorrespondingColumns.add(name);
                }
            }

            if (unionCorrespondingColumns.isEmpty()) {
                throw Error.error(ErrorCode.X_42579);
            }

            leftQueryExpression.unionColumnMap  = leftColumns.toArray();
            rightQueryExpression.unionColumnMap = rightColumns.toArray();
        } else {
            leftQueryExpression.unionColumnMap =
                new int[unionCorrespondingColumns.size()];
            rightQueryExpression.unionColumnMap =
                new int[unionCorrespondingColumns.size()];

            for (int i = 0; i < unionCorrespondingColumns.size(); i++) {
                String name  = (String) unionCorrespondingColumns.get(i);
                int    index = ArrayUtil.find(leftNames, name);

                if (index == -1) {
                    throw Error.error(ErrorCode.X_42579);
                }

                leftQueryExpression.unionColumnMap[i] = index;
                index = ArrayUtil.find(rightNames, name);

                if (index == -1) {
                    throw Error.error(ErrorCode.X_42579);
                }

                rightQueryExpression.unionColumnMap[i] = index;
            }
        }

        columnCount      = unionCorrespondingColumns.size();
        unionColumnTypes = new Type[columnCount];

        resolveColumnRefernecesInUnionOrderBy();
    }

    /**
     * Only simple column reference or column position allowed
     */
    void resolveColumnRefernecesInUnionOrderBy() {

        int orderCount = sortAndSlice.getOrderLength();

        if (orderCount == 0) {
            return;
        }

        String[] unionColumnNames = getColumnNames();

        for (int i = 0; i < orderCount; i++) {
            Expression sort = (Expression) sortAndSlice.exprList.get(i);
            Expression e    = sort.getLeftNode();

            if (e.getType() == OpTypes.VALUE) {
                if (e.getDataType().typeCode == Types.SQL_INTEGER) {
                    int index = ((Integer) e.getValue(null)).intValue();

                    if (0 < index && index <= unionColumnNames.length) {
                        sort.getLeftNode().queryTableColumnIndex = index - 1;

                        continue;
                    }
                }
            } else if (e.getType() == OpTypes.COLUMN) {
                int index = ArrayUtil.find(unionColumnNames,
                                           e.getColumnName());

                if (index >= 0) {
                    sort.getLeftNode().queryTableColumnIndex = index;

                    continue;
                }
            }

            throw Error.error(ErrorCode.X_42576);
        }

        sortAndSlice.prepare(null);
    }

    private void addUnresolvedExpressions(HsqlList expressions) {

        if (expressions == null) {
            return;
        }

        if (unresolvedExpressions == null) {
            unresolvedExpressions = new ArrayListIdentity();
        }

        unresolvedExpressions.addAll(expressions);
    }

    public void resolveTypes(Session session) {

        if (isResolved) {
            return;
        }

        resolveTypesPartOne(session);
        resolveTypesPartTwo(session);

        isResolved = true;
    }

    void resolveTypesPartOne(Session session) {

        ArrayUtil.projectRowReverse(leftQueryExpression.unionColumnTypes,
                                    leftQueryExpression.unionColumnMap,
                                    unionColumnTypes);
        leftQueryExpression.resolveTypesPartOne(session);
        ArrayUtil.projectRow(leftQueryExpression.unionColumnTypes,
                             leftQueryExpression.unionColumnMap,
                             unionColumnTypes);
        ArrayUtil.projectRowReverse(rightQueryExpression.unionColumnTypes,
                                    rightQueryExpression.unionColumnMap,
                                    unionColumnTypes);
        rightQueryExpression.resolveTypesPartOne(session);
        ArrayUtil.projectRow(rightQueryExpression.unionColumnTypes,
                             rightQueryExpression.unionColumnMap,
                             unionColumnTypes);
    }

    void resolveTypesPartTwo(Session session) {

        ArrayUtil.projectRowReverse(leftQueryExpression.unionColumnTypes,
                                    leftQueryExpression.unionColumnMap,
                                    unionColumnTypes);
        leftQueryExpression.resolveTypesPartTwo(session);
        ArrayUtil.projectRowReverse(rightQueryExpression.unionColumnTypes,
                                    rightQueryExpression.unionColumnMap,
                                    unionColumnTypes);
        rightQueryExpression.resolveTypesPartTwo(session);

        //
        if (unionCorresponding) {
            resultMetaData = leftQueryExpression.getMetaData().getNewMetaData(
                leftQueryExpression.unionColumnMap);

            createTable(session);
        }

        if (sortAndSlice.hasOrder()) {
            QueryExpression queryExpression = this;

            while (true) {
                if (queryExpression.leftQueryExpression == null
                        || queryExpression.unionCorresponding) {
                    sortAndSlice.setIndex(queryExpression.resultTable);

                    break;
                }

                queryExpression = queryExpression.leftQueryExpression;
            }
        }
    }

    public Object[] getValues(Session session) {

        Result r    = getResult(session, 2);
        int    size = r.getNavigator().getSize();

        if (size == 0) {
            return new Object[r.metaData.getColumnCount()];
        } else if (size == 1) {
            return r.getSingleRowData();
        } else {
            throw Error.error(ErrorCode.X_21000);
        }
    }

    public Object[] getSingleRowValues(Session session) {

        Result r    = getResult(session, 2);
        int    size = r.getNavigator().getSize();

        if (size == 0) {
            return null;
        } else if (size == 1) {
            return r.getSingleRowData();
        } else {
            throw Error.error(ErrorCode.X_21000);
        }
    }

    public Object getValue(Session session) {

        Object[] values = getValues(session);

        return values[0];
    }

    Result getResult(Session session, int maxRows) {

        int    currentMaxRows = unionType == UNION_ALL ? maxRows
                                                       : Integer.MAX_VALUE;
        Result first = leftQueryExpression.getResult(session, currentMaxRows);
        RowSetNavigatorData navigator =
            (RowSetNavigatorData) first.getNavigator();
        Result second = rightQueryExpression.getResult(session,
            currentMaxRows);
        RowSetNavigatorData rightNavigator =
            (RowSetNavigatorData) second.getNavigator();

        if (unionCorresponding) {
            RowSetNavigatorData rowSet = new RowSetNavigatorData(session,
                this);

            rowSet.copy(navigator, leftQueryExpression.unionColumnMap);

            navigator = rowSet;

            first.setNavigator(navigator);

            first.metaData = this.getMetaData();
            rowSet         = new RowSetNavigatorData(session, this);

            if (unionType != UNION && unionType != UNION_ALL) {
                rowSet.copy(rightNavigator,
                            rightQueryExpression.unionColumnMap);

                rightNavigator = rowSet;
            }
        }

        switch (unionType) {

            case UNION :
                navigator.union(rightNavigator,
                                rightQueryExpression.unionColumnMap);
                break;

            case UNION_ALL :
                navigator.unionAll(rightNavigator,
                                   rightQueryExpression.unionColumnMap);
                break;

            case INTERSECT :
                navigator.intersect(rightNavigator);
                break;

            case INTERSECT_ALL :
                navigator.intersectAll(rightNavigator);
                break;

            case EXCEPT :
                navigator.except(rightNavigator);
                break;

            case EXCEPT_ALL :
                navigator.exceptAll(rightNavigator);
                break;

            default :
                throw Error.runtimeError(ErrorCode.U_S0500, "QueryExpression");
        }

        if (sortAndSlice.hasOrder()) {
            RowSetNavigatorData nav =
                (RowSetNavigatorData) first.getNavigator();

            nav.sortUnion(sortAndSlice);
            nav.trim(sortAndSlice.getLimitStart(session),
                     sortAndSlice.getLimitCount(session, maxRows));
        }

        navigator.reset();

        return first;
    }

    public boolean isSingleColumn() {
        return leftQueryExpression.isSingleColumn();
    }

    public ResultMetaData getMetaData() {

        if (resultMetaData != null) {
            return resultMetaData;
        }

        return leftQueryExpression.getMetaData();
    }

    public QuerySpecification getMainSelect() {

        if (leftQueryExpression == null) {
            return (QuerySpecification) this;
        }

        return leftQueryExpression.getMainSelect();
    }

    /** @todo 1.9.0 review */
    public String describe(Session session) {
        return leftQueryExpression.describe(session);
    }

    public HsqlList getUnresolvedExpressions() {
        return unresolvedExpressions;
    }

    public boolean areColumnsResolved() {
        return unresolvedExpressions == null
               || unresolvedExpressions.isEmpty();
    }

    String[] getColumnNames() {

        if (unionCorrespondingColumns == null) {
            return leftQueryExpression.getColumnNames();
        }

        String[] names = new String[unionCorrespondingColumns.size()];

        unionCorrespondingColumns.toArray(names);

        return names;
    }

    public Type[] getColumnTypes() {
        return unionColumnTypes;
    }

    public int getColumnCount() {

        if (unionCorrespondingColumns == null) {
            int left  = leftQueryExpression.getColumnCount();
            int right = rightQueryExpression.getColumnCount();

            if (left != right) {
                throw Error.error(ErrorCode.X_42594);
            }

            return left;
        }

        return unionCorrespondingColumns.size();
    }

    public void collectAllExpressions(HsqlList set, OrderedIntHashSet typeSet,
                                      OrderedIntHashSet stopAtTypeSet) {

        leftQueryExpression.collectAllExpressions(set, typeSet, stopAtTypeSet);

        if (rightQueryExpression != null) {
            rightQueryExpression.collectAllExpressions(set, typeSet,
                    stopAtTypeSet);
        }
    }

    public void collectObjectNames(Set set) {

        leftQueryExpression.collectObjectNames(set);

        if (rightQueryExpression != null) {
            rightQueryExpression.collectObjectNames(set);
        }
    }

    public HashMappedList getColumns() {

        this.getResultTable();

        return ((TableDerived) getResultTable()).columnList;
    }

    /**
     * Used prior to type resolution
     */
    public void setView(View view) {
        this.view = view;
    }

    /**
     * Used in views after full type resolution
     */
    public void setTableColumnNames(HashMappedList list) {

        if (resultTable != null) {
            ((TableDerived) resultTable).columnList = list;

            return;
        }

        leftQueryExpression.setTableColumnNames(list);
    }

    void createTable(Session session) {

        createResultTable(session);

        mainIndex = resultTable.getPrimaryIndex();

        if (sortAndSlice.hasOrder()) {
            orderIndex = resultTable.createAndAddIndexStructure(null,
                    sortAndSlice.sortOrder, sortAndSlice.sortDescending,
                    sortAndSlice.sortNullsLast, false, false, false);
        }

        int[] fullCols = new int[columnCount];

        ArrayUtil.fillSequence(fullCols);

        fullIndex = resultTable.createAndAddIndexStructure(null, fullCols,
                null, null, false, false, false);
        resultTable.fullIndex = fullIndex;
    }

    void createResultTable(Session session) {

        HsqlName       tableName;
        HashMappedList columnList;
        int            tableType;

        tableName = session.database.nameManager.getSubqueryTableName();
        tableType = persistenceScope == TableBase.SCOPE_STATEMENT
                    ? TableBase.SYSTEM_SUBQUERY
                    : TableBase.RESULT_TABLE;
        columnList = leftQueryExpression.getUnionColumns();

        try {
            resultTable = new TableDerived(session.database, tableName,
                                           tableType, unionColumnTypes,
                                           columnList, null);
        } catch (Exception e) {}
    }

    public void setColumnsDefined() {

        columnMode = TableBase.COLUMNS_REFERENCED;

        if (leftQueryExpression != null) {
            leftQueryExpression.setColumnsDefined();
        }
    }

    /**
     * Not for views. Only used on root node.
     */
    public void setAsTopLevel() {

        if (compileContext.getSequences().length > 0) {
            throw Error.error(ErrorCode.X_42598);
        }

        isTopLevel = true;

        setReturningResultSet();
    }

    /**
     * Sets the scope to SESSION for the QueryExpression object that creates
     * the table
     */
    void setReturningResultSet() {

        if (unionCorresponding) {
            persistenceScope = TableBase.SCOPE_SESSION;
            columnMode       = TableBase.COLUMNS_UNREFERENCED;

            return;
        }

        leftQueryExpression.setReturningResultSet();
    }

    private HashMappedList getUnionColumns() {

        if (unionCorresponding || leftQueryExpression == null) {
            HashMappedList columns = ((TableDerived) resultTable).columnList;
            HashMappedList list    = new HashMappedList();

            for (int i = 0; i < unionColumnMap.length; i++) {
                ColumnSchema column = (ColumnSchema) columns.get(i);

                list.add(column.getName().name, column);
            }

            return list;
        }

        return leftQueryExpression.getUnionColumns();
    }

    public HsqlName[] getResultColumnNames() {

        if (resultTable == null) {
            return leftQueryExpression.getResultColumnNames();
        }

        HashMappedList list = ((TableDerived) resultTable).columnList;
        HsqlName[]     resultColumnNames = new HsqlName[list.size()];

        for (int i = 0; i < resultColumnNames.length; i++) {
            resultColumnNames[i] = ((ColumnSchema) list.get(i)).getName();
        }

        return resultColumnNames;
    }

    public TableBase getResultTable() {

        if (resultTable != null) {
            return resultTable;
        }

        if (leftQueryExpression != null) {
            return leftQueryExpression.getResultTable();
        }

        return null;
    }

    //
    public Table getBaseTable() {
        return null;
    }

    public boolean isUpdatable() {
        return isUpdatable;
    }

    public boolean isInsertable() {
        return isInsertable;
    }

    public int[] getBaseTableColumnMap() {
        return null;
    }

    public Expression getCheckCondition() {
        return null;
    }

    public boolean hasReference(RangeVariable range) {

        if (leftQueryExpression.hasReference(range)) {
            return true;
        }

        if (rightQueryExpression.hasReference(range)) {
            return true;
        }

        return false;
    }

    void getBaseTableNames(OrderedHashSet set) {
        leftQueryExpression.getBaseTableNames(set);
        rightQueryExpression.getBaseTableNames(set);
    }
}
TOP

Related Classes of org.hsqldb.QueryExpression

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.