alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

HSQLDB example source code file (Index.java)

This example HSQLDB source code file (Index.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - HSQLDB tags/keywords

hsqlexception, hsqlexception, hsqlname, index, indexrowiterator, indexrowiterator, node, node, object, object, row, rowiterator, string, table, util

The HSQLDB Index.java source code

/*
 * For work developed by the HSQL Development Group:
 *
 * Copyright (c) 2001-2010, 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.
 *
 *
 *
 * For work originally developed by the Hypersonic SQL Group:
 *
 * 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.
 */


package org.hsqldb;

import java.util.NoSuchElementException;

import org.hsqldb.HsqlNameManager.HsqlName;
import org.hsqldb.index.RowIterator;
import org.hsqldb.lib.ArrayUtil;

// fredt@users 20020221 - patch 513005 by sqlbob@users - corrections
// fredt@users 20020225 - patch 1.7.0 - changes to support cascading deletes
// tony_lai@users 20020820 - patch 595052 - better error message
// fredt@users 20021205 - patch 1.7.2 - changes to method signature
// fredt@users - patch 1.80 - reworked the interface and comparison methods

/**
 * Implementation of an AVL tree with parent pointers in nodes. Subclasses
 * of Node implement the tree node objects for memory or disk storage. An
 * Index has a root Node that is linked with other nodes using Java Object
 * references or file pointers, depending on Node implementation.<p>
 * An Index object also holds information on table columns (in the form of int
 * indexes) that are covered by it.(fredt@users)
 *
 * @author Thomas Mueller (Hypersonic SQL Group)
 * @version 1.8.0
 * @since Hypersonic SQL
 */
public class Index {

    // types of index
    static final int MEMORY_INDEX  = 0;
    static final int DISK_INDEX    = 1;
    static final int POINTER_INDEX = 2;

    // fields
    private final HsqlName indexName;
    final boolean[]        colCheck;
    final int[]            colIndex;
    private final int[]    colTypes;
    final int[]            pkCols;
    final int[]            pkTypes;
    private final boolean  isUnique;    // DDL uniqueness
    private final boolean  useRowId;
    final boolean          isConstraint;
    final boolean          isForward;
    final boolean          isTemp;
    private Node           root;
    private int            depth;
    final Collation        collation;
    static IndexRowIterator emptyIterator = new IndexRowIterator(null, null,
        null);
    IndexRowIterator updatableIterators;
    final boolean    onCommitPreserve;
    final Table      table;

    /**
     * Constructor declaration
     *
     *
     * @param name HsqlName of the index
     * @param table table of the index
     * @param column array of column indexes
     * @param type array of column types
     * @param unique is this a unique index
     * @param constraint does this index belonging to a constraint
     * @param forward is this an auto-index for an FK that refers to a table defined after this table
     * @param visColumns count of visible columns
     */
    Index(Database database, HsqlName name, Table table, int[] column,
            int[] colTypes, boolean isPk, boolean unique, boolean constraint,
            boolean forward, int[] pkcols, int[] pktypes, boolean temp) {

        this.table     = table;
        this.indexName = name;
        this.colIndex  = column;
        this.colTypes  = colTypes;
        this.pkCols    = pkcols;
        this.pkTypes   = pktypes;
        isUnique       = unique;
        isConstraint   = constraint;
        isForward      = forward;
        useRowId = (!isUnique && pkCols.length == 0) || (colIndex.length == 0);
        colCheck       = table.getNewColumnCheckList();

        ArrayUtil.intIndexesToBooleanArray(colIndex, colCheck);

        updatableIterators      = new IndexRowIterator(null, null, null);
        updatableIterators.next = updatableIterators.last = updatableIterators;
        collation               = database.collation;
        isTemp                  = temp;
        onCommitPreserve        = table.onCommitPreserve;
    }

    /**
     * Returns the HsqlName object
     */
    HsqlName getName() {
        return indexName;
    }

    /**
     * Changes index name. Used by 'alter index rename to'. Argument isquoted
     * is true if the name was quoted in the DDL.
     */
    void setName(String name, boolean isquoted) throws HsqlException {
        indexName.rename(name, isquoted);
    }

    /**
     * Returns the count of visible columns used
     */
    int getVisibleColumns() {
        return colIndex.length;
    }

    /**
     * Is this a UNIQUE index?
     */
    boolean isUnique() {
        return isUnique;
    }

    /**
     * Does this index belong to a constraint?
     */
    boolean isConstraint() {
        return isConstraint;
    }

    /**
     * Returns the array containing column indexes for index
     */
    int[] getColumns() {
        return colIndex;    // todo: this gives back also primary key field(s)!
    }

    /**
     * Returns the array containing column indexes for index
     */
    int[] getColumnTypes() {
        return colTypes;    // todo: this gives back also primary key field(s)!
    }

    String getColumnNameList() {

        String columnNameList = "";

        for (int j = 0; j < colIndex.length; ++j) {
            columnNameList +=
                table.getColumn(colIndex[j]).columnName.statementName;

            if (j < colIndex.length - 1) {
                columnNameList += ",";
            }
        }

        return columnNameList;
    }

    /**
     * Returns the node count.
     */
    int size(Session session) throws HsqlException {

        int         count = 0;
        RowIterator it    = firstRow(session);

        while (it.hasNext()) {
            it.next();

            count++;
        }

        return count;
    }

    boolean isEmpty(Session session) {
        return getRoot(session) == null;
    }

    public int sizeEstimate() throws HsqlException {

        firstRow(null);

        return (int) (1L << depth);
    }

    void clearAll(Session session) {

        setRoot(session, null);

        depth                   = 0;
        updatableIterators.next = updatableIterators.last = updatableIterators;
    }

    void clearIterators() {
        updatableIterators.next = updatableIterators.last = updatableIterators;
    }

    void setRoot(Session session, Node node) {

        if (isTemp) {
            session.setIndexRoot(indexName, onCommitPreserve, node);
        } else {
            root = node;
        }
    }

    int getRoot() {
        return (root == null) ? -1
                              : root.getKey();
    }

    private Node getRoot(Session session) {

        if (isTemp && session != null) {
            return session.getIndexRoot(indexName, onCommitPreserve);
        } else {
            return root;
        }
    }

    /**
     * Insert a node into the index
     */
    void insert(Session session, Row row, int offset) throws HsqlException {

        Node    n       = getRoot(session);
        Node    x       = n;
        boolean isleft  = true;
        int     compare = -1;

        while (true) {
            if (n == null) {
                if (x == null) {
                    setRoot(session, row.getNode(offset));

                    return;
                }

                set(x, isleft, row.getNode(offset));

                break;
            }

            compare = compareRowForInsert(session, row, n.getRow());

            if (compare == 0) {
                int    errorCode = Trace.VIOLATION_OF_UNIQUE_INDEX;
                String name      = indexName.statementName;

                if (isConstraint) {
                    Constraint c = table.getUniqueOrPKConstraintForIndex(this);

                    if (c != null) {
                        name      = c.getName().name;
                        errorCode = Trace.VIOLATION_OF_UNIQUE_CONSTRAINT;
                    }
                }

                throw Trace.error(errorCode, new Object[] {
                    name, getColumnNameList()
                });
            }

            isleft = compare < 0;
            x      = n;
            n      = child(x, isleft);
        }

        balance(session, x, isleft);
    }

    /**
     * Balances part of the tree after an alteration to the index.
     */
    private void balance(Session session, Node x,
                         boolean isleft) throws HsqlException {

        while (true) {
            int sign = isleft ? 1
                              : -1;

            x = x.getUpdatedNode();

            switch (x.getBalance() * sign) {

                case 1 :
                    x.setBalance(0);

                    return;

                case 0 :
                    x.setBalance(-sign);
                    break;

                case -1 :
                    Node l = child(x, isleft);

                    if (l.getBalance() == -sign) {
                        replace(session, x, l);
                        set(x, isleft, child(l, !isleft));
                        set(l, !isleft, x);

                        x = x.getUpdatedNode();

                        x.setBalance(0);

                        l = l.getUpdatedNode();

                        l.setBalance(0);
                    } else {
                        Node r = child(l, !isleft);

                        replace(session, x, r);
                        set(l, !isleft, child(r.getUpdatedNode(), isleft));
                        set(r, isleft, l);
                        set(x, isleft, child(r.getUpdatedNode(), !isleft));
                        set(r, !isleft, x);

                        int rb = r.getUpdatedNode().getBalance();

                        x.getUpdatedNode().setBalance((rb == -sign) ? sign
                                                                    : 0);
                        l.getUpdatedNode().setBalance((rb == sign) ? -sign
                                                                   : 0);
                        r.getUpdatedNode().setBalance(0);
                    }

                    return;
            }

            x = x.getUpdatedNode();

            if (x.isRoot()) {
                return;
            }

            isleft = x.isFromLeft();
            x      = x.getParent();
        }
    }

    /**
     * Delete a node from the index
     */
    void delete(Session session, Node x) throws HsqlException {

        if (x == null) {
            return;
        }

        for (IndexRowIterator it = updatableIterators.next;
                it != updatableIterators; it = it.next) {
            it.updateForDelete(x);
        }

        Node n;

        if (x.getLeft() == null) {
            n = x.getRight();
        } else if (x.getRight() == null) {
            n = x.getLeft();
        } else {
            Node d = x;

            x = x.getLeft();

/*
            // todo: this can be improved

            while (x.getRight() != null) {
                if (Trace.STOP) {
                    Trace.stop();
                }

                x = x.getRight();
            }
*/
            for (Node temp = x; (temp = temp.getRight()) != null; ) {
                x = temp;
            }

            // x will be replaced with n later
            n = x.getLeft();

            // swap d and x
            int b = x.getBalance();

            x = x.getUpdatedNode();

            x.setBalance(d.getBalance());

            d = d.getUpdatedNode();

            d.setBalance(b);

            // set x.parent
            Node xp = x.getParent();
            Node dp = d.getParent();

            x = x.getUpdatedNode();

            if (d.isRoot()) {
                setRoot(session, x);
            }

            x.setParent(dp);

            if (dp != null) {
                dp = dp.getUpdatedNode();

                if (dp.isRight(d)) {
                    dp.setRight(x);
                } else {
                    dp.setLeft(x);
                }
            }

            // relink d.parent, x.left, x.right
            d = d.getUpdatedNode();

            if (d.equals(xp)) {
                d.setParent(x);

                if (d.isLeft(x)) {
                    x = x.getUpdatedNode();

                    x.setLeft(d);

                    Node dr = d.getRight();

                    x = x.getUpdatedNode();

                    x.setRight(dr);
                } else {
                    x.setRight(d);

                    Node dl = d.getLeft();

                    x = x.getUpdatedNode();

                    x.setLeft(dl);
                }
            } else {
                d.setParent(xp);

                xp = xp.getUpdatedNode();

                xp.setRight(d);

                Node dl = d.getLeft();
                Node dr = d.getRight();

                x = x.getUpdatedNode();

                x.setLeft(dl);
                x.setRight(dr);
            }

            x.getRight().setParent(x);
            x.getLeft().setParent(x);

            // set d.left, d.right
            d = d.getUpdatedNode();

            d.setLeft(n);

            if (n != null) {
                n = n.getUpdatedNode();

                n.setParent(d);
            }

            d = d.getUpdatedNode();

            d.setRight(null);

            x = d;
        }

        boolean isleft = x.isFromLeft();

        replace(session, x, n);

        n = x.getParent();
        x = x.getUpdatedNode();

        x.delete();

        while (n != null) {
            x = n;

            int sign = isleft ? 1
                              : -1;

            x = x.getUpdatedNode();

            switch (x.getBalance() * sign) {

                case -1 :
                    x.setBalance(0);
                    break;

                case 0 :
                    x.setBalance(sign);

                    return;

                case 1 :
                    Node r = child(x, !isleft);
                    int  b = r.getBalance();

                    if (b * sign >= 0) {
                        replace(session, x, r);
                        set(x, !isleft, child(r, isleft));
                        set(r, isleft, x);

                        if (b == 0) {
                            x = x.getUpdatedNode();

                            x.setBalance(sign);

                            r = r.getUpdatedNode();

                            r.setBalance(-sign);

                            return;
                        }

                        x = x.getUpdatedNode();

                        x.setBalance(0);

                        r = r.getUpdatedNode();

                        r.setBalance(0);

                        x = r;
                    } else {
                        Node l = child(r, isleft);

                        replace(session, x, l);

                        l = l.getUpdatedNode();
                        b = l.getBalance();

                        set(r, isleft, child(l, !isleft));
                        set(l, !isleft, r);
                        set(x, !isleft, child(l, isleft));
                        set(l, isleft, x);

                        x = x.getUpdatedNode();

                        x.setBalance((b == sign) ? -sign
                                                 : 0);

                        r = r.getUpdatedNode();

                        r.setBalance((b == -sign) ? sign
                                                  : 0);

                        l = l.getUpdatedNode();

                        l.setBalance(0);

                        x = l;
                    }
            }

            isleft = x.isFromLeft();
            n      = x.getParent();
        }
    }

    RowIterator findFirstRow(Session session, Object[] rowdata,
                             int[] rowColMap) throws HsqlException {

        Node node = findNotNull(session, rowdata, rowColMap, true);

        return getIterator(session, node);
    }

    RowIterator findFirstRowForDelete(Session session, Object[] rowdata,
                                      int[] rowColMap) throws HsqlException {

        Node             node = findNotNull(session, rowdata, rowColMap, true);
        IndexRowIterator it   = getIterator(session, node);

        if (node != null) {
            updatableIterators.link(it);
        }

        return it;
    }

    /**
     * Finds an existing row
     */
    Row findRow(Session session, Row row) throws HsqlException {

        Node node = search(session, row);

        return node == null ? null
                            : node.getRow();
    }

    boolean exists(Session session, Object[] rowdata,
                   int[] rowColMap) throws HsqlException {
        return findNotNull(session, rowdata, rowColMap, true) != null;
    }

    RowIterator emptyIterator() {
        return emptyIterator;
    }

    /**
     * Finds a foreign key referencing rows (in child table)
     *
     * @param rowdata array containing data for the index columns
     * @param rowColMap map of the data to columns
     * @param first true if the first matching node is required, false if any node
     * @return matching node or null
     * @throws HsqlException
     */
    private Node findNotNull(Session session, Object[] rowdata,
                             int[] rowColMap,
                             boolean first) throws HsqlException {

        Node x = getRoot(session);
        Node n;
        Node result = null;

        if (isNull(rowdata, rowColMap)) {
            return null;
        }

        while (x != null) {
            int i = this.compareRowNonUnique(session, rowdata, rowColMap,
                                             x.getData());

            if (i == 0) {
                if (first == false) {
                    result = x;

                    break;
                } else if (result == x) {
                    break;
                }

                result = x;
                n      = x.getLeft();
            } else if (i > 0) {
                n = x.getRight();
            } else {
                n = x.getLeft();
            }

            if (n == null) {
                break;
            }

            x = n;
        }

        return result;
    }

    /**
     * Finds any row that matches the rowdata. Use rowColMap to map index
     * columns to rowdata. Limit to visible columns of data.
     *
     * @param rowdata array containing data for the index columns
     * @param rowColMap map of the data to columns
     * @return node matching node
     * @throws HsqlException
     */
/*
    Node find(Object[] rowdata, int[] rowColMap) throws HsqlException {

        Node x = root;

        while (x != null) {
            int c = compareRowNonUnique(rowdata, rowColMap, x.getData());

            if (c == 0) {
                return x;
            } else if (c < 0) {
                x = x.getLeft();
            } else {
                x = x.getRight();
            }
        }

        return null;
    }
*/

    /**
     * Determines if a table row has a null column for any of the columns given
     * in the rowColMap array.
     */
    static boolean isNull(Object[] row, int[] rowColMap) {

        int count = rowColMap.length;

        for (int i = 0; i < count; i++) {
            if (row[rowColMap[i]] == null) {
                return true;
            }
        }

        return false;
    }

    /**
     * Determines if a table row has a null column for any of the indexed
     * columns.
     */
    boolean isNull(Object[] row) {

        int count = colIndex.length;

        for (int i = 0; i < count; i++) {
            int j = colIndex[i];

            if (row[j] == null) {
                return true;
            }
        }

        return false;
    }

    /**
     * Return the first node equal to the rowdata object. Use visible columns
     * only. The rowdata has the same column mapping as this table.
     *
     * @param rowdata array containing table row data
     * @return iterator
     * @throws HsqlException
     */
    RowIterator findFirstRow(Session session,
                             Object[] rowdata, int count) throws HsqlException {

        Node    x      = getRoot(session);
        Node    found  = null;
        boolean unique = isUnique && !isNull(rowdata);

        while (x != null) {
            int c = compareRowNonUnique(session, rowdata, colIndex,
                                        x.getData(), count);

            if (c == 0) {
                found = x;

                if (unique) {
                    break;
                }

                x = x.getLeft();
            } else if (c < 0) {
                x = x.getLeft();
            } else {
                x = x.getRight();
            }
        }

        return getIterator(session, found);
    }

    /**
     * Finds the first node that is larger or equal to the given one based
     * on the first column of the index only.
     *
     * @param value value to match
     * @param compare comparison Expression type
     *
     * @return iterator
     *
     * @throws HsqlException
     */
    RowIterator findFirstRow(Session session, Object value,
                             int compare) throws HsqlException {

        boolean isEqual = compare == Expression.EQUAL
                          || compare == Expression.IS_NULL;
        Node x     = getRoot(session);
        int  iTest = 1;

        if (compare == Expression.BIGGER) {
            iTest = 0;
        }

        if (value == null && !isEqual) {
            return emptyIterator;
        }

/*
        // this method returns the correct node only with the following conditions
        boolean check = compare == Expression.BIGGER
                        || compare == Expression.EQUAL
                        || compare == Expression.BIGGER_EQUAL;

        if (!check) {
            Trace.doAssert(false, "Index.findFirst");
        }
*/
        while (x != null) {
            boolean t =
                Column.compare(
                    collation, value, x.getData()[colIndex[0]],
                    colTypes[0]) >= iTest;

            if (t) {
                Node r = x.getRight();

                if (r == null) {
                    break;
                }

                x = r;
            } else {
                Node l = x.getLeft();

                if (l == null) {
                    break;
                }

                x = l;
            }
        }

/*
        while (x != null
                && Column.compare(value, x.getData()[colIndex_0], colType_0)
                   >= iTest) {
            x = next(x);
        }
*/
        while (x != null) {
            Object colvalue = x.getData()[colIndex[0]];
            int result = Column.compare(collation, value, colvalue,
                                        colTypes[0]);

            if (result >= iTest) {
                x = next(x);
            } else {
                if (isEqual) {
                    if (result != 0) {
                        x = null;
                    }
                } else if (colvalue == null) {
                    x = next(x);

                    continue;
                }

                break;
            }
        }

        return getIterator(session, x);
    }

    /**
     * Finds the first node where the data is not null.
     *
     * @return iterator
     *
     * @throws HsqlException
     */
    RowIterator findFirstRowNotNull(Session session) throws HsqlException {

        Node x = getRoot(session);

        while (x != null) {
            boolean t = Column.compare(
                collation, null, x.getData()[colIndex[0]], colTypes[0]) >= 0;

            if (t) {
                Node r = x.getRight();

                if (r == null) {
                    break;
                }

                x = r;
            } else {
                Node l = x.getLeft();

                if (l == null) {
                    break;
                }

                x = l;
            }
        }

        while (x != null) {
            Object colvalue = x.getData()[colIndex[0]];

            if (colvalue == null) {
                x = next(x);
            } else {
                break;
            }
        }

        return getIterator(session, x);
    }

    /**
     * Returns the row for the first node of the index
     *
     * @return Iterator for first row
     *
     * @throws HsqlException
     */
    RowIterator firstRow(Session session) throws HsqlException {

        depth = 0;

        Node x = getRoot(session);
        Node l = x;

        while (l != null) {
            x = l;
            l = x.getLeft();

            depth++;
        }

        return getIterator(session, x);
    }

    /**
     * Returns the row for the last node of the index
     *
     * @return last row
     *
     * @throws HsqlException
     */
    Row lastRow(Session session) throws HsqlException {

        Node x = getRoot(session);
        Node l = x;

        while (l != null) {
            x = l;
            l = x.getRight();
        }

        return x == null ? null
                         : x.getRow();
    }

    /**
     * Returns the node after the given one
     *
     * @param x node
     *
     * @return next node
     *
     * @throws HsqlException
     */
    Node next(Node x) throws HsqlException {

        if (x == null) {
            return null;
        }

        Node r = x.getRight();

        if (r != null) {
            x = r;

            Node l = x.getLeft();

            while (l != null) {
                x = l;
                l = x.getLeft();
            }

            return x;
        }

        Node ch = x;

        x = x.getParent();

        while (x != null && ch.equals(x.getRight())) {
            ch = x;
            x  = x.getParent();
        }

        return x;
    }

    /**
     * Returns either child node
     *
     * @param x node
     * @param isleft boolean
     *
     * @return child node
     *
     * @throws HsqlException
     */
    private Node child(Node x, boolean isleft) throws HsqlException {
        return isleft ? x.getLeft()
                      : x.getRight();
    }

    /**
     * Replace two nodes
     *
     * @param x node
     * @param n node
     *
     * @throws HsqlException
     */
    private void replace(Session session, Node x,
                         Node n) throws HsqlException {

        if (x.isRoot()) {
            if (n != null) {
                n = n.getUpdatedNode();

                n.setParent(null);
            }

            setRoot(session, n);
        } else {
            set(x.getParent(), x.isFromLeft(), n);
        }
    }

    /**
     * Set a node as child of another
     *
     * @param x parent node
     * @param isleft boolean
     * @param n child node
     *
     * @throws HsqlException
     */
    private void set(Node x, boolean isleft, Node n) throws HsqlException {

        x = x.getUpdatedNode();

        if (isleft) {
            x.setLeft(n);
        } else {
            x.setRight(n);
        }

        if (n != null) {
            n = n.getUpdatedNode();

            n.setParent(x);
        }
    }

    /**
     * Find a node with matching data
     *
     * @param row row data
     *
     * @return matching node
     *
     * @throws HsqlException
     */
    private Node search(Session session, Row row) throws HsqlException {

        Object[] d = row.getData();
        Node     x = getRoot(session);

        while (x != null) {
            int c = compareRowForInsert(session, row, x.getRow());

            if (c == 0) {
                return x;
            } else if (c < 0) {
                x = x.getLeft();
            } else {
                x = x.getRight();
            }
        }

        return null;
    }

    /**
     * Compares two table rows based on the columns of this index. The rowColMap
     * parameter specifies which columns of the other table are to be compared
     * with the colIndex columns of this index. The rowColMap can cover all
     * or only some columns of this index.
     *
     * @param a row from another table
     * @param rowColMap column indexes in the other table
     * @param b a full row in this table
     *
     * @return comparison result, -1,0,+1
     * @throws HsqlException
     */
    int compareRowNonUnique(Session session, Object[] a, int[] rowColMap,
                            Object[] b) throws HsqlException {

        return compareRowNonUnique(session, a, rowColMap, b, rowColMap.length) ;
    }

    int compareRowNonUnique(Session session, Object[] a, int[] rowColMap,
                            Object[] b, int colCount) throws HsqlException {

        int i = Column.compare(collation, a[rowColMap[0]], b[colIndex[0]],
                               colTypes[0]);

        if (i != 0) {
            return i;
        }

        for (int j = 1; j < colCount; j++) {
            i = Column.compare(collation, a[rowColMap[j]], b[colIndex[j]],
                               colTypes[j]);

            if (i != 0) {
                return i;
            }
        }

        return 0;
    }
    /**
     * compares two full table rows based on a set of columns
     *
     * @param a a full row
     * @param b a full row
     * @param cols array of column indexes to compare
     *
     * @return comparison result, -1,0,+1
     * @throws HsqlException
     */
    static int compareRows(Session session, Object[] a, Object[] b,
                           int[] cols, int[] coltypes) throws HsqlException {

        int fieldcount = cols.length;

        for (int j = 0; j < fieldcount; j++) {
            int i = Column.compare(session.database.collation, a[cols[j]],
                                   b[cols[j]], coltypes[cols[j]]);

            if (i != 0) {
                return i;
            }
        }

        return 0;
    }

    /**
     * Compare two rows of the table for inserting rows into unique indexes
     *
     * @param a data
     * @param b data
     *
     * @return comparison result, -1,0,+1
     *
     * @throws HsqlException
     */
    private int compareRowForInsert(Session session, Row newRow,
                                    Row existingRow) throws HsqlException {

        Object[] a       = newRow.getData();
        Object[] b       = existingRow.getData();
        int      j       = 0;
        boolean  hasNull = false;

        for (; j < colIndex.length; j++) {
            Object currentvalue = a[colIndex[j]];
            int i = Column.compare(collation, currentvalue, b[colIndex[j]],
                                   colTypes[j]);

            if (i != 0) {
                return i;
            }

            if (currentvalue == null) {
                hasNull = true;
            }
        }

        if (isUnique && !useRowId && !hasNull) {
            return 0;
        }

        for (j = 0; j < pkCols.length; j++) {
            Object currentvalue = a[pkCols[j]];
            int i = Column.compare(collation, currentvalue, b[pkCols[j]],
                                   pkTypes[j]);

            if (i != 0) {
                return i;
            }
        }

        if (useRowId) {
            int difference = newRow.getPos() - existingRow.getPos();

            if (difference < 0) {
                difference = -1;
            } else if (difference > 0) {
                difference = 1;
            }

            return difference;
        }

        return 0;
    }

    /**
     * Returns a value indicating the order of different types of index in
     * the list of indexes for a table. The position of the groups of Indexes
     * in the list in ascending order is as follows:
     *
     * primary key index
     * unique constraint indexes
     * autogenerated foreign key indexes for FK's that reference this table or
     *  tables created before this table
     * user created indexes (CREATE INDEX)
     * autogenerated foreign key indexes for FK's that reference tables created
     *  after this table
     *
     * Among a group of indexes, the order is based on the order of creation
     * of the index.
     *
     * @return ordinal value
     */
    int getIndexOrderValue() {

        int value = 0;

        if (isConstraint) {
            return isForward ? 4
                             : isUnique ? 0
                                        : 1;
        } else {
            return 2;
        }
    }

    private IndexRowIterator getIterator(Session session, Node x) {

        if (x == null) {
            return emptyIterator;
        } else {
            IndexRowIterator it = new IndexRowIterator(session, this, x);

            return it;
        }
    }

    static class IndexRowIterator implements RowIterator {

        Session                    session;
        Index                      index;
        Node                       nextnode;
        protected IndexRowIterator last;
        protected IndexRowIterator next;

        /**
         * When session == null, rows from all sessions are returned
         */
        private IndexRowIterator(Session session, Index index, Node node) {

            if (index == null) {
                return;
            }

            this.session  = session;
            this.index    = index;
            this.nextnode = node;
        }

        public boolean hasNext() {
            return nextnode != null;
        }

        public Row next() {

            if (hasNext()) {
                try {
                    Row row = nextnode.getRow();

                    nextnode = index.next(nextnode);

                    return row;
                } catch (Exception e) {
                    throw new NoSuchElementException(e.getMessage());
                }
            } else {
                return null;
            }
        }

        void updateForDelete(Node node) {

            try {
                if (node.equals(nextnode)) {
                    nextnode = index.next(node);
                }
            } catch (Exception e) {}
        }

        void link(IndexRowIterator other) {

            other.next = next;
            other.last = this;
            next.last  = other;
            next       = other;
        }

        public void release() {

            if (last != null) {
                last.next = next;
            }

            if (next != null) {
                next.last = last;
            }
        }
    }
}

Other HSQLDB examples (source code examples)

Here is a short list of links related to this HSQLDB Index.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.