All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hsqldb.QueryExpression Maven / Gradle / Ivy

There is a newer version: 10.0.0
Show newest version
/* Copyright (c) 2001-2022, 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.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.index.Index;
import org.hsqldb.lib.ArrayListIdentity;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.List;
import org.hsqldb.lib.OrderedHashMap;
import org.hsqldb.lib.OrderedHashSet;
import org.hsqldb.lib.OrderedIntHashSet;
import org.hsqldb.lib.Set;
import org.hsqldb.map.ValuePool;
import org.hsqldb.navigator.RowSetNavigatorData;
import org.hsqldb.navigator.RowSetNavigatorDataTable;
import org.hsqldb.persist.PersistentStore;
import org.hsqldb.result.Result;
import org.hsqldb.result.ResultMetaData;
import org.hsqldb.types.Type;
import org.hsqldb.types.Types;

/**
 * Implementation of an SQL query expression
 *
 * @author Fred Toussi (fredt@users dot sourceforge.net)
 * @version 2.7.0
 * @since 1.9.0
 */
public class QueryExpression implements RangeGroup {

    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;
    QueryExpression        leftQueryExpression;
    QueryExpression        rightQueryExpression;
    public SortAndSlice    sortAndSlice;
    private int            unionType;
    private boolean        unionCorresponding;
    private OrderedHashSet unionCorrespondingColumns;
    int[]                  unionColumnMap;
    Type[]                 unionColumnTypes;
    boolean                isFullOrder;

    //
    List unresolvedExpressions;

    //
    boolean isReferencesResolved;
    boolean isPartOneResolved;
    boolean isPartTwoResolved;
    boolean isResolved;

    //
    int persistenceScope = TableBase.SCOPE_STATEMENT;

    //
    ResultMetaData resultMetaData;
    boolean[]      accessibleColumns;

    //
    View             view;
    boolean          isBaseMergeable;
    boolean          isMergeable;
    boolean          isUpdatable;
    boolean          isInsertable;
    boolean          isCheckable;
    boolean          isTopLevel;
    boolean          isRecursive;
    boolean          isSingleRow;
    boolean          acceptsSequences;
    boolean          isCorrelated;
    boolean          isTable;
    boolean          isValueList;
    boolean          lowerCaseResultIdentifier;
    public TableBase resultTable;
    public Index     mainIndex;
    public Index     fullIndex;
    public Index     orderIndex;
    public Index     idIndex;

    //
    TableDerived           recursiveWorkTable;
    TableDerived           recursiveResultTable;
    RecursiveQuerySettings recursiveSettings;
    TableDerived[]         materialiseList = TableDerived.emptyArray;

