devdaily home | apple | java | perl | unix | directory | blog

What this is

This file 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.

Other links

The source code

/* Copyrights and Licenses
 *
 * This product includes Hypersonic SQL.
 * Originally developed by Thomas Mueller and the Hypersonic SQL Group. 
 *
 * Copyright (c) 1995-2000 by 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. 
 *     -  All advertising materials mentioning features or use of this software must display the
 *        following acknowledgment: "This product includes Hypersonic SQL." 
 *     -  Products derived from this software may not be called "Hypersonic SQL" nor may
 *        "Hypersonic SQL" appear in their names without prior written permission of the
 *         Hypersonic SQL Group. 
 *     -  Redistributions of any form whatsoever must retain the following acknowledgment: "This
 *          product includes Hypersonic SQL." 
 * This software is provided "as is" and any expressed 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 its 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 any on any theory of liability, whether in contract,
 * strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this
 * software, even if advised of the possibility of such damage. 
 * This software consists of voluntary contributions made by many individuals on behalf of the
 * Hypersonic SQL Group.
 *
 *
 * For work added by the HSQL Development Group:
 *
 * Copyright (c) 2001-2004, 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, including earlier
 * license statements (above) and comply with all above license conditions.
 *
 * 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, including earlier
 * license statements (above) and comply with all above license conditions.
 *
 * 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 java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.NoSuchElementException;

import org.hsqldb.lib.InOutUtil;
import org.hsqldb.lib.Iterator;
import org.hsqldb.rowio.RowInputBinary;
import org.hsqldb.rowio.RowOutputBinary;

// fredt@users 20020130 - patch 1.7.0 by fredt
// to ensure consistency of r.rTail r.iSize in all operations
// methods for set operations moved here from Select.java
// tony_lai@users 20020820 - patch 595073 - duplicated exception msg
// fredt@users 20030801 - patch 1.7.2 - separate metadata and polymophic serialisation
// boucherb@users 200307/8 - various, in support of fred's work over the same time period

/**
 *  The primary unit of comunication between Connection, Server and Session
 *  objects.
 *
 *  An HSQLDB Result object encapsulates all requests (such as to alter or
 *  query session settings, to allocate and execute statements, etc.) and all
 *  responses (such as exception indications, update counts, result sets and
 *  result set metadata). It also implements the HSQL wire protocol for
 *  comunicating all such requests and responses across the network.
 *
 * @version    1.7.2
 */
public class Result {

    // record list
    public Record  rRoot;
    private Record rTail;
    private int    iSize;

    // transient - number of significant columns
    private int significantColumns;

    // type of result
    public int iMode;

//    boolean isMulti;
    // database ID
    int databaseID;

    // session ID
    int sessionID;

    // user / password or error strings
    String mainString;
    String subString;

    // database name
    String subSubString;

    // prepared statement id / error vendor code
    int statementID;

    // max rows (out) or update count (in)
    int                   iUpdateCount;
    public ResultMetaData metaData;

    /** A Result object's metadata */
    public static class ResultMetaData {

        // always resolved
        public String  sLabel[];
        public String  sTable[];
        public String  sName[];
        public boolean isLabelQuoted[];
        public int     colType[];
        public int     colSize[];
        public int     colScale[];

        // extra attrs, sometimes resolved
        public String    sCatalog[];
        public String    sSchema[];
        public int       nullability[];
        public boolean   isIdentity[];
        public boolean[] isWritable;
        public int       paramMode[];

        // It's possible to do better than java.lang.Object
        // for type OTHER if the expression generating the value
        // is of type FUNCTION.  This applies to result set columns
        // whose value is the result of a SQL function call and
        // especially to the arguments and return value of a CALL
        public String sClassName[];
        boolean       isParameterDescription;

        ResultMetaData() {}

        ResultMetaData(int n) {
            prepareData(n);
        }

        /**
         *  Method declaration
         *
         * @param  columns
         */
        private void prepareData(int columns) {

            sLabel        = new String[columns];
            sTable        = new String[columns];
            sName         = new String[columns];
            isLabelQuoted = new boolean[columns];
            colType       = new int[columns];
            colSize       = new int[columns];
            colScale      = new int[columns];
            sCatalog      = new String[columns];
            sSchema       = new String[columns];
            nullability   = new int[columns];
            isIdentity    = new boolean[columns];
            isWritable    = new boolean[columns];
            sClassName    = new String[columns];
        }

