001: /*
002: * $Id: SubSelectCommand.java,v 1.14 2005/12/20 18:32:28 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2002-2005 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040:
041: package org.axiondb.engine.commands;
042:
043: import org.axiondb.AxionException;
044: import org.axiondb.DataType;
045: import org.axiondb.Database;
046: import org.axiondb.OrderNode;
047: import org.axiondb.Row;
048: import org.axiondb.RowDecorator;
049: import org.axiondb.RowIterator;
050: import org.axiondb.Selectable;
051: import org.axiondb.Table;
052: import org.axiondb.TableIdentifier;
053: import org.axiondb.VariableContext;
054: import org.axiondb.engine.tables.TableView;
055: import org.axiondb.jdbc.AxionResultSet;
056: import org.axiondb.types.AnyType;
057:
058: /**
059: * A Sub <tt>SELECT</tt> query used for view, scalar value, from node, row list
060: *
061: * @version $Revision: 1.14 $ $Date: 2005/12/20 18:32:28 $
062: * @author Ahimanikya Satapathy
063: */
064: public class SubSelectCommand extends SelectCommand implements
065: Selectable {
066:
067: public SubSelectCommand(AxionQueryContext context) {
068: super (context);
069: }
070:
071: public Object evaluate(RowDecorator row) throws AxionException {
072: // If this is a scalar select then we might have parent row
073: // that this select should have access to.
074: if (_evaluteAsScalarValue) {
075: RowIterator rowIter = getRowIterator(_dbForSubSelect, row);
076:
077: Object rval = null;
078: if (rowIter.hasNext()) {
079: Row rrow = rowIter.next();
080: if (rowIter.hasNext()) {
081: throw new AxionException(
082: "single-row subquery returns more than one row");
083: }
084: if (rrow.size() > 1) {
085: throw new AxionException("too many values");
086: }
087: rval = rrow.get(0);
088: }
089: return rval;
090: }
091:
092: return getRowIterator(_dbForSubSelect, row);
093: }
094:
095: public boolean execute(Database database) throws AxionException {
096: throw new UnsupportedOperationException(
097: "Can't execute the sub-query directly");
098: }
099:
100: public AxionResultSet executeQuery(Database db)
101: throws AxionException {
102: throw new UnsupportedOperationException(
103: "Can't execute the sub-query directly");
104: }
105:
106: public int executeUpdate(Database database) throws AxionException {
107: throw new UnsupportedOperationException(
108: "Can't execute the sub-query directly");
109: }
110:
111: public String getAlias() {
112: return _context.getAliasName();
113: }
114:
115: public DataType getDataType() {
116: return AnyType.INSTANCE;
117: }
118:
119: public String getLabel() {
120: return getName();
121: }
122:
123: public String getName() {
124: return _context.getAliasName() != null ? _context
125: .getAliasName() : "SELECT";
126: }
127:
128: /**
129: * Return RowIterator that can used for other commands for sub-query.
130: *
131: * @return the {@link org.axiondb.RowIterator}.
132: * @throws AxionException
133: */
134: public RowIterator getRowIterator(Database db)
135: throws AxionException {
136: return getTableView(db, null).getRowIterator(true);
137: }
138:
139: public RowIterator getRowIterator(Database db, RowDecorator rowDec)
140: throws AxionException {
141: _context.setParentRow(rowDec);
142: return getTableView(db, null).getRowIterator(true);
143: }
144:
145: /**
146: * Return TableView a table wrapper to hold sub-query RowIterator.
147: *
148: * @return the {@link org.axiondb.engine.tables.TableView}.
149: * @throws AxionException
150: */
151: public Table getTableView(Database db, String name)
152: throws AxionException {
153: if (_view == null) {
154: _view = new TableView(db, name, this );
155: }
156: return _view;
157: }
158:
159: /**
160: * Return TableView a table wrapper to hold sub-query RowIterator.
161: *
162: * @return the {@link org.axiondb.engine.tables.TableView}.
163: * @throws AxionException
164: */
165: public Table getTableView(Database db, String name, boolean addToDb)
166: throws AxionException {
167: if (_view == null) {
168: _view = new TableView(db, name, this );
169: }
170:
171: if (addToDb && !db.hasTable(_view.getName())) {
172: db.addTable(_view);
173: }
174:
175: return _view;
176: }
177:
178: public boolean isScalarSelect() {
179: return _evaluteAsScalarValue;
180: }
181:
182: public boolean isCorrelated() {
183: return _foundCorrelatedColumnReference;
184: }
185:
186: public RowIterator makeRowIterator(Database db, boolean readOnly)
187: throws AxionException {
188: if (_context.getRows() == null
189: || _currentDatabase != db
190: || (_context.getGroupByCount() > 0)
191: || (_evaluteAsScalarValue && _context
192: .isCorrelatedSubQuery())) {
193: super .makeRowIterator(db, readOnly, true);
194: } else {
195: _context.getRows().reset();
196: }
197: return _context.getRows();
198: }
199:
200: public void setAlias(String aliasName) {
201: _context.setAliasName(aliasName);
202: }
203:
204: // This is needed in order to get this Selectable to be evaluated..
205: public void setDB(Database db) {
206: _dbForSubSelect = db;
207: }
208:
209: public void setEvaluteAsScalarValue() {
210: _evaluteAsScalarValue = true;
211: }
212:
213: public void setParentTables(TableIdentifier[] tables) {
214: _context.setParentTables(tables);
215: }
216:
217: public void setVariableContext(VariableContext context) {
218: }
219:
220: protected void buildTableList(Database db) throws AxionException {
221: TableIdentifier[] t = _context.getFromArray();
222: findCorrelatedColumnReference(db, t);
223: _context.setCorrelatedSubQuery(isCorrelated());
224:
225: // scan the query to find outer table reference.
226: if (isCorrelated()) {
227: TableIdentifier[] pt = _context.getParentTables();
228: int tableLen = t.length;
229: tableLen += pt.length;
230:
231: TableIdentifier[] tables = new TableIdentifier[tableLen];
232: int pos = 0;
233:
234: for (int i = 0; t != null && i < t.length; i++) {
235: tables[pos++] = t[i];
236: }
237:
238: for (int i = 0; pt != null && i < pt.length; i++) {
239: tables[pos++] = pt[i];
240: }
241: _context.setTables(tables);
242: } else {
243: _context.setParentTables(null);
244: _context.setParentRow(null);
245: _context.setTables(t);
246: }
247: }
248:
249: private boolean findCorrelatedColumnReference(Database db,
250: TableIdentifier[] t) throws AxionException {
251: // this is a lazy guess, 2nd pass may find more unresolved column
252: _foundCorrelatedColumnReference = false;
253: try {
254: if (_context.getWhere() != null) {
255: resolveSelectable(_context.getWhere(), db, t);
256: }
257:
258: if (null != _context.getGroupBy()) {
259: for (int i = 0, I = _context.getGroupByCount(); i < I; i++) {
260: resolveSelectable(_context.getGroupBy(i), db, t);
261: }
262: }
263: resolveSelectable(_context.getHaving(), db, t);
264: if (null != _context.getOrderBy()) {
265: for (int i = 0, I = _context.getOrderByCount(); i < I; i++) {
266: OrderNode ob = _context.getOrderBy(i);
267: resolveSelectable(ob.getSelectable(), db, t);
268: }
269: }
270:
271: } catch (AxionException e) {
272: _foundCorrelatedColumnReference = true;
273: }
274: return _foundCorrelatedColumnReference;
275: }
276:
277: // ----------------------------------------------------------------- Members
278:
279: private Database _dbForSubSelect;
280: private boolean _evaluteAsScalarValue = false;
281: private boolean _foundCorrelatedColumnReference = false;
282: private transient volatile TableView _view;
283: }
|