001: /**
002: * com.mckoi.database.interpret.FromClause 09 Sep 2001
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.interpret;
024:
025: import com.mckoi.database.*;
026: import java.util.Set;
027: import java.util.HashMap;
028: import java.util.ArrayList;
029: import java.util.Collection;
030:
031: /**
032: * A container for the From clause of a select statement. This handles
033: * the different types of joins.
034: *
035: * @author Tobias Downer
036: */
037:
038: public final class FromClause implements java.io.Serializable,
039: StatementTreeObject, Cloneable {
040:
041: static final long serialVersionUID = 565726601314503609L;
042:
043: /**
044: * The JoiningSet object that we have created to represent the joins in this
045: * FROM clause.
046: */
047: private JoiningSet join_set = new JoiningSet();
048:
049: /**
050: * A list of all FromTableDef objects in this clause in order of when they
051: * were specified.
052: */
053: private ArrayList def_list = new ArrayList();
054:
055: /**
056: * A list of all table names in this from clause.
057: */
058: private ArrayList all_table_names = new ArrayList();
059:
060: /**
061: * An id used for making unique names for anonymous inner selects.
062: */
063: private int table_key = 0;
064:
065: /**
066: * Creates a new unique key string.
067: */
068: private String createNewKey() {
069: ++table_key;
070: return Integer.toString(table_key);
071: }
072:
073: private void addTableDef(String table_name, FromTableDef def) {
074: if (table_name != null) {
075: if (all_table_names.contains(table_name)) {
076: throw new Error("Duplicate table name in FROM clause: "
077: + table_name);
078: }
079: all_table_names.add(table_name);
080: }
081: // Create a new unique key for this table
082: String key = createNewKey();
083: def.setUniqueKey(key);
084: // Add the table key to the join set
085: join_set.addTable(new TableName(key));
086: // Add to the alias def map
087: def_list.add(def);
088: }
089:
090: /**
091: * Adds a table name to this FROM clause. Note that the given name
092: * may be a dot deliminated ref such as (schema.table_name).
093: */
094: public void addTable(String table_name) {
095: addTableDef(table_name, new FromTableDef(table_name));
096: }
097:
098: /**
099: * Adds a table name + alias to this FROM clause.
100: */
101: public void addTable(String table_name, String table_alias) {
102: addTableDef(table_alias, new FromTableDef(table_name,
103: table_alias));
104: }
105:
106: /**
107: * A generic form of a table declaration. If any parameters are 'null' it
108: * means the information is not available.
109: */
110: public void addTableDeclaration(String table_name,
111: TableSelectExpression select, String table_alias) {
112: // This is an inner select in the FROM clause
113: if (table_name == null && select != null) {
114: if (table_alias == null) {
115: addTableDef(null, new FromTableDef(select));
116: } else {
117: addTableDef(table_alias, new FromTableDef(select,
118: table_alias));
119: }
120: }
121: // This is a standard table reference in the FROM clause
122: else if (table_name != null && select == null) {
123: if (table_alias == null) {
124: addTable(table_name);
125: } else {
126: addTable(table_name, table_alias);
127: }
128: }
129: // Error
130: else {
131: throw new Error("Unvalid declaration parameters.");
132: }
133:
134: }
135:
136: /**
137: * Adds a Join to the from clause. 'type' must be a join type as defined
138: * in JoiningSet.
139: */
140: public void addJoin(int type) {
141: // System.out.println("Add Join: " + type);
142: join_set.addJoin(type);
143: }
144:
145: /**
146: * Hack, add a joining type to the previous entry from the end. This is
147: * an artifact of how joins are parsed.
148: */
149: public void addPreviousJoin(int type, Expression on_expression) {
150: join_set.addPreviousJoin(type, on_expression);
151: }
152:
153: /**
154: * Adds a Join to the from clause. 'type' must be a join type as defined
155: * in JoiningSet, and expression represents the ON condition.
156: */
157: public void addJoin(int type, Expression on_expression) {
158: join_set.addJoin(type, on_expression);
159: }
160:
161: /**
162: * Returns the JoiningSet object for the FROM clause.
163: */
164: public JoiningSet getJoinSet() {
165: return join_set;
166: }
167:
168: /**
169: * Returns the type of join after table 'n' in the set of tables in the
170: * from clause. Returns, JoiningSet.INNER_JOIN, JoiningSet.FULL_OUTER_JOIN,
171: * etc.
172: */
173: public int getJoinType(int n) {
174: return getJoinSet().getJoinType(n);
175: }
176:
177: /**
178: * Returns the ON Expression for the type of join after table 'n' in the
179: * set.
180: */
181: public Expression getOnExpression(int n) {
182: return getJoinSet().getOnExpression(n);
183: }
184:
185: /**
186: * Returns a Set of FromTableDef objects that represent all the tables
187: * that are in this from clause.
188: */
189: public Collection allTables() {
190: return def_list;
191: }
192:
193: // Implemented from StatementTreeObject
194: public void prepareExpressions(ExpressionPreparer preparer)
195: throws DatabaseException {
196: // Prepare expressions in the JoiningSet first
197: int size = join_set.getTableCount() - 1;
198: for (int i = 0; i < size; ++i) {
199: Expression exp = join_set.getOnExpression(i);
200: if (exp != null) {
201: exp.prepare(preparer);
202: }
203: }
204: // Prepare the StatementTree sub-queries in the from tables
205: for (int i = 0; i < def_list.size(); ++i) {
206: FromTableDef table_def = (FromTableDef) def_list.get(i);
207: table_def.prepareExpressions(preparer);
208: }
209:
210: }
211:
212: public Object clone() throws CloneNotSupportedException {
213: FromClause v = (FromClause) super .clone();
214: v.join_set = (JoiningSet) join_set.clone();
215: ArrayList cloned_def_list = new ArrayList(def_list.size());
216: v.def_list = cloned_def_list;
217: v.all_table_names = (ArrayList) all_table_names.clone();
218:
219: for (int i = 0; i < def_list.size(); ++i) {
220: FromTableDef table_def = (FromTableDef) def_list.get(i);
221: cloned_def_list.add(table_def.clone());
222: }
223:
224: return v;
225: }
226:
227: }
|