        public int[] getParameterTypes() {
            return colType;
        }

        boolean isTableColumn(int i) {
            return sTable[i] != null && sTable[i].length() > 0
                   && sName[i] != null && sName[i].length() > 0;
        }

        private void decodeTableColumnAttrs(int in, int i) {

            nullability[i] = in & 0x0000000f;
            isIdentity[i]  = (in & 0x00000010) != 0;
            isWritable[i]  = (in & 0x00000020) != 0;
        }

        private void writeTableColumnAttrs(RowOutputBinary out,
                                           int i)
                                           throws IOException, HsqlException {

            // Currently, HSQLDB accepts and logs (precision, scale)
            // for all types, which is not to the spec.
            // HSQLDB also ignores precision and scale for all types except
            // XXXCHAR, for which it may (or may not) perform some trimming/padding.
            // All in all, it's currently meaningless (indeed misleading) to
            // transmit and report the values, as the data typically will
            // not be constrained accordingly.
//        switch(colType[i]) {
//            // As early as SQL 92, these are allowed to have a scale.
//            // However, DatabaseCommandInterpreter.processCreateColumn
//            // does not currently handle this correctly and will assign
//            // a precision instead of a scale if TIME(s) or TIMESTAMP(s)
//            // is specified
//            case Types.TIME :
//            case Types.TIMESTAMP :
//                  out.writeIntData(colScale[i]);
//                  break;
//            case Types.DECIMAL :
//            case Types.NUMERIC : {
//                out.writeIntData(colScale[i]);
//            } // fall through
//            // Apparently, SQL 92 specifies that FLOAT can have
//            // a declared precision, which is typically the number of
//            // bits (not binary digits).  In any case, this is somewhat
//            // meaningless under HSQLDB/Java, in that we use java.lang.Double
//            // to represent SQL FLOAT
//            case Types.FLOAT :
//            // It's legal to declare precision for these, although HSQLDB
//            // currently does not use it to constrain values
//            case Types.BINARY :
//            case Types.VARBINARY :
//            case Types.LONGVARBINARY :
//            // possibly, but not universally acted upon (trimmming/padding)
//            case Types.CHAR  :
//            case Types.VARCHAR :
//            case Types.LONGVARCHAR : {
//                out.writeIntData(colSize[i]);
//            }
//        }
            out.writeIntData(encodeTableColumnAttrs(i));
            out.writeString(sCatalog[i] == null ? ""
                                                : sCatalog[i]);
            out.writeString(sSchema[i] == null ? ""
                                               : sSchema[i]);
        }

        private int encodeTableColumnAttrs(int i) {

            int out = nullability[i];    // always between 0x00 and 0x02

            if (isIdentity[i]) {
                out |= 0x00000010;
            }

            if (isWritable[i]) {
                out |= 0x00000020;
            }

            return out;
        }

        private void readTableColumnAttrs(RowInputBinary in,
                                          int i)
                                          throws IOException, HsqlException {

// no point in transmitting these yet
// if ever implemented, must follow logic of switch as outlined in comments
// for corresponding write method
//        colScale[i] = in.readIntData();
//        colSize[i] = in.readIntData();
            decodeTableColumnAttrs(in.readIntData(), i);

            sCatalog[i] = in.readString();
            sSchema[i]  = in.readString();
        }

        void read(RowInputBinary in) throws HsqlException, IOException {

            int l = in.readIntData();

            prepareData(l);

            if (isParameterDescription) {
                paramMode = new int[l];
            }

            for (int i = 0; i < l; i++) {
                colType[i]    = in.readType();
                sLabel[i]     = in.readString();
                sTable[i]     = in.readString();
                sName[i]      = in.readString();
                sClassName[i] = in.readString();

                if (isTableColumn(i)) {
                    readTableColumnAttrs(in, i);
                }

                if (isParameterDescription) {
                    paramMode[i] = in.readIntData();
                }
            }
        }

