001: /**
002: * com.mckoi.database.JoiningSet 20 Sep 2000
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.database;
024:
025: import java.util.ArrayList;
026:
027: /**
028: * Used in TableSet to describe how we naturally join the tables together.
029: * This is used when the TableSet has evaluated the search condition and it
030: * is required for any straggling tables to be naturally joined. In SQL,
031: * these joining types are specified in the FROM clause.
032: * <p>
033: * For example,<br><pre>
034: * FROM table_a LEFT OUTER JOIN table_b ON ( table_a.id = table_b.id ), ...
035: * </pre><p>
036: * A ',' should donate an INNER_JOIN in an SQL FROM clause.
037: *
038: * @author Tobias Downer
039: */
040:
041: public final class JoiningSet implements java.io.Serializable,
042: Cloneable {
043:
044: static final long serialVersionUID = -380871062550922402L;
045:
046: /**
047: * Statics for Join Types.
048: */
049: // Donates a standard inner join (in SQL, this is ',' in the FROM clause)
050: public final static int INNER_JOIN = 1;
051: // Left Outer Join,
052: public final static int LEFT_OUTER_JOIN = 2;
053: // Right Outer Join,
054: public final static int RIGHT_OUTER_JOIN = 3;
055: // Full Outer Join
056: public final static int FULL_OUTER_JOIN = 4;
057:
058: /**
059: * The list of tables we are joining together a JoinPart object that
060: * represents how the tables are joined.
061: */
062: private ArrayList join_set;
063:
064: /**
065: * Constructs the JoiningSet.
066: */
067: public JoiningSet() {
068: join_set = new ArrayList();
069: }
070:
071: /**
072: * Resolves the schema of tables in this joining set. This runs through
073: * each table in the joining set and if the schema has not been set for the
074: * table then it attempts to resolve it against the given DatabaseConnection
075: * object. This would typically be called in the preparation of a statement.
076: */
077: public void prepare(DatabaseConnection connection) {
078: }
079:
080: /**
081: * Adds a new table into the set being joined. The table name should be the
082: * unique name that distinguishes this table in the TableSet.
083: */
084: public void addTable(TableName table_name) {
085: join_set.add(table_name);
086: }
087:
088: /**
089: * Hack, add a joining type to the previous entry from the end. This is
090: * an artifact of how joins are parsed.
091: */
092: public void addPreviousJoin(int type, Expression on_expression) {
093: join_set.add(join_set.size() - 1, new JoinPart(type,
094: on_expression));
095: }
096:
097: /**
098: * Adds a joining type to the set, and an 'on' expression.
099: */
100: public void addJoin(int type, Expression on_expression) {
101: join_set.add(new JoinPart(type, on_expression));
102: }
103:
104: /**
105: * Adds a joining type to the set with no 'on' expression.
106: */
107: public void addJoin(int type) {
108: join_set.add(new JoinPart(type));
109: }
110:
111: /**
112: * Returns the number of tables that are in this set.
113: */
114: public int getTableCount() {
115: return (join_set.size() + 1) / 2;
116: }
117:
118: /**
119: * Returns the first table in the join set.
120: */
121: public TableName getFirstTable() {
122: return getTable(0);
123: }
124:
125: /**
126: * Returns table 'n' in the result set where table 0 is the first table in
127: * the join set.
128: */
129: public TableName getTable(int n) {
130: return (TableName) join_set.get(n * 2);
131: }
132:
133: /**
134: * Sets the table at the given position in this joining set.
135: */
136: private void setTable(int n, TableName table) {
137: join_set.set(n * 2, table);
138: }
139:
140: /**
141: * Returns the type of join after table 'n' in the set. An example
142: * of using this;<p><pre>
143: *
144: * String table1 = joins.getFirstTable();
145: * for (int i = 0; i < joins.getTableCount() - 1; ++i) {
146: * int type = joins.getJoinType(i);
147: * String table2 = getTable(i + 1);
148: * // ... Join table1 and table2 ...
149: * table1 = table2;
150: * }
151: *
152: * </pre>
153: */
154: public int getJoinType(int n) {
155: return ((JoinPart) join_set.get((n * 2) + 1)).type;
156: }
157:
158: /**
159: * Returns the ON Expression for the type of join after table 'n' in the
160: * set.
161: */
162: public Expression getOnExpression(int n) {
163: return ((JoinPart) join_set.get((n * 2) + 1)).on_expression;
164: }
165:
166: /**
167: * Performs a deep clone on this object.
168: */
169: public Object clone() throws CloneNotSupportedException {
170: JoiningSet v = (JoiningSet) super .clone();
171: int size = join_set.size();
172: ArrayList cloned_join_set = new ArrayList(size);
173: v.join_set = cloned_join_set;
174:
175: for (int i = 0; i < size; ++i) {
176: Object element = join_set.get(i);
177: if (element instanceof TableName) {
178: // immutable so leave alone
179: } else if (element instanceof JoinPart) {
180: element = ((JoinPart) element).clone();
181: } else {
182: throw new CloneNotSupportedException(element.getClass()
183: .toString());
184: }
185: cloned_join_set.add(element);
186: }
187:
188: return v;
189: }
190:
191: // ---------- Inner classes ----------
192:
193: public static class JoinPart implements java.io.Serializable,
194: Cloneable {
195:
196: static final long serialVersionUID = -1664565759669808084L;
197:
198: /**
199: * The type of join. Either LEFT_OUTER_JOIN,
200: * RIGHT_OUTER_JOIN, FULL_OUTER_JOIN, INNER_JOIN.
201: */
202: int type;
203:
204: /**
205: * The expression that we are joining on (eg. ON clause in SQL). If there
206: * is no ON expression (such as in the case of natural joins) then this is
207: * null.
208: */
209: Expression on_expression;
210:
211: /**
212: * Constructs the JoinPart.
213: */
214: public JoinPart(int type, Expression on_expression) {
215: this .type = type;
216: this .on_expression = on_expression;
217: }
218:
219: public JoinPart(int type) {
220: this (type, null);
221: }
222:
223: public Object clone() throws CloneNotSupportedException {
224: JoinPart v = (JoinPart) super .clone();
225: if (on_expression != null) {
226: v.on_expression = (Expression) on_expression.clone();
227: }
228: return v;
229: }
230:
231: }
232:
233: }
|