Path: blob/master/src/java.sql.rowset/share/classes/javax/sql/rowset/JoinRowSet.java
40948 views
/*1* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.sql.rowset;2627import java.sql.*;28import javax.sql.*;29import javax.naming.*;30import java.io.*;31import java.math.*;32import java.util.*;3334import javax.sql.rowset.*;3536/**37* The <code>JoinRowSet</code> interface provides a mechanism for combining related38* data from different <code>RowSet</code> objects into one <code>JoinRowSet</code>39* object, which represents an SQL <code>JOIN</code>.40* In other words, a <code>JoinRowSet</code> object acts as a41* container for the data from <code>RowSet</code> objects that form an SQL42* <code>JOIN</code> relationship.43* <P>44* The <code>Joinable</code> interface provides the methods for setting,45* retrieving, and unsetting a match column, the basis for46* establishing an SQL <code>JOIN</code> relationship. The match column may47* alternatively be set by supplying it to the appropriate version of the48* <code>JointRowSet</code> method <code>addRowSet</code>.49*50* <h2>1.0 Overview</h2>51* Disconnected <code>RowSet</code> objects (<code>CachedRowSet</code> objects52* and implementations extending the <code>CachedRowSet</code> interface)53* do not have a standard way to establish an SQL <code>JOIN</code> between54* <code>RowSet</code> objects without the expensive operation of55* reconnecting to the data source. The <code>JoinRowSet</code>56* interface is specifically designed to address this need.57* <P>58* Any <code>RowSet</code> object59* can be added to a <code>JoinRowSet</code> object to become60* part of an SQL <code>JOIN</code> relationship. This means that both connected61* and disconnected <code>RowSet</code> objects can be part of a <code>JOIN</code>.62* <code>RowSet</code> objects operating in a connected environment63* (<code>JdbcRowSet</code> objects) are64* encouraged to use the database to which they are already65* connected to establish SQL <code>JOIN</code> relationships between66* tables directly. However, it is possible for a67* <code>JdbcRowSet</code> object to be added to a <code>JoinRowSet</code> object68* if necessary.69* <P>70* Any number of <code>RowSet</code> objects can be added to an71* instance of <code>JoinRowSet</code> provided that they72* can be related in an SQL <code>JOIN</code>.73* By definition, the SQL <code>JOIN</code> statement is used to74* combine the data contained in two or more relational database tables based75* upon a common attribute. The <code>Joinable</code> interface provides the methods76* for establishing a common attribute, which is done by setting a77* <i>match column</i>. The match column commonly coincides with78* the primary key, but there is79* no requirement that the match column be the same as the primary key.80* By establishing and then enforcing column matches,81* a <code>JoinRowSet</code> object establishes <code>JOIN</code> relationships82* between <code>RowSet</code> objects without the assistance of an available83* relational database.84* <P>85* The type of <code>JOIN</code> to be established is determined by setting86* one of the <code>JoinRowSet</code> constants using the method87* <code>setJoinType</code>. The following SQL <code>JOIN</code> types can be set:88* <UL>89* <LI><code>CROSS_JOIN</code>90* <LI><code>FULL_JOIN</code>91* <LI><code>INNER_JOIN</code> - the default if no <code>JOIN</code> type has been set92* <LI><code>LEFT_OUTER_JOIN</code>93* <LI><code>RIGHT_OUTER_JOIN</code>94* </UL>95* Note that if no type is set, the <code>JOIN</code> will automatically be an96* inner join. The comments for the fields in the97* <code>JoinRowSet</code> interface explain these <code>JOIN</code> types, which are98* standard SQL <code>JOIN</code> types.99*100* <h2>2.0 Using a <code>JoinRowSet</code> Object for Creating a <code>JOIN</code></h2>101* When a <code>JoinRowSet</code> object is created, it is empty.102* The first <code>RowSet</code> object to be added becomes the basis for the103* <code>JOIN</code> relationship.104* Applications must determine which column in each of the105* <code>RowSet</code> objects to be added to the <code>JoinRowSet</code> object106* should be the match column. All of the107* <code>RowSet</code> objects must contain a match column, and the values in108* each match column must be ones that can be compared to values in the other match109* columns. The columns do not have to have the same name, though they often do,110* and they do not have to store the exact same data type as long as the data types111* can be compared.112* <P>113* A match column can be set in two ways:114* <ul>115* <li>By calling the <code>Joinable</code> method <code>setMatchColumn</code><br>116* This is the only method that can set the match column before a <code>RowSet</code>117* object is added to a <code>JoinRowSet</code> object. The <code>RowSet</code> object118* must have implemented the <code>Joinable</code> interface in order to use the method119* <code>setMatchColumn</code>. Once the match column value120* has been set, this method can be used to reset the match column at any time.121* <li>By calling one of the versions of the <code>JoinRowSet</code> method122* <code>addRowSet</code> that takes a column name or number (or an array of123* column names or numbers)<BR>124* Four of the five <code>addRowSet</code> methods take a match column as a parameter.125* These four methods set or reset the match column at the time a <code>RowSet</code>126* object is being added to a <code>JoinRowSet</code> object.127* </ul>128* <h2>3.0 Sample Usage</h2>129* <p>130* The following code fragment adds two <code>CachedRowSet</code>131* objects to a <code>JoinRowSet</code> object. Note that in this example,132* no SQL <code>JOIN</code> type is set, so the default <code>JOIN</code> type,133* which is <i>INNER_JOIN</i>, is established.134* <p>135* In the following code fragment, the table <code>EMPLOYEES</code>, whose match136* column is set to the first column (<code>EMP_ID</code>), is added to the137* <code>JoinRowSet</code> object <i>jrs</i>. Then138* the table <code>ESSP_BONUS_PLAN</code>, whose match column is likewise139* the <code>EMP_ID</code> column, is added. When this second140* table is added to <i>jrs</i>, only the rows in141* <code>ESSP_BONUS_PLAN</code> whose <code>EMP_ID</code> value matches an142* <code>EMP_ID</code> value in the <code>EMPLOYEES</code> table are added.143* In this case, everyone in the bonus plan is an employee, so all of the rows144* in the table <code>ESSP_BONUS_PLAN</code> are added to the <code>JoinRowSet</code>145* object. In this example, both <code>CachedRowSet</code> objects being added146* have implemented the <code>Joinable</code> interface and can therefore call147* the <code>Joinable</code> method <code>setMatchColumn</code>.148* <PRE>149* JoinRowSet jrs = new JoinRowSetImpl();150*151* ResultSet rs1 = stmt.executeQuery("SELECT * FROM EMPLOYEES");152* CachedRowSet empl = new CachedRowSetImpl();153* empl.populate(rs1);154* empl.setMatchColumn(1);155* jrs.addRowSet(empl);156*157* ResultSet rs2 = stmt.executeQuery("SELECT * FROM ESSP_BONUS_PLAN");158* CachedRowSet bonus = new CachedRowSetImpl();159* bonus.populate(rs2);160* bonus.setMatchColumn(1); // EMP_ID is the first column161* jrs.addRowSet(bonus);162* </PRE>163* <P>164* At this point, <i>jrs</i> is an inside JOIN of the two <code>RowSet</code> objects165* based on their <code>EMP_ID</code> columns. The application can now browse the166* combined data as if it were browsing one single <code>RowSet</code> object.167* Because <i>jrs</i> is itself a <code>RowSet</code> object, an application can168* navigate or modify it using <code>RowSet</code> methods.169* <PRE>170* jrs.first();171* int employeeID = jrs.getInt(1);172* String employeeName = jrs.getString(2);173* </PRE>174* <P>175* Note that because the SQL <code>JOIN</code> must be enforced when an application176* adds a second or subsequent <code>RowSet</code> object, there177* may be an initial degradation in performance while the <code>JOIN</code> is178* being performed.179* <P>180* The following code fragment adds an additional <code>CachedRowSet</code> object.181* In this case, the match column (<code>EMP_ID</code>) is set when the182* <code>CachedRowSet</code> object is added to the <code>JoinRowSet</code> object.183* <PRE>184* ResultSet rs3 = stmt.executeQuery("SELECT * FROM 401K_CONTRIB");185* CachedRowSet fourO1k = new CachedRowSetImpl();186* four01k.populate(rs3);187* jrs.addRowSet(four01k, 1);188* </PRE>189* <P>190* The <code>JoinRowSet</code> object <i>jrs</i> now contains values from all three191* tables. The data in each row in <i>four01k</i> in which the value for the192* <code>EMP_ID</code> column matches a value for the <code>EMP_ID</code> column193* in <i>jrs</i> has been added to <i>jrs</i>.194*195* <h2>4.0 <code>JoinRowSet</code> Methods</h2>196* The <code>JoinRowSet</code> interface supplies several methods for adding197* <code>RowSet</code> objects and for getting information about the198* <code>JoinRowSet</code> object.199* <UL>200* <LI>Methods for adding one or more <code>RowSet</code> objects<BR>201* These methods allow an application to add one <code>RowSet</code> object202* at a time or to add multiple <code>RowSet</code> objects at one time. In203* either case, the methods may specify the match column for each204* <code>RowSet</code> object being added.205* <LI>Methods for getting information<BR>206* One method retrieves the <code>RowSet</code> objects in the207* <code>JoinRowSet</code> object, and another method retrieves the208* <code>RowSet</code> names. A third method retrieves either the SQL209* <code>WHERE</code> clause used behind the scenes to form the210* <code>JOIN</code> or a text description of what the <code>WHERE</code>211* clause does.212* <LI>Methods related to the type of <code>JOIN</code><BR>213* One method sets the <code>JOIN</code> type, and five methods find out whether214* the <code>JoinRowSet</code> object supports a given type.215* <LI>A method to make a separate copy of the <code>JoinRowSet</code> object<BR>216* This method creates a copy that can be persisted to the data source.217* </UL>218*219* @since 1.5220*/221222public interface JoinRowSet extends WebRowSet {223224/**225* Adds the given <code>RowSet</code> object to this <code>JoinRowSet</code>226* object. If the <code>RowSet</code> object227* is the first to be added to this <code>JoinRowSet</code>228* object, it forms the basis of the <code>JOIN</code> relationship to be229* established.230* <P>231* This method should be used only when the given <code>RowSet</code>232* object already has a match column that was set with the <code>Joinable</code>233* method <code>setMatchColumn</code>.234* <p>235* Note: A <code>Joinable</code> object is any <code>RowSet</code> object236* that has implemented the <code>Joinable</code> interface.237*238* @param rowset the <code>RowSet</code> object that is to be added to this239* <code>JoinRowSet</code> object; it must implement the240* <code>Joinable</code> interface and have a match column set241* @throws SQLException if (1) an empty rowset is added to the to this242* <code>JoinRowSet</code> object, (2) a match column has not been243* set for <i>rowset</i>, or (3) <i>rowset</i>244* violates the active <code>JOIN</code>245* @see Joinable#setMatchColumn246*/247public void addRowSet(Joinable rowset) throws SQLException;248249/**250* Adds the given <code>RowSet</code> object to this <code>JoinRowSet</code>251* object and sets the designated column as the match column for252* the <code>RowSet</code> object. If the <code>RowSet</code> object253* is the first to be added to this <code>JoinRowSet</code>254* object, it forms the basis of the <code>JOIN</code> relationship to be255* established.256* <P>257* This method should be used when <i>RowSet</i> does not already have a match258* column set.259*260* @param rowset the <code>RowSet</code> object that is to be added to this261* <code>JoinRowSet</code> object; it may implement the262* <code>Joinable</code> interface263* @param columnIdx an <code>int</code> that identifies the column to become the264* match column265* @throws SQLException if (1) <i>rowset</i> is an empty rowset or266* (2) <i>rowset</i> violates the active <code>JOIN</code>267* @see Joinable#unsetMatchColumn268*/269public void addRowSet(RowSet rowset, int columnIdx) throws SQLException;270271/**272* Adds <i>rowset</i> to this <code>JoinRowSet</code> object and273* sets the designated column as the match column. If <i>rowset</i>274* is the first to be added to this <code>JoinRowSet</code>275* object, it forms the basis for the <code>JOIN</code> relationship to be276* established.277* <P>278* This method should be used when the given <code>RowSet</code> object279* does not already have a match column.280*281* @param rowset the <code>RowSet</code> object that is to be added to this282* <code>JoinRowSet</code> object; it may implement the283* <code>Joinable</code> interface284* @param columnName the <code>String</code> object giving the name of the285* column to be set as the match column286* @throws SQLException if (1) <i>rowset</i> is an empty rowset or287* (2) the match column for <i>rowset</i> does not satisfy the288* conditions of the <code>JOIN</code>289*/290public void addRowSet(RowSet rowset,291String columnName) throws SQLException;292293/**294* Adds one or more <code>RowSet</code> objects contained in the given295* array of <code>RowSet</code> objects to this <code>JoinRowSet</code>296* object and sets the match column for297* each of the <code>RowSet</code> objects to the match columns298* in the given array of column indexes. The first element in299* <i>columnIdx</i> is set as the match column for the first300* <code>RowSet</code> object in <i>rowset</i>, the second element of301* <i>columnIdx</i> is set as the match column for the second element302* in <i>rowset</i>, and so on.303* <P>304* The first <code>RowSet</code> object added to this <code>JoinRowSet</code>305* object forms the basis for the <code>JOIN</code> relationship.306* <P>307* This method should be used when the given <code>RowSet</code> object308* does not already have a match column.309*310* @param rowset an array of one or more <code>RowSet</code> objects311* to be added to the <code>JOIN</code>; it may implement the312* <code>Joinable</code> interface313* @param columnIdx an array of <code>int</code> values indicating the index(es)314* of the columns to be set as the match columns for the <code>RowSet</code>315* objects in <i>rowset</i>316* @throws SQLException if (1) an empty rowset is added to this317* <code>JoinRowSet</code> object, (2) a match column is not set318* for a <code>RowSet</code> object in <i>rowset</i>, or (3)319* a <code>RowSet</code> object being added violates the active320* <code>JOIN</code>321*/322public void addRowSet(RowSet[] rowset,323int[] columnIdx) throws SQLException;324325/**326* Adds one or more <code>RowSet</code> objects contained in the given327* array of <code>RowSet</code> objects to this <code>JoinRowSet</code>328* object and sets the match column for329* each of the <code>RowSet</code> objects to the match columns330* in the given array of column names. The first element in331* <i>columnName</i> is set as the match column for the first332* <code>RowSet</code> object in <i>rowset</i>, the second element of333* <i>columnName</i> is set as the match column for the second element334* in <i>rowset</i>, and so on.335* <P>336* The first <code>RowSet</code> object added to this <code>JoinRowSet</code>337* object forms the basis for the <code>JOIN</code> relationship.338* <P>339* This method should be used when the given <code>RowSet</code> object(s)340* does not already have a match column.341*342* @param rowset an array of one or more <code>RowSet</code> objects343* to be added to the <code>JOIN</code>; it may implement the344* <code>Joinable</code> interface345* @param columnName an array of <code>String</code> values indicating the346* names of the columns to be set as the match columns for the347* <code>RowSet</code> objects in <i>rowset</i>348* @throws SQLException if (1) an empty rowset is added to this349* <code>JoinRowSet</code> object, (2) a match column is not set350* for a <code>RowSet</code> object in <i>rowset</i>, or (3)351* a <code>RowSet</code> object being added violates the active352* <code>JOIN</code>353*/354public void addRowSet(RowSet[] rowset,355String[] columnName) throws SQLException;356357/**358* Returns a <code>Collection</code> object containing the359* <code>RowSet</code> objects that have been added to this360* <code>JoinRowSet</code> object.361* This should return the 'n' number of RowSet contained362* within the <code>JOIN</code> and maintain any updates that have occurred while in363* this union.364*365* @return a <code>Collection</code> object consisting of the366* <code>RowSet</code> objects added to this <code>JoinRowSet</code>367* object368* @throws SQLException if an error occurs generating the369* <code>Collection</code> object to be returned370*/371public Collection<?> getRowSets() throws java.sql.SQLException;372373/**374* Returns a <code>String</code> array containing the names of the375* <code>RowSet</code> objects added to this <code>JoinRowSet</code>376* object.377*378* @return a <code>String</code> array of the names of the379* <code>RowSet</code> objects in this <code>JoinRowSet</code>380* object381* @throws SQLException if an error occurs retrieving the names of382* the <code>RowSet</code> objects383* @see CachedRowSet#setTableName384*/385public String[] getRowSetNames() throws java.sql.SQLException;386387/**388* Creates a new <code>CachedRowSet</code> object containing the389* data in this <code>JoinRowSet</code> object, which can be saved390* to a data source using the <code>SyncProvider</code> object for391* the <code>CachedRowSet</code> object.392* <P>393* If any updates or modifications have been applied to the JoinRowSet394* the CachedRowSet returned by the method will not be able to persist395* it's changes back to the originating rows and tables in the396* in the datasource. The CachedRowSet instance returned should not397* contain modification data and it should clear all properties of398* it's originating SQL statement. An application should reset the399* SQL statement using the <code>RowSet.setCommand</code> method.400* <p>401* In order to allow changes to be persisted back to the datasource402* to the originating tables, the <code>acceptChanges</code> method403* should be used and called on a JoinRowSet object instance. Implementations404* can leverage the internal data and update tracking in their405* implementations to interact with the SyncProvider to persist any406* changes.407*408* @return a CachedRowSet containing the contents of the JoinRowSet409* @throws SQLException if an error occurs assembling the CachedRowSet410* object411* @see javax.sql.RowSet412* @see javax.sql.rowset.CachedRowSet413* @see javax.sql.rowset.spi.SyncProvider414*/415public CachedRowSet toCachedRowSet() throws java.sql.SQLException;416417/**418* Indicates if CROSS_JOIN is supported by a JoinRowSet419* implementation420*421* @return true if the CROSS_JOIN is supported; false otherwise422*/423public boolean supportsCrossJoin();424425/**426* Indicates if INNER_JOIN is supported by a JoinRowSet427* implementation428*429* @return true is the INNER_JOIN is supported; false otherwise430*/431public boolean supportsInnerJoin();432433/**434* Indicates if LEFT_OUTER_JOIN is supported by a JoinRowSet435* implementation436*437* @return true is the LEFT_OUTER_JOIN is supported; false otherwise438*/439public boolean supportsLeftOuterJoin();440441/**442* Indicates if RIGHT_OUTER_JOIN is supported by a JoinRowSet443* implementation444*445* @return true is the RIGHT_OUTER_JOIN is supported; false otherwise446*/447public boolean supportsRightOuterJoin();448449/**450* Indicates if FULL_JOIN is supported by a JoinRowSet451* implementation452*453* @return true is the FULL_JOIN is supported; false otherwise454*/455public boolean supportsFullJoin();456457/**458* Allow the application to adjust the type of <code>JOIN</code> imposed459* on tables contained within the JoinRowSet object instance.460* Implementations should throw a SQLException if they do461* not support a given <code>JOIN</code> type.462*463* @param joinType the standard JoinRowSet.XXX static field definition464* of a SQL <code>JOIN</code> to re-configure a JoinRowSet instance on465* the fly.466* @throws SQLException if an unsupported <code>JOIN</code> type is set467* @see #getJoinType468*/469public void setJoinType(int joinType) throws SQLException;470471/**472* Return a SQL-like description of the WHERE clause being used473* in a JoinRowSet object. An implementation can describe474* the WHERE clause of the SQL <code>JOIN</code> by supplying a SQL475* strings description of <code>JOIN</code> or provide a textual476* description to assist applications using a <code>JoinRowSet</code>477*478* @return whereClause a textual or SQL description of the logical479* WHERE clause used in the JoinRowSet instance480* @throws SQLException if an error occurs in generating a representation481* of the WHERE clause.482*/483public String getWhereClause() throws SQLException;484485/**486* Returns a <code>int</code> describing the set SQL <code>JOIN</code> type487* governing this JoinRowSet instance. The returned type will be one of488* standard JoinRowSet types: <code>CROSS_JOIN</code>, <code>INNER_JOIN</code>,489* <code>LEFT_OUTER_JOIN</code>, <code>RIGHT_OUTER_JOIN</code> or490* <code>FULL_JOIN</code>.491*492* @return joinType one of the standard JoinRowSet static field493* definitions of a SQL <code>JOIN</code>. <code>JoinRowSet.INNER_JOIN</code>494* is returned as the default <code>JOIN</code> type is no type has been495* explicitly set.496* @throws SQLException if an error occurs determining the SQL <code>JOIN</code>497* type supported by the JoinRowSet instance.498* @see #setJoinType499*/500public int getJoinType() throws SQLException;501502/**503* An ANSI-style <code>JOIN</code> providing a cross product of two tables504*/505public static int CROSS_JOIN = 0;506507/**508* An ANSI-style <code>JOIN</code> providing a inner join between two tables. Any509* unmatched rows in either table of the join should be discarded.510*/511public static int INNER_JOIN = 1;512513/**514* An ANSI-style <code>JOIN</code> providing a left outer join between two515* tables. In SQL, this is described where all records should be516* returned from the left side of the JOIN statement.517*/518public static int LEFT_OUTER_JOIN = 2;519520/**521* An ANSI-style <code>JOIN</code> providing a right outer join between522* two tables. In SQL, this is described where all records from the523* table on the right side of the JOIN statement even if the table524* on the left has no matching record.525*/526public static int RIGHT_OUTER_JOIN = 3;527528/**529* An ANSI-style <code>JOIN</code> providing a full JOIN. Specifies that all530* rows from either table be returned regardless of matching531* records on the other table.532*/533public static int FULL_JOIN = 4;534535536}537538539