        void write(RowOutputBinary out,
                   int colCount) throws HsqlException, IOException {

            out.writeIntData(colCount);

            for (int i = 0; i < colCount; i++) {
                out.writeType(colType[i]);

                // CAREFUL: writeString will throw NPE if passed NULL
                // There is no guarantee that these will all be non-null
                // and there's no point in hanging network communications
                // or doing a big rewrite for null-safety over something
                // like this.  We could explicitly do a writeNull here if
                // detected null, but, frankly, readString on the other
                // end will simply turn it into a zero-length string
                // anyway, as nulls are only handled "properly" by
                // readData(...), not by the individual readXXX methods.
                out.writeString(sLabel[i] == null ? ""
                                                  : sLabel[i]);
                out.writeString(sTable[i] == null ? ""
                                                  : sTable[i]);
                out.writeString(sName[i] == null ? ""
                                                 : sName[i]);
                out.writeString(sClassName[i] == null ? ""
                                                      : sClassName[i]);

                if (isTableColumn(i)) {
                    writeTableColumnAttrs(out, i);
                }

                if (isParameterDescription) {
                    out.writeIntData(paramMode[i]);
                }
            }
        }
    }

    /**
     *  General constructor
     */
    public Result(int type) {

        iMode = type;

/*
        if (type == ResultConstants.MULTI) {
            isMulti = true;
        }
*/
        if (type == ResultConstants.DATA
                || type == ResultConstants.PARAM_META_DATA
                || type == ResultConstants.SQLEXECUTE
                || type == ResultConstants.SETSESSIONATTR) {
            metaData = new ResultMetaData();
        }
    }

    Result(ResultMetaData md) {

        iMode              = ResultConstants.DATA;
        significantColumns = md.colType.length;
        metaData           = md;
    }

// fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)

    /**
     *  Constructor for errors
     *
     * @param  error error message
     * @param  state   sql state
     * @param  code   vendor code
     */
    Result(String error, String state, int code) {

        iMode        = ResultConstants.ERROR;
        mainString   = error;
        subString    = state;
        statementID  = code;
        subSubString = "";
    }

    /**
     *  Only used with DATA and PARAM_META_DATA results
     *
     * @param  columns
     */
    Result(int type, int columns) {

        metaData = new ResultMetaData();

        metaData.prepareData(columns);

        if (type == ResultConstants.PARAM_META_DATA) {
            metaData.isParameterDescription = true;
            metaData.paramMode              = new int[columns];
        }

        iMode              = type;
        significantColumns = columns;
    }

    /**
     * For BATCHEXECUTE and BATCHEXECDIRECT
     */
    public Result(int type, int types[], int id) {

        iMode              = type;
        metaData           = new ResultMetaData();
        metaData.colType   = types;
        significantColumns = types.length;
        statementID        = id;
    }

    /**
     *  Constructor declaration
     *
     * @param  in
     * @exception  HsqlException  Description of the Exception
     */
    Result(RowInputBinary in) throws HsqlException {

        try {
            iMode = in.readIntData();

            if (iMode == ResultConstants.MULTI) {
                readMultiResult(in);

                return;
            }

            databaseID = in.readIntData();
            sessionID  = in.readIntData();

            switch (iMode) {

                case ResultConstants.GETSESSIONATTR :
                case ResultConstants.SQLDISCONNECT :
                case ResultConstants.SQLSTARTTRAN :
                    break;

                case ResultConstants.SQLPREPARE :
                    setStatementType(in.readIntData());

                    mainString = in.readString();
                    break;

                case ResultConstants.PREPARE_ACK :
                case ResultConstants.SQLFREESTMT :
                    statementID = in.readIntData();
                    break;

                case ResultConstants.SQLEXECDIRECT :
                    iUpdateCount = in.readIntData();
                    statementID  = in.readIntData();
                    mainString   = in.readString();
                    break;

                case ResultConstants.ERROR :
                case ResultConstants.SQLCONNECT :
                    mainString   = in.readString();
                    subString    = in.readString();
                    subSubString = in.readString();
                    statementID  = in.readIntData();

//                    throw Trace.getError(string, code);
                    break;

                case ResultConstants.UPDATECOUNT :
                    iUpdateCount = in.readIntData();
                    break;

                case ResultConstants.SQLENDTRAN : {
                    int type = in.readIntData();

                    setEndTranType(type);                    // endtran type

                    switch (type) {

                        case ResultConstants.SAVEPOINT_NAME_RELEASE :
                        case ResultConstants.SAVEPOINT_NAME_ROLLBACK :
                            mainString = in.readString();    // savepoint name

                        //  default: throw - case never happens
                    }

                    break;
                }
                case ResultConstants.BATCHEXECUTE :
                case ResultConstants.BATCHEXECDIRECT :
                case ResultConstants.SQLEXECUTE :
                case ResultConstants.SETSESSIONATTR : {
                    iUpdateCount = in.readIntData();
                    statementID  = in.readIntData();

                    int l = in.readIntData();

                    metaData           = new ResultMetaData(l);
                    significantColumns = l;

                    for (int i = 0; i < l; i++) {
                        metaData.colType[i] = in.readType();
                    }

                    int count = in.readIntData();

                    while (count-- > 0) {
                        add(in.readData(metaData.colType));
                    }

                    break;
                }
                case ResultConstants.DATA :
                case ResultConstants.PARAM_META_DATA : {
                    metaData = new ResultMetaData();
                    metaData.isParameterDescription =
                        iMode == ResultConstants.PARAM_META_DATA;

                    metaData.read(in);

                    significantColumns = metaData.sLabel.length;

                    int count = in.readIntData();

                    while (count-- > 0) {
                        add(in.readData(metaData.colType));
                    }

                    break;
                }
                case ResultConstants.SQLSETCONNECTATTR : {
                    int type = in.readIntData();             // attr type

                    setConnectionAttrType(type);

                    switch (type) {

                        case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
                            mainString = in.readString();    // savepoint name

                        //  case ResultConstants.SQL_ATTR_AUTO_IPD :
                        //      - always true
                        //  default: throw - case never happens
                    }

                    break;
                }
                default :
                    throw new HsqlException(
                        Trace.getMessage(
                            Trace.Result_Result, true, new Object[]{
                                new Integer(iMode) }), null, 0);
            }
        } catch (IOException e) {
            throw Trace.error(Trace.TRANSFER_CORRUPTED);
        }
    }