    //
    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;
    }

    public RangeVariable[] getRangeVariables() {
        return RangeVariable.emptyArray;
    }

    public void setCorrelated() {
        isCorrelated = true;
    }

    public boolean isVariable() {
        return false;
    }

    public void setSingleRow() {
        isSingleRow = true;
    }

    public boolean isRecursive() {
        return isRecursive;
    }

    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) {
            leftQueryExpression.setFullOrder();
        }

        if (rightQueryExpression != null) {
            rightQueryExpression.setFullOrder();
        }
    }

    public void resolve(Session session) {

        resolveReferences(session, RangeGroup.emptyArray);
        ExpressionColumn.checkColumnsResolved(unresolvedExpressions);
        resolveTypes(session);
    }

    public void resolve(Session session, RangeGroup[] rangeGroups,
                        Type[] targetTypes) {

        resolveReferences(session, rangeGroups);
        ExpressionColumn.checkColumnsResolved(unresolvedExpressions);
        resolveTypesPartOne(session);

        if (targetTypes != null) {
            for (int i = 0;
                    i < unionColumnTypes.length && i < targetTypes.length;
                    i++) {
                if (unionColumnTypes[i] == null) {
                    unionColumnTypes[i] = targetTypes[i];
                }
            }
        }

        resolveTypesPartTwo(session);
        resolveTypesPartThree(session);
    }

    public void resolveReferences(Session session, RangeGroup[] rangeGroups) {

        if (isReferencesResolved) {
            return;
        }

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

        if (leftQueryExpression.isCorrelated
                || rightQueryExpression.isCorrelated) {
            setCorrelated();
        }

        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);
            resolveColumnReferencesInUnionOrderBy();

            accessibleColumns    = leftQueryExpression.accessibleColumns;
            isReferencesResolved = true;

            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) {
                    if (!leftQueryExpression.accessibleColumns[i]) {
                        throw Error.error(ErrorCode.X_42578);
                    }

                    if (!rightQueryExpression.accessibleColumns[index]) {
                        throw Error.error(ErrorCode.X_42578);
                    }

                    leftColumns.add(i);
                    rightColumns.add(index);
                    unionCorrespondingColumns.add(name);
                }
            }

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

            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_42501);
                }

                if (!leftQueryExpression.accessibleColumns[index]) {
                    throw Error.error(ErrorCode.X_42578);
                }

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

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

                if (!rightQueryExpression.accessibleColumns[index]) {
                    throw Error.error(ErrorCode.X_42578);
                }

                rightQueryExpression.unionColumnMap[i] = index;
            }
        }

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

        resolveColumnReferencesInUnionOrderBy();

        accessibleColumns = new boolean[columnCount];

        ArrayUtil.fillArray(accessibleColumns, true);

        isReferencesResolved = true;
    }

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

        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().resultTableColumnIndex = index - 1;

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

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

                    continue;
                }
            }

            throw Error.error(ErrorCode.X_42576);
        }

        sortAndSlice.prepare(0);
    }

    private void addUnresolvedExpressions(List 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);
        resolveTypesPartThree(session);
    }

    void resolveTypesPartOne(Session session) {

        if (isPartOneResolved) {
            return;
        }

        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);

        isPartOneResolved = true;
    }

    void resolveTypesPartTwoRecursive(Session session) {
        resolveTypesPartTwo(session);
    }

    void resolveTypesPartTwo(Session session) {

        if (isPartTwoResolved) {
            return;
        }

        ArrayUtil.projectRowReverse(leftQueryExpression.unionColumnTypes,
                                    leftQueryExpression.unionColumnMap,
                                    unionColumnTypes);

        if (isRecursive) {
            leftQueryExpression.resolveTypesPartTwoRecursive(session);

            recursiveWorkTable.colTypes = leftQueryExpression.getColumnTypes();

            for (int i = 0; i < recursiveWorkTable.colTypes.length; i++) {
                recursiveWorkTable.getColumn(i).setType(
                    recursiveWorkTable.colTypes[i]);
            }

            recursiveWorkTable.getFullIndex(session);
        } else {
            leftQueryExpression.resolveTypesPartTwo(session);
        }

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

        //
        ResultMetaData leftMeta  = leftQueryExpression.getMetaData();
        ResultMetaData rightMeta = rightQueryExpression.getMetaData();

        for (int i = 0; i < leftQueryExpression.unionColumnMap.length; i++) {
            int        leftIndex  = leftQueryExpression.unionColumnMap[i];
            int        rightIndex = rightQueryExpression.unionColumnMap[i];
            ColumnBase column     = leftMeta.columns[leftIndex];
            byte leftNullability =
                leftMeta.columns[leftIndex].getNullability();
            byte rightNullability =
                rightMeta.columns[rightIndex].getNullability();

            if (rightNullability == SchemaObject.Nullability
                    .NULLABLE || (rightNullability == SchemaObject.Nullability
                        .NULLABLE_UNKNOWN && leftNullability == SchemaObject
                        .Nullability.NO_NULLS)) {
                if (column instanceof ColumnSchema) {
                    column = new ColumnBase();

                    column.setType(leftQueryExpression.unionColumnTypes[i]);

                    leftMeta.columns[leftIndex] = column;
                }

                column.setNullability(rightNullability);
            }
        }

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

            createTable(session);
        }

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

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

                    break;
                }

                queryExpression = queryExpression.leftQueryExpression;
            }
        }

        isPartTwoResolved = true;
    }

    void resolveTypesPartThree(Session session) {
        compileContext = null;
        isResolved     = true;
    }

    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 void addExtraConditions(Expression e) {}

    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) {

        if (isRecursive) {
            return getResultRecursive(session);
        }

        int    currentMaxRows = unionType == UNION_ALL ? maxRows
                                                       : 0;
        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;
            boolean memory =
                session.resultMaxMemoryRows == 0
                || (navigator.getSize() < session.resultMaxMemoryRows
                    && rightNavigator.getSize() < session.resultMaxMemoryRows);

            if (memory) {
                rowSet = new RowSetNavigatorData(session, this);
            } else {
                rowSet = new RowSetNavigatorDataTable(session, this);
            }

            rowSet.copy(navigator, leftQueryExpression.unionColumnMap);
            navigator.release();

            navigator = rowSet;

            first.setNavigator(navigator);

            first.metaData = getMetaData();

            if (memory) {
                rowSet = new RowSetNavigatorData(session, this);
            } else {
                rowSet = new RowSetNavigatorDataTable(session, this);
            }

            rowSet.copy(rightNavigator, rightQueryExpression.unionColumnMap);
            rightNavigator.release();

            rightNavigator = rowSet;
        }

        switch (unionType) {

            case UNION :
                navigator.union(rightNavigator);
                break;

            case UNION_ALL :
                navigator.unionAll(rightNavigator);
                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");
        }

        rightNavigator.release();

        if (sortAndSlice.hasOrder()) {
            navigator.sortOrderUnion(sortAndSlice);
        }

        if (sortAndSlice.hasLimit()) {
            int[] limits = sortAndSlice.getLimits(session, this, maxRows);

            navigator.trim(limits[0], limits[1]);
        }

        navigator.reset();

        return first;
    }

    public void setRecursiveQuerySettings(RecursiveQuerySettings settings) {

        OrderedHashSet subqueryList = rightQueryExpression.getSubqueries();
        OrderedHashSet refList      = new OrderedHashSet();

        if (subqueryList == null) {
            subqueryList = new OrderedHashSet();
        }

        for (int i = 0; i < subqueryList.size(); i++) {
            TableDerived td = (TableDerived) subqueryList.get(i);

            if (td.isCorrelated()) {
                continue;
            }

            QueryExpression qe = td.queryExpression;

            if (qe == null) {
                continue;
            }

            refList = qe.collectRangeVariables(refList);

            for (int j = 0; j < refList.size(); j++) {
                RangeVariable range = (RangeVariable) refList.get(j);

                if (range.rangeTable == recursiveWorkTable
                        || range.rangeTable == recursiveResultTable) {
                    materialiseList =
                        ArrayUtil.toAdjustedArray(materialiseList, td);

                    break;
                }
            }
        }

        recursiveSettings = settings;
    }

    Result getResultRecursive(Session session) {

        RowSetNavigatorData resultNav = new RowSetNavigatorData(session, this);
        Result leftResult = leftQueryExpression.getResult(session, 0);
        PersistentStore recursiveStore =
            recursiveWorkTable.getRowStore(session);
        PersistentStore recursiveResultStore =
            recursiveResultTable.getRowStore(session);

        leftResult.getNavigator().reset();
        recursiveWorkTable.insertSys(session, recursiveStore, leftResult);
        leftResult.getNavigator().reset();
        recursiveResultTable.insertSys(session, recursiveResultStore,
                                       leftResult);
        resultNav.unionAll((RowSetNavigatorData) leftResult.getNavigator());

        for (int round = 0; ; round++) {
            for (int i = 0; i < materialiseList.length; i++) {
                materialiseList[i].materialise(session);
            }

            Result currentResult = rightQueryExpression.getResult(session, 0);
            RowSetNavigatorData currentNavigator =
                (RowSetNavigatorData) currentResult.getNavigator();

            if (currentNavigator.isEmpty()) {
                break;
            }

            int startSize = resultNav.getSize();

            switch (unionType) {

                case UNION :
                    resultNav.union(currentNavigator);
                    break;

                case UNION_ALL :
                    resultNav.unionAll(currentNavigator);
                    break;

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

            if (startSize == resultNav.getSize()) {
                break;
            }

            if (round > session.database.sqlMaxRecursive) {
                throw Error.error(ErrorCode.X_22522);
            }

            currentNavigator.reset();
            recursiveResultTable.insertSys(session, recursiveResultStore,
                                           currentResult);
            recursiveStore.removeAll();
            currentNavigator.reset();
            recursiveWorkTable.insertSys(session, recursiveStore,
                                         currentResult);
        }

        Result result = Result.newResult(resultNav);

        result.metaData = resultMetaData;

        return result;
    }

    public OrderedHashSet getSubqueries() {

        OrderedHashSet subqueries = leftQueryExpression.getSubqueries();

        subqueries =
            OrderedHashSet.addAll(subqueries,
                                  rightQueryExpression.getSubqueries());

        return subqueries;
    }

    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 regular review */
    public String describe(Session session, int blanks) {

        StringBuilder sb;
        String        temp;
        StringBuilder b = new StringBuilder(blanks);

        for (int i = 0; i < blanks; i++) {
            b.append(' ');
        }

        sb = new StringBuilder();

        switch (unionType) {

            case UNION :
                temp = Tokens.T_UNION;
                break;

            case UNION_ALL :
                temp = Tokens.T_UNION + ' ' + Tokens.T_ALL;
                break;

            case INTERSECT :
                temp = Tokens.T_INTERSECT;
                break;

            case INTERSECT_ALL :
                temp = Tokens.T_INTERSECT + ' ' + Tokens.T_ALL;
                break;

            case EXCEPT :
                temp = Tokens.T_EXCEPT;
                break;

            case EXCEPT_ALL :
                temp = Tokens.T_EXCEPT + ' ' + Tokens.T_ALL;
                break;

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

        sb.append(b).append(temp).append("\n");
        sb.append(b).append("Left Query=[\n");
        sb.append(b).append(leftQueryExpression.describe(session, blanks + 2));
        sb.append(b).append("]\n");
        sb.append(b).append("Right Query=[\n");
        sb.append(b).append(rightQueryExpression.describe(session,
                blanks + 2));
        sb.append(b).append("]\n");

        return sb.toString();
    }

    public List getUnresolvedExpressions() {
        return unresolvedExpressions;
    }

    public boolean areColumnsResolved() {

        if (unresolvedExpressions == null || unresolvedExpressions.isEmpty()) {
            return true;
        }

        for (int i = 0; i < unresolvedExpressions.size(); i++) {
            Expression e = (Expression) unresolvedExpressions.get(i);

            if (e.getRangeVariable() == null) {
                return false;
            }

            if (e.getRangeVariable().rangeType == RangeVariable.TABLE_RANGE) {
                return false;
            }
        }

        return true;
    }

    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 OrderedHashSet collectAllExpressions(OrderedHashSet set,
            OrderedIntHashSet typeSet, OrderedIntHashSet stopAtTypeSet) {

        set = leftQueryExpression.collectAllExpressions(set, typeSet,
                stopAtTypeSet);

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

        return set;
    }

    OrderedHashSet collectRangeVariables(RangeVariable[] rangeVars,
                                         OrderedHashSet set) {

        set = leftQueryExpression.collectRangeVariables(rangeVars, set);

        if (rightQueryExpression != null) {
            set = rightQueryExpression.collectRangeVariables(rangeVars, set);
        }

        return set;
    }

    OrderedHashSet collectRangeVariables(OrderedHashSet set) {

        set = leftQueryExpression.collectRangeVariables(set);

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

        return set;
    }

    public void collectObjectNames(Set set) {

        leftQueryExpression.collectObjectNames(set);

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

    public OrderedHashMap getColumns() {

        TableDerived table = (TableDerived) getResultTable();

        return table.columnList;
    }

    /**
     * Used prior to type resolution
     */
    public void setView(View view) {

        this.view             = view;
        this.isUpdatable      = true;
        this.acceptsSequences = true;
        this.isTopLevel       = true;
    }

    /**
     * Used in views after full type resolution
     */
    public void setTableColumnNames(OrderedHashMap 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 = sortAndSlice.getNewIndex(session, resultTable);
        }

        int[] fullCols = new int[columnCount];

        ArrayUtil.fillSequence(fullCols);

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

    void createResultTable(Session session) {

        HsqlName       tableName;
        OrderedHashMap columnList;
        int            tableType;

        tableName = session.database.nameManager.getSubqueryTableName();
        tableType = persistenceScope == TableBase.SCOPE_STATEMENT
                    ? TableBase.SYSTEM_SUBQUERY
                    : TableBase.RESULT_TABLE;
        columnList = leftQueryExpression.getUnionColumns();
        resultTable = new TableDerived(session.database, tableName, tableType,
                                       unionColumnTypes, columnList,
                                       ValuePool.emptyIntArray);
    }

    public void setColumnsDefined() {

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

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

        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;

            return;
        }

        leftQueryExpression.setReturningResultSet();
    }

    private OrderedHashMap getUnionColumns() {

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

            for (int i = 0; i < unionColumnMap.length; i++) {
                ColumnSchema column =
                    (ColumnSchema) columns.get(unionColumnMap[i]);
                String name = (String) columns.getKeyAt(unionColumnMap[i]);

                list.add(name, column);
            }

            return list;
        }

        return leftQueryExpression.getUnionColumns();
    }

    public HsqlName[] getResultColumnNames() {

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

        OrderedHashMap 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);
    }

    boolean isEquivalent(QueryExpression other) {

        return leftQueryExpression.isEquivalent(other.leftQueryExpression)
               && unionType == other.unionType
               && (rightQueryExpression == null
                   ? other.rightQueryExpression == null
                   : rightQueryExpression.isEquivalent(
                       other.rightQueryExpression));
    }

    public void replaceColumnReferences(Session session, RangeVariable range,
                                        Expression[] list) {
        leftQueryExpression.replaceColumnReferences(session, range, list);
        rightQueryExpression.replaceColumnReferences(session, range, list);
    }

    public void replaceRangeVariables(RangeVariable[] ranges,
                                      RangeVariable[] newRanges) {
        leftQueryExpression.replaceRangeVariables(ranges, newRanges);
        rightQueryExpression.replaceRangeVariables(ranges, newRanges);
    }

    /**
     * non-working temp code for replacing aggregate functions with simple column
     */
    public void replaceExpressions(OrderedHashSet expressions,
                                   int resultRangePosition) {

        leftQueryExpression.replaceExpressions(expressions,
                                               resultRangePosition);
        rightQueryExpression.replaceExpressions(expressions,
                resultRangePosition);
    }

    public void setAsExists() {}

    public void setLowerCaseResultIdentifer() {
        lowerCaseResultIdentifier = true;
    }

    static class RecursiveQuerySettings {

        static final int none         = 0;
        static final int depthFirst   = 1;
        static final int breadthFirst = 2;
        static final int findCycle    = 1;
        int              searchOrderType;
        SortAndSlice     searchOrderSort;
        ColumnSchema     searchOrderSetColumn;
        int              cycle;
        int[]            cycleColumnList;
        ColumnSchema     cycleColumnFirst;
        ColumnSchema     cycleMarkColumn;
        String           cycleMarkValue;
        String           noCycleMarkValue;
        ColumnSchema     cyclePathColumn;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy