001: /*
002: $Header: /cvsroot/xorm/xorm/src/org/xorm/query/Selector.java,v 1.18 2003/11/12 23:39:06 wbiggs Exp $
003:
004: This file is part of XORM.
005:
006: XORM is free software; you can redistribute it and/or modify
007: it under the terms of the GNU General Public License as published by
008: the Free Software Foundation; either version 2 of the License, or
009: (at your option) any later version.
010:
011: XORM 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 for more details.
015:
016: You should have received a copy of the GNU General Public License
017: along with XORM; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package org.xorm.query;
021:
022: import org.xorm.datastore.Column;
023: import org.xorm.datastore.DataFetchGroup;
024: import org.xorm.datastore.Table;
025:
026: import java.util.Set;
027: import java.util.Iterator;
028:
029: public class Selector implements Cloneable {
030: /** Immutable class to capture ordering information. */
031: public static class Ordering {
032: public static final int ASCENDING = 0;
033: public static final int DESCENDING = 1;
034:
035: private Column column;
036: private int order;
037:
038: public Ordering(Column column, int order) {
039: this .column = column;
040: this .order = order;
041: }
042:
043: public Column getColumn() {
044: return column;
045: }
046:
047: public int getOrder() {
048: return order;
049: }
050: }
051:
052: private Table table;
053: private Condition condition;
054: private Set fetchColumns;
055: private boolean outerJoin;
056: private Ordering[] ordering;
057: private Column joinColumn;
058:
059: public Selector(Table table, Condition condition) {
060: this .table = table;
061: this .condition = condition;
062: this .joinColumn = table.getPrimaryKey();
063: }
064:
065: public Object clone() {
066: Selector clone = null;
067: try {
068: clone = (Selector) super .clone();
069: if (condition != null) {
070: clone.condition = (Condition) condition.clone();
071: }
072: } catch (CloneNotSupportedException ignore) {
073: }
074: return clone;
075: }
076:
077: public boolean isOuterJoin() {
078: return outerJoin;
079: }
080:
081: public void setOuterJoin(boolean value) {
082: outerJoin = value;
083: }
084:
085: public Table getTable() {
086: return table;
087: }
088:
089: public Condition getCondition() {
090: return condition;
091: }
092:
093: public void setCondition(Condition condition) {
094: this .condition = condition;
095: }
096:
097: public Set getFetchColumns() {
098: return fetchColumns;
099: }
100:
101: public void setOrdering(Ordering[] ordering) {
102: this .ordering = ordering;
103: }
104:
105: public Ordering[] getOrdering() {
106: return ordering;
107: }
108:
109: public Column getJoinColumn() {
110: return joinColumn;
111: }
112:
113: public void setJoinColumn(Column joinColumn) {
114: this .joinColumn = joinColumn;
115: }
116:
117: public String toString() {
118: return (table == null ? null : table.getName()) + "."
119: + (joinColumn == null ? null : joinColumn.getName())
120: + " where " + condition;
121: }
122:
123: public void require(DataFetchGroup fetchGroup) {
124: fetchColumns = fetchGroup.getColumns();
125: Column column;
126: Iterator i = fetchGroup.getSubgroupColumns().iterator();
127: while (i.hasNext()) {
128: column = (Column) i.next();
129: DataFetchGroup subgroup = fetchGroup.getSubgroup(column);
130: // Find or create the Selector for the subgroup
131: Selector selector = findSelector(condition, subgroup
132: .getTable());
133: if (selector == null) {
134: selector = new Selector(subgroup.getTable(), null);
135: selector.outerJoin = !column.isNonNull();
136: Condition join = new SimpleCondition(column,
137: Operator.EQUAL, selector);
138: if (condition != null) {
139: condition = new AndCondition(join, condition);
140: } else {
141: condition = join;
142: }
143: }
144: selector.require(subgroup);
145: }
146: }
147:
148: public Selector findSelector(Table table) {
149: if (this .table == table)
150: return this ;
151: return findSelector(condition, table);
152: }
153:
154: private static Selector findSelector(Condition condition,
155: Table table) {
156: Selector result = null;
157: if (condition instanceof SimpleCondition) {
158: Object v = ((SimpleCondition) condition).getValue();
159: if (v instanceof Selector) {
160: Selector s = (Selector) v;
161: if (s.getTable().equals(table)) {
162: result = s;
163: } else {
164: return findSelector(s.getCondition(), table);
165: }
166: }
167: } else if (condition instanceof CompoundCondition) {
168: CompoundCondition cc = (CompoundCondition) condition;
169: // Try LHS
170: result = findSelector(cc.getLHS(), table);
171: if (result == null) {
172: // Try RHS
173: result = findSelector(cc.getRHS(), table);
174: }
175: }
176: return result;
177: }
178:
179: /**
180: * Optimizes two Selectors by creating an AndCondition or
181: * OrCondition at the proper level.
182: *
183: * @return true if the selectors were merged
184: */
185: public boolean merge(Selector other, Operator operator) {
186: if (other.getTable().equals(table)) {
187: Condition otherCond = other.condition;
188: if (otherCond == null)
189: return true;
190: Condition this Cond = condition;
191: if ((this Cond instanceof SimpleCondition)
192: && (otherCond instanceof SimpleCondition)) {
193: SimpleCondition this SC = (SimpleCondition) this Cond;
194: SimpleCondition otherSC = (SimpleCondition) otherCond;
195: if (this SC.getColumn().equals(otherSC.getColumn())
196: && this SC.getOperator().equals(
197: otherSC.getOperator())) {
198: Object this Val = this SC.getValue();
199: Object otherVal = otherSC.getValue();
200: if ((this Val instanceof Selector)
201: && (otherVal instanceof Selector)) {
202: Selector this Sel = (Selector) this Val;
203: Selector otherSel = (Selector) otherVal;
204: if (this Sel.getTable().equals(
205: otherSel.getTable())) {
206: return this Sel.merge(otherSel, operator);
207: }
208: }
209: }
210: }
211: // Merge at this point
212: if (operator.equals(Operator.ANDC)) {
213: condition = new AndCondition(this Cond, otherCond);
214: } else {
215: condition = new OrCondition(this Cond, otherCond);
216: }
217: return true;
218: } else {
219: // Don't merge
220: return false;
221: }
222: }
223: }
|