    static Result newSingleColumnResult(String colName, int colType) {

        Result result = new Result(ResultConstants.DATA, 1);

        result.metaData.sName[0]   = colName;
        result.metaData.sLabel[0]  = colName;
        result.metaData.sTable[0]  = "";
        result.metaData.colType[0] = colType;

        return result;
    }

    static Result newPrepareResponse(int csid, Result rsmd, Result pmd) {

        Result out;
        Result pack;

        out = new Result(ResultConstants.MULTI);

//        out.isMulti      = true;
        pack             = new Result(ResultConstants.PREPARE_ACK);
        pack.statementID = csid;

        out.add(new Object[]{ pack });
        out.add(new Object[]{ rsmd });
        out.add(new Object[]{ pmd });

        return out;
    }

    static Result newParameterDescriptionResult(int len) {

        Result r = new Result(ResultConstants.PARAM_META_DATA, len);

        r.metaData.isParameterDescription = true;
        r.metaData.paramMode              = new int[len];

        return r;
    }

    public static Result newFreeStmtRequest(int statementID) {

        Result r = new Result(ResultConstants.SQLFREESTMT);

        r.statementID = statementID;

        return r;
    }

    static Result newExecuteDirectRequest(String sql) {

        Result out;

        out = new Result(ResultConstants.SQLEXECDIRECT);

        out.setMainString(sql);

        return out;
    }

    public static Result newReleaseSavepointRequest(String name) {

        Result out;

        out = new Result(ResultConstants.SQLENDTRAN);

        out.setMainString(name);
        out.setEndTranType(ResultConstants.SAVEPOINT_NAME_RELEASE);

        return out;
    }

    public static Result newRollbackToSavepointRequest(String name) {

        Result out;

        out = new Result(ResultConstants.SQLENDTRAN);

        out.setMainString(name);
        out.setEndTranType(ResultConstants.SAVEPOINT_NAME_ROLLBACK);

        return out;
    }

    public static Result newSetSavepointRequest(String name) {

        Result out;

        out = new Result(ResultConstants.SQLSETCONNECTATTR);

        out.setConnectionAttrType(ResultConstants.SQL_ATTR_SAVEPOINT_NAME);
        out.setMainString(name);

        return out;
    }

    /**
     *  Method declaration
     *
     * @return
     */
    public int getSize() {
        return iSize;
    }

    /**
     *  Method declaration
     *
     * @param  columns
     */
    void setColumnCount(int columns) {
        significantColumns = columns;
    }

    /**
     *  Method declaration
     *
     * @return
     */
    public int getColumnCount() {
        return significantColumns;
    }

