4353 lines · 201.8 KB · Java
RawDownload
/* * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.rowset; import java.sql.*;import javax.sql.*;import javax.naming.*;import java.io.*;import java.math.*;import java.util.*; import javax.sql.rowset.*;import javax.sql.rowset.spi.SyncProvider;import javax.sql.rowset.spi.SyncProviderException; /** * The standard implementation of the <code>JoinRowSet</code> * interface providing an SQL <code>JOIN</code> between <code>RowSet</code> * objects. * <P> * The implementation provides an ANSI-style <code>JOIN</code> providing an * inner join between two tables. Any unmatched rows in either table of the * join are  discarded. * <p> * Typically, a <code>JoinRowSet</code> implementation is leveraged by * <code>RowSet</code> instances that are in a disconnected environment and * thus do not have the luxury of an open connection to the data source to * establish logical relationships between themselves. In other words, it is * largely <code>CachedRowSet</code> objects and implementations derived from * the <code>CachedRowSet</code> interface that will use the <code>JoinRowSetImpl</code> * implementation. * * @author Amit Handa, Jonathan Bruce */public class JoinRowSetImpl extends WebRowSetImpl implements JoinRowSet {    /**     * A <code>Vector</code> object that contains the <code>RowSet</code> objects     * that have been added to this <code>JoinRowSet</code> object.     */    private Vector<CachedRowSetImpl> vecRowSetsInJOIN;     /**     * The <code>CachedRowSet</code> object that encapsulates this     * <code>JoinRowSet</code> object.     * When <code>RowSet</code> objects are added to this <code>JoinRowSet</code>     * object, they are also added to <i>crsInternal</i> to form the same kind of     * SQL <code>JOIN</code>.  As a result, methods for making updates to this     * <code>JoinRowSet</code> object can use <i>crsInternal</i> methods in their     * implementations.     */    private CachedRowSetImpl crsInternal;     /**     * A <code>Vector</code> object containing the types of join that have been set     * for this <code>JoinRowSet</code> object.     * The last join type set forms the basis of succeeding joins.     */    private Vector<Integer> vecJoinType;     /**     * A <code>Vector</code> object containing the names of all the tables entering     * the join.     */    private Vector<String> vecTableNames;     /**     * An <code>int</code> that indicates the column index of the match column.     */    private int iMatchKey;     /**     * A <code>String</code> object that stores the name of the match column.     */    private String strMatchKey ;     /**     * An array of <code>boolean</code> values indicating the types of joins supported     * by this <code>JoinRowSet</code> implementation.     */    boolean[] supportedJOINs;     /**     * The <code>WebRowSet</code> object that encapsulates this <code>JoinRowSet</code>     * object. This <code>WebRowSet</code> object allows this <code>JoinRowSet</code>     * object to leverage the properties and methods of a <code>WebRowSet</code>     * object.     */    private WebRowSet wrs;      /**     * Constructor for <code>JoinRowSetImpl</code> class. Configures various internal data     * structures to provide mechanisms required for <code>JoinRowSet</code> interface     * implementation.     *     * @throws SQLException if an error occurs in instantiating an instance of     * <code>JoinRowSetImpl</code>     */    public JoinRowSetImpl() throws SQLException {         vecRowSetsInJOIN = new Vector<CachedRowSetImpl>();        crsInternal = new CachedRowSetImpl();        vecJoinType = new Vector<Integer>();        vecTableNames = new Vector<String>();        iMatchKey = -1;        strMatchKey = null;        supportedJOINs =              new boolean[] {false, true, false, false, false};       try {           resBundle = JdbcRowSetResourceBundle.getJdbcRowSetResourceBundle();        } catch(IOException ioe) {            throw new RuntimeException(ioe);        }     }     /**     * Adds the given <code>RowSet</code> object to this     * <code>JoinRowSet</code> object.  If this     * rowset is the first to be added to the <code>JoinRowSet</code>     * object, it forms the basis for the <code>JOIN</code>     * relationships to be formed.     * <p>     * This method should be used when the given <code>RowSet</code> object     * already has a match column set.     *     * @param rowset the <code>RowSet</code> object that implements the     *         <code>Joinable</code> interface and is to be added     *         to this <code>JoinRowSet</code> object     * @throws SQLException if an empty <code>RowSet</code> is added to the to the     *         <code>JoinRowSet</code>; if a match column is not set; or if an     *         additional <code>RowSet</code> violates the active <code>JOIN</code>     * @see CachedRowSet#setMatchColumn     */    public void addRowSet(Joinable rowset) throws SQLException {        boolean boolColId, boolColName;         boolColId = false;        boolColName = false;        CachedRowSetImpl cRowset;         if(!(rowset instanceof RowSet)) {            throw new SQLException(resBundle.handleGetObject("joinrowsetimpl.notinstance").toString());        }         if(rowset instanceof JdbcRowSetImpl ) {            cRowset = new CachedRowSetImpl();            cRowset.populate((RowSet)rowset);            if(cRowset.size() == 0){                throw new SQLException(resBundle.handleGetObject("joinrowsetimpl.emptyrowset").toString());            }              try {                int matchColumnCount = 0;                for(int i=0; i< rowset.getMatchColumnIndexes().length; i++) {                    if(rowset.getMatchColumnIndexes()[i] != -1)                        ++ matchColumnCount;                    else                        break;                }                int[] pCol = new int[matchColumnCount];                for(int i=0; i<matchColumnCount; i++)                   pCol[i] = rowset.getMatchColumnIndexes()[i];                cRowset.setMatchColumn(pCol);            } catch(SQLException sqle) {             }         } else {             cRowset = (CachedRowSetImpl)rowset;             if(cRowset.size() == 0){                 throw new SQLException(resBundle.handleGetObject("joinrowsetimpl.emptyrowset").toString());             }        }         // Either column id or column name will be set        // If both not set throw exception.         try {             iMatchKey = (cRowset.getMatchColumnIndexes())[0];        } catch(SQLException sqle) {           //if not set catch the exception but do nothing now.             boolColId = true;        }         try {             strMatchKey = (cRowset.getMatchColumnNames())[0];        } catch(SQLException sqle) {           //if not set catch the exception but do nothing now.           boolColName = true;        }         if(boolColId && boolColName) {           // neither setter methods have been used to set           throw new SQLException(resBundle.handleGetObject("joinrowsetimpl.matchnotset").toString());        } else {           //if(boolColId || boolColName)           // either of the setter methods have been set.           if(boolColId){              //              ArrayList<Integer> indices = new ArrayList<>();              for(int i=0;i<cRowset.getMatchColumnNames().length;i++) {                  if( (strMatchKey = (cRowset.getMatchColumnNames())[i]) != null) {                      iMatchKey = cRowset.findColumn(strMatchKey);                      indices.add(iMatchKey);                  }                  else                      break;              }              int[] indexes = new int[indices.size()];              for(int i=0; i<indices.size();i++)                  indexes[i] = ((Integer)indices.get(i)).intValue();              cRowset.setMatchColumn(indexes);              // Set the match column here because join will be              // based on columnId,              // (nested for loop in initJOIN() checks for equality              //  based on columnIndex)           } else {              //do nothing, iMatchKey is set.           }           // Now both iMatchKey and strMatchKey have been set pointing           // to the same column        }         // Till first rowset setJoinType may not be set because        // default type is JoinRowSet.INNER_JOIN which should        // be set and for subsequent additions of rowset, if not set        // keep on adding join type as JoinRowSet.INNER_JOIN        // to vecJoinType.         initJOIN(cRowset);    }     /**     * Adds the given <code>RowSet</code> object to the <code>JOIN</code> relation     * and sets the designated column as the match column.     * If the given <code>RowSet</code>     * object is the first to be added to this <code>JoinRowSet</code>     * object, it forms the basis of the <code>JOIN</code> relationship to be formed     * when other <code>RowSet</code> objects are added .     * <P>     * This method should be used when the given <code>RowSet</code> object     * does not already have a match column set.     *     * @param rowset a <code>RowSet</code> object to be added to     *         the <code>JOIN</code> relation; must implement the <code>Joinable</code>     *         interface     * @param columnIdx an <code>int</code> giving the index of the column to be set as     *         the match column     * @throws SQLException if (1) an empty <code>RowSet</code> object is added to this     *         <code>JoinRowSet</code> object, (2) a match column has not been set,     *         or (3) the <code>RowSet</code> object being added violates the active     *         <code>JOIN</code>     * @see CachedRowSet#unsetMatchColumn     */    public void addRowSet(RowSet rowset, int columnIdx) throws SQLException {        //passing the rowset as well as the columnIdx to form the joinrowset.         ((CachedRowSetImpl)rowset).setMatchColumn(columnIdx);         addRowSet((Joinable)rowset);    }     /**     * Adds the given <code>RowSet</code> object to the <code>JOIN</code> relationship     * and sets the designated column as the match column. If the given     * <code>RowSet</code>     * object is the first to be added to this <code>JoinRowSet</code>     * object, it forms the basis of the <code>JOIN</code> relationship to be formed     * when other <code>RowSet</code> objects are added .     * <P>     * This method should be used when the given <code>RowSet</code> object     * does not already have a match column set.     *     * @param rowset a <code>RowSet</code> object to be added to     *         the <code>JOIN</code> relation     * @param columnName a <code>String</code> object giving the name of the column     *        to be set as the match column; must implement the <code>Joinable</code>     *        interface     * @throws SQLException if (1) an empty <code>RowSet</code> object is added to this     *         <code>JoinRowSet</code> object, (2) a match column has not been set,     *         or (3) the <code>RowSet</code> object being added violates the active     *         <code>JOIN</code>     */    public void addRowSet(RowSet rowset, String columnName) throws SQLException {        //passing the rowset as well as the columnIdx to form the joinrowset.        ((CachedRowSetImpl)rowset).setMatchColumn(columnName);        addRowSet((Joinable)rowset);    }     /**     * Adds the given <code>RowSet</code> objects to the <code>JOIN</code> relationship     * and sets the designated columns as the match columns. If the first     * <code>RowSet</code> object in the array of <code>RowSet</code> objects     * is the first to be added to this <code>JoinRowSet</code>     * object, it forms the basis of the <code>JOIN</code> relationship to be formed     * when other <code>RowSet</code> objects are added.     * <P>     * The first <code>int</code>     * in <i>columnIdx</i> is used to set the match column for the first     * <code>RowSet</code> object in <i>rowset</i>, the second <code>int</code>     * in <i>columnIdx</i> is used to set the match column for the second     * <code>RowSet</code> object in <i>rowset</i>, and so on.     * <P>     * This method should be used when the given <code>RowSet</code> objects     * do not already have match columns set.     *     * @param rowset an array of <code>RowSet</code> objects to be added to     *         the <code>JOIN</code> relation; each <code>RowSet</code> object must     *         implement the <code>Joinable</code> interface     * @param columnIdx an array of <code>int</code> values designating the columns     *        to be set as the     *        match columns for the <code>RowSet</code> objects in <i>rowset</i>     * @throws SQLException if the number of <code>RowSet</code> objects in     *         <i>rowset</i> is not equal to the number of <code>int</code> values     *         in <i>columnIdx</i>     */    public void addRowSet(RowSet[] rowset,                          int[] columnIdx) throws SQLException {    //validate if length of rowset array is same as length of int array.     if(rowset.length != columnIdx.length) {        throw new SQLException             (resBundle.handleGetObject("joinrowsetimpl.numnotequal").toString());     } else {        for(int i=0; i< rowset.length; i++) {           ((CachedRowSetImpl)rowset[i]).setMatchColumn(columnIdx[i]);           addRowSet((Joinable)rowset[i]);        } //end for     } //end if    }      /**     * Adds the given <code>RowSet</code> objects to the <code>JOIN</code> relationship     * and sets the designated columns as the match columns. If the first     * <code>RowSet</code> object in the array of <code>RowSet</code> objects     * is the first to be added to this <code>JoinRowSet</code>     * object, it forms the basis of the <code>JOIN</code> relationship to be formed     * when other <code>RowSet</code> objects are added.     * <P>     * The first <code>String</code> object     * in <i>columnName</i> is used to set the match column for the first     * <code>RowSet</code> object in <i>rowset</i>, the second <code>String</code>     * object in <i>columnName</i> is used to set the match column for the second     * <code>RowSet</code> object in <i>rowset</i>, and so on.     * <P>     * This method should be used when the given <code>RowSet</code> objects     * do not already have match columns set.     *     * @param rowset an array of <code>RowSet</code> objects to be added to     *         the <code>JOIN</code> relation; each <code>RowSet</code> object must     *         implement the <code>Joinable</code> interface     * @param columnName an array of <code>String</code> objects designating the columns     *        to be set as the     *        match columns for the <code>RowSet</code> objects in <i>rowset</i>     * @throws SQLException if the number of <code>RowSet</code> objects in     *         <i>rowset</i> is not equal to the number of <code>String</code> objects     *         in <i>columnName</i>, an empty <code>JdbcRowSet</code> is added to the     *         <code>JoinRowSet</code>, if a match column is not set,     *         or one or the <code>RowSet</code> objects in <i>rowset</i> violates the     *         active <code>JOIN</code>     */    public void addRowSet(RowSet[] rowset,                          String[] columnName) throws SQLException {    //validate if length of rowset array is same as length of int array.      if(rowset.length != columnName.length) {        throw new SQLException                 (resBundle.handleGetObject("joinrowsetimpl.numnotequal").toString());     } else {        for(int i=0; i< rowset.length; i++) {           ((CachedRowSetImpl)rowset[i]).setMatchColumn(columnName[i]);           addRowSet((Joinable)rowset[i]);        } //end for     } //end if     }     /**     * Returns a Collection of the <code>RowSet</code> object instances     * currently residing with the instance of the <code>JoinRowSet</code>     * object instance. This should return the 'n' number of RowSet contained     * within the JOIN and maintain any updates that have occoured while in     * this union.     *     * @return A <code>Collection</code> of the added <code>RowSet</code>     * object instances     * @throws SQLException if an error occours generating a collection     * of the originating RowSets contained within the JOIN.     */    public Collection getRowSets() throws SQLException {        return vecRowSetsInJOIN;    }     /**     * Returns a string array of the RowSet names currently residing     * with the <code>JoinRowSet</code> object instance.     *     * @return a string array of the RowSet names     * @throws SQLException if an error occours retrieving the RowSet names     * @see CachedRowSet#setTableName     */    public String[] getRowSetNames() throws SQLException {        Object [] arr = vecTableNames.toArray();        String []strArr = new String[arr.length];         for( int i = 0;i < arr.length; i++) {           strArr[i] = arr[i].toString();        }         return strArr;    }     /**     * Creates a separate <code>CachedRowSet</code> object that contains the data     * in this <code>JoinRowSet</code> object.     * <P>     * If any updates or modifications have been applied to this <code>JoinRowSet</code>     * object, the <code>CachedRowSet</code> object returned by this method will     * not be able to persist     * the changes back to the originating rows and tables in the     * data source because the data may be from different tables. The     * <code>CachedRowSet</code> instance returned should not     * contain modification data, such as whether a row has been updated or what the     * original values are.  Also, the <code>CachedRowSet</code> object should clear     * its  properties pertaining to     * its originating SQL statement. An application should reset the     * SQL statement using the <code>RowSet.setCommand</code> method.     * <p>     * To persist changes back to the data source, the <code>JoinRowSet</code> object     * calls the method <code>acceptChanges</code>. Implementations     * can leverage the internal data and update tracking in their     * implementations to interact with the <code>SyncProvider</code> to persist any     * changes.     *     * @return a <code>CachedRowSet</code> object containing the contents of this     *         <code>JoinRowSet</code> object     * @throws SQLException if an error occurs assembling the <code>CachedRowSet</code>     *         object     * @see javax.sql.RowSet     * @see javax.sql.rowset.CachedRowSet     * @see javax.sql.rowset.spi.SyncProvider     */    public CachedRowSet toCachedRowSet() throws SQLException {        return crsInternal;    }     /**     * Returns <code>true</code> if this <code>JoinRowSet</code> object supports     * an SQL <code>CROSS_JOIN</code> and <code>false</code> if it does not.     *     * @return <code>true</code> if the CROSS_JOIN is supported; <code>false</code>     *         otherwise     */    public boolean supportsCrossJoin() {        return supportedJOINs[JoinRowSet.CROSS_JOIN];    }     /**     * Returns <code>true</code> if this <code>JoinRowSet</code> object supports     * an SQL <code>INNER_JOIN</code> and <code>false</code> if it does not.     *     * @return true is the INNER_JOIN is supported; false otherwise     */    public boolean supportsInnerJoin() {        return supportedJOINs[JoinRowSet.INNER_JOIN];    }     /**     * Returns <code>true</code> if this <code>JoinRowSet</code> object supports     * an SQL <code>LEFT_OUTER_JOIN</code> and <code>false</code> if it does not.     *     * @return true is the LEFT_OUTER_JOIN is supported; false otherwise     */    public boolean supportsLeftOuterJoin() {

Lines 1–500 of 4353.