    /**
     *  Append Result argument to this.
     *
     * @param  a
     */
    void append(Result a) {

        if (a.rRoot == null) {
            return;
        }

        if (rRoot == null) {
            rRoot = a.rRoot;
        } else {
            rTail.next = a.rRoot;
        }

        rTail = a.rTail;
        iSize += a.iSize;
    }

    void addAll(Result r) {

        if (r == null) {
            return;
        }

        Record from = r.rRoot;

        while (from != null) {
            add(from.data);

            from = from.next;
        }
    }

    public void clear() {

        rRoot = null;
        rTail = null;
        iSize = 0;
    }

    public boolean isEmpty() {
        return rRoot == null;
    }

    /**
     *  Method declaration
     *
     * @param  a
     */
    void setRows(Result a) {

        if (a == null) {
            rRoot = null;
            rTail = null;
            iSize = 0;
        } else {
            rRoot = a.rRoot;
            rTail = a.rTail;
            iSize = a.iSize;
        }
    }

    /**
     *  Method declaration
     *
     * @param  d
     */
    public void add(Object d[]) {

        Record r = new Record();

        r.data = d;

        if (rRoot == null) {
            rRoot = r;
        } else {
            rTail.next = r;
        }

        rTail = r;

        iSize++;
    }

    /**
     *  Method declaration
     *
     * @param  limitstart  number of records to discard at the head
     * @param  limitcount  number of records to keep, all the rest if 0
     */

// fredt@users 20020130 - patch 1.7.0 by fredt
// rewritten and moved from Select.java
    void trimResult(int limitstart, int limitcount) {

        Record n = rRoot;

        if (n == null) {
            return;
        }

        if (limitstart >= iSize) {
            iSize = 0;
            rRoot = rTail = null;

            return;
        }

        iSize -= limitstart;

        for (int i = 0; i < limitstart; i++) {
            n = n.next;

            if (n == null) {

                // if iSize is consistent this block will never be reached
                iSize = 0;
                rRoot = rTail = n;

                return;
            }
        }

        rRoot = n;

        if (limitcount == 0 || limitcount >= iSize) {
            return;
        }

        for (int i = 1; i < limitcount; i++) {
            n = n.next;

            if (n == null) {

                // if iSize is consistent this block will never be reached
                return;
            }
        }

        iSize  = limitcount;
        n.next = null;
        rTail  = n;
    }

    /**
     * Removes duplicate rows on the basis of comparing the singificant
     * columns of the rows in the result.
     *
     * @throws  HsqlException
     */
    void removeDuplicates() throws HsqlException {
        removeDuplicates(significantColumns);
    }

    /**
     * Removes duplicate rows on the basis of comparing the first columnCount
     * columns of rows in the result.
     *
     * @throws  HsqlException
     */

// fredt@users 20020130 - patch 1.7.0 by fredt
// to ensure consistency of r.rTail r.iSize in all set operations
    void removeDuplicates(int columnCount) throws HsqlException {

        if (rRoot == null) {
            return;
        }

        int order[] = new int[columnCount];
        int way[]   = new int[columnCount];

        for (int i = 0; i < columnCount; i++) {
            order[i] = i;
            way[i]   = 1;
        }

        sortResult(order, way);

        Record n = rRoot;

        for (;;) {
            Record next = n.next;

            if (next == null) {
                break;
            }

            if (compareRecord(n.data, next.data, columnCount) == 0) {
                n.next = next.next;

                iSize--;
            } else {
                n = next;
            }
        }

        rTail = n;
    }

    /**
     *  Removes duplicates then removes the contents of the second result
     *  from this one base on first columnCount of the rows in each result.
     *
     * @param  minus
     * @throws  HsqlException
     */
    void removeSecond(Result minus, int columnCount) throws HsqlException {

        removeDuplicates(columnCount);
        minus.removeDuplicates(columnCount);

        Record  n     = rRoot;
        Record  last  = rRoot;
        boolean rootr = true;    // checking rootrecord
        Record  n2    = minus.rRoot;
        int     i     = 0;

        while (n != null && n2 != null) {
            i = compareRecord(n.data, n2.data, columnCount);

            if (i == 0) {
                if (rootr) {
                    rRoot = last = n.next;
                } else {
                    last.next = n.next;
                }

                n = n.next;

                iSize--;
            } else if (i > 0) {    // r > minus
                n2 = n2.next;
            } else {               // r < minus
                last  = n;
                rootr = false;
                n     = n.next;
            }
        }

        for (; n != null; ) {
            last = n;
            n    = n.next;
        }

        rTail = last;
    }

    /**
     * Removes all duplicate rows then removes all rows that are not shared
     * between this and the other result, based on comparing the first
     * columnCount columns of each result.
     *
     * @param  r2
     * @throws  HsqlException
     */
    void removeDifferent(Result r2, int columnCount) throws HsqlException {

        removeDuplicates(columnCount);
        r2.removeDuplicates(columnCount);

        Record  n     = rRoot;
        Record  last  = rRoot;
        boolean rootr = true;    // checking rootrecord
        Record  n2    = r2.rRoot;
        int     i     = 0;

        iSize = 0;

        while (n != null && n2 != null) {
            i = compareRecord(n.data, n2.data, columnCount);

            if (i == 0) {             // same rows
                if (rootr) {
                    rRoot = n;        // make this the first record
                } else {
                    last.next = n;    // this is next record in resultset
                }

                rootr = false;
                last  = n;            // this is last record in resultset
                n     = n.next;
                n2    = n2.next;

                iSize++;
            } else if (i > 0) {       // r > r2
                n2 = n2.next;
            } else {                  // r < r2
                n = n.next;
            }
        }

        if (rootr) {             // if no lines in resultset
            rRoot = null;        // then return null
            last  = null;
        } else {
            last.next = null;    // else end resultset
        }

        rTail = last;
    }

    /**
     *  Method declaration
     *
     * @param  order
     * @param  way
     * @throws  HsqlException
     */
    void sortResult(final int order[], final int way[]) throws HsqlException {

        if (rRoot == null || rRoot.next == null) {
            return;
        }

        Record source0, source1;
        Record target[]     = new Record[2];
        Record targetlast[] = new Record[2];
        int    dest         = 0;
        Record n            = rRoot;

        while (n != null) {
            Record next = n.next;

            n.next       = target[dest];
            target[dest] = n;
            n            = next;
            dest         ^= 1;
        }

        for (int blocksize = 1; target[1] != null; blocksize <<= 1) {
            source0   = target[0];
            source1   = target[1];
            target[0] = target[1] = targetlast[0] = targetlast[1] = null;

            for (dest = 0; source0 != null; dest ^= 1) {
                int n0 = blocksize,
                    n1 = blocksize;

                while (true) {
                    if (n0 == 0 || source0 == null) {
                        if (n1 == 0 || source1 == null) {
                            break;
                        }

                        n       = source1;
                        source1 = source1.next;

                        n1--;
                    } else if (n1 == 0 || source1 == null) {
                        n       = source0;
                        source0 = source0.next;

                        n0--;
                    } else if (compareRecord(
                            source0.data, source1.data, order, way) > 0) {
                        n       = source1;
                        source1 = source1.next;

                        n1--;
                    } else {
                        n       = source0;
                        source0 = source0.next;

                        n0--;
                    }

                    if (target[dest] == null) {
                        target[dest] = n;
                    } else {
                        targetlast[dest].next = n;
                    }

                    targetlast[dest] = n;
                    n.next           = null;
                }
            }
        }

        rRoot = target[0];
        rTail = targetlast[0];
    }

    /**
     *  Method declaration
     *
     * @param  a
     * @param  b
     * @param  order
     * @param  way
     * @return -1, 0, +1
     * @throws  HsqlException
     */
    private int compareRecord(Object a[], final Object b[],
                              final int order[],
                              int way[]) throws HsqlException {

        int i = Column.compare(a[order[0]], b[order[0]],
                               metaData.colType[order[0]]);

        if (i == 0) {
            for (int j = 1; j < order.length; j++) {
                i = Column.compare(a[order[j]], b[order[j]],
                                   metaData.colType[order[j]]);

                if (i != 0) {
                    return i * way[j];
                }
            }
        }

        return i * way[0];
    }

    /**
     *  Method declaration
     *
     * @param  a
     * @param  b
     * @param  len
     * @return -1, 0, +1
     * @throws  HsqlException
     */
    private int compareRecord(Object a[], Object b[],
                              int len) throws HsqlException {

        for (int j = 0; j < len; j++) {
            int i = Column.compare(a[j], b[j], metaData.colType[j]);

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

        return 0;
    }

    void write(RowOutputBinary out) throws IOException, HsqlException {

//        if (isMulti) {
        if (iMode == ResultConstants.MULTI) {
            writeMulti(out);

            return;
        }

        int startPos = out.size();

        out.writeSize(0);
        out.writeIntData(iMode);
        out.writeIntData(databaseID);
        out.writeIntData(sessionID);

        switch (iMode) {

            case ResultConstants.GETSESSIONATTR :
            case ResultConstants.SQLDISCONNECT :
            case ResultConstants.SQLSTARTTRAN :
                break;

            case ResultConstants.SQLPREPARE :

                // Allows the engine side to fast-fail prepare of non-CALL
                // statement against a CallableStatement object and CALL
                // statement against PreparedStatement.
                //
                // May be useful in the future for other things
                out.writeIntData(getStatementType());
                out.writeString(mainString);
                break;

            case ResultConstants.PREPARE_ACK :
            case ResultConstants.SQLFREESTMT :
                out.writeIntData(statementID);
                break;

            case ResultConstants.SQLEXECDIRECT :
                out.writeIntData(iUpdateCount);
                out.writeIntData(statementID);          // currently unused
                out.writeString(mainString);
                break;

            case ResultConstants.ERROR :
            case ResultConstants.SQLCONNECT :
                out.writeString(mainString);
                out.writeString(subString);
                out.writeString(subSubString);
                out.writeIntData(statementID);
                break;

            case ResultConstants.UPDATECOUNT :
                out.writeIntData(iUpdateCount);
                break;

            case ResultConstants.SQLENDTRAN : {
                int type = getEndTranType();

                out.writeIntData(type);                 // endtran type

                switch (type) {

                    case ResultConstants.SAVEPOINT_NAME_RELEASE :
                    case ResultConstants.SAVEPOINT_NAME_ROLLBACK :
                        out.writeString(mainString);    // savepoint name

                    // default; // do nothing
                }

                break;
            }
            case ResultConstants.BATCHEXECUTE :
            case ResultConstants.BATCHEXECDIRECT :
            case ResultConstants.SQLEXECUTE :
            case ResultConstants.SETSESSIONATTR : {
                out.writeIntData(iUpdateCount);
                out.writeIntData(statementID);

                int l = significantColumns;

                out.writeIntData(l);

                for (int i = 0; i < l; i++) {
                    out.writeType(metaData.colType[i]);
                }

                out.writeIntData(iSize);

                Record n = rRoot;

                while (n != null) {
                    out.writeData(l, metaData.colType, n.data, null, false);

                    n = n.next;
                }

                break;
            }
            case ResultConstants.DATA :
            case ResultConstants.PARAM_META_DATA : {
                metaData.write(out, significantColumns);
                out.writeIntData(iSize);

                Record n = rRoot;

                while (n != null) {
                    out.writeData(significantColumns, metaData.colType,
                                  n.data, null, false);

                    n = n.next;
                }

                break;
            }
            case ResultConstants.SQLSETCONNECTATTR : {
                int type = getConnectionAttrType();

                out.writeIntData(type);                 // attr type

                switch (type) {

                    case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
                        out.writeString(mainString);    // savepoint name

                    // case ResultConstants.SQL_ATTR_AUTO_IPD // always true
                    // default: // throw, but case never happens
                }

                break;
            }
            default :
                throw new HsqlException(
                    Trace.getMessage(
                        Trace.Result_Result, true, new Object[]{
                            new Integer(iMode) }), null, 0);
        }

        out.writeIntData(out.size(), startPos);
    }

    void readMultiResult(RowInputBinary in)
    throws HsqlException, IOException {

        iMode      = ResultConstants.MULTI;
        databaseID = in.readIntData();
        sessionID  = in.readIntData();

        int count = in.readIntData();

        for (int i = 0; i < count; i++) {

            // Currently required for the outer result, but can simply
            // be ignored for sub-results
            in.readIntData();
            add(new Object[]{ new Result(in) });
        }
    }

    private void writeMulti(RowOutputBinary out)
    throws IOException, HsqlException {

        int startPos = out.size();

        out.writeSize(0);
        out.writeIntData(iMode);
        out.writeIntData(databaseID);
        out.writeIntData(sessionID);
        out.writeIntData(iSize);

        Record n = rRoot;

        while (n != null) {
            ((Result) n.data[0]).write(out);

            n = n.next;
        }

        out.writeIntData(out.size(), startPos);
    }

    /**
     * Convenience method for writing, shared by Server side.
     */
    public static void write(Result r, RowOutputBinary rowout,
                             OutputStream dataout)
                             throws IOException, HsqlException {

        rowout.reset();
        r.write(rowout);
        dataout.write(rowout.getOutputStream().getBuffer(), 0,
                      rowout.getOutputStream().size());
        dataout.flush();
    }

    /**
     * Convenience method for reading, shared by Server side.
     */
    public static Result read(RowInputBinary rowin,
                              InputStream datain)
                              throws IOException, HsqlException {

        int length = InOutUtil.readInt(datain);

        rowin.resetRow(0, length);

        byte[] byteArray = rowin.getBuffer();
        int    offset    = 4;

        for (; offset < length; ) {
            int count = datain.read(byteArray, offset, length - offset);

            if (count < 0) {
                throw new IOException();
            }

            offset += count;
        }

        return new Result(rowin);
    }

/** @todo fredt - move the messages to Trace.java */
    public Result(Throwable t, String statement) {

        iMode = ResultConstants.ERROR;

        if (t instanceof HsqlException) {
            HsqlException he = (HsqlException) t;

            subString  = he.state;
            mainString = he.message;

            if (statement != null) {
                mainString += " in statement [" + statement + "]";
            }

            statementID = he.code;
        } else if (t instanceof Exception) {
            t.printStackTrace();

            subString  = "S1000";
            mainString = Trace.getMessage(Trace.GENERAL_ERROR) + " " + t;

            if (statement != null) {
                mainString += " in statement [" + statement + "]";
            }

            statementID = Trace.GENERAL_ERROR;
        } else if (t instanceof OutOfMemoryError) {

            // At this point, we've nothing to lose by doing this
            System.gc();
            t.printStackTrace();

            subString   = "S1000";
            mainString  = "out of memory";
            statementID = Trace.OUT_OF_MEMORY;
        }

        subSubString = "";
    }

    public int getStatementID() {
        return statementID;
    }

    void setStatementID(int id) {
        statementID = id;
    }

    public String getMainString() {
        return mainString;
    }

    public void setMainString(String sql) {
        mainString = sql;
    }

    public String getSubString() {
        return subString;
    }

    public void setMaxRows(int count) {
        this.iUpdateCount = count;
    }

    public int getUpdateCount() {
        return iUpdateCount;
    }

    int getConnectionAttrType() {
        return iUpdateCount;
    }

    void setConnectionAttrType(int type) {
        iUpdateCount = type;
    }

    int getEndTranType() {
        return iUpdateCount;
    }

    void setEndTranType(int type) {
        iUpdateCount = type;
    }

    /** @todo fred - check this repurposing */
    public int[] getUpdateCounts() {
        return metaData.colType;
    }

    Object[] getParameterData() {
        return (rRoot == null) ? null
                               : rRoot.data;
    }

    public void setParameterData(Object[] data) {

        if (rRoot == null) {
            rRoot = new Record();
        }

        rRoot.data = data;
        rRoot.next = null;
        rTail      = rRoot;
        iSize      = 1;
    }

    public void setResultType(int type) {
        iMode = type;
    }

    public void setStatementType(int type) {
        iUpdateCount = type;
    }

    public int getStatementType() {
        return iUpdateCount;
    }

    public Iterator iterator() {
        return new ResultIterator();
    }

    private class ResultIterator implements Iterator {

        boolean removed;
        int     counter;
        Record  current = rRoot;
        Record  last;

        public boolean hasNext() {
            return counter < iSize;
        }

        public Object next() {

            if (hasNext()) {
                removed = false;

                if (counter != 0) {
                    last    = current;
                    current = current.next;
                }

                counter++;

                return current.data;
            }

            throw new NoSuchElementException();
        }

        public int nextInt() {
            throw new NoSuchElementException();
        }

        public long nextLong() {
            throw new NoSuchElementException();
        }

        public void remove() {

            if (counter <= iSize && counter != 0 &&!removed) {
                removed = true;

                if (current == rTail) {
                    rTail = last;
                }

                if (current == rRoot) {
                    current = rRoot = rRoot.next;
                } else {
                    current      = last;
                    last         = null;
                    current.next = current.next.next;
                }

                iSize--;
                counter--;

                return;
            }

            throw new NoSuchElementException();
        }
    }
}




Copyright 1998-2008 Alvin Alexander
All Rights Reserved.
 
devdaily.com is based in louisville, kentucky, and this web site is hosted by godaddy.com