001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.db.sql;
031:
032: import com.caucho.db.Database;
033: import com.caucho.db.store.Transaction;
034: import com.caucho.db.table.TableIterator;
035: import com.caucho.log.Log;
036: import com.caucho.sql.SQLExceptionWrapper;
037: import com.caucho.util.CharBuffer;
038:
039: import java.io.IOException;
040: import java.sql.SQLException;
041: import java.util.Iterator;
042: import java.util.logging.Logger;
043:
044: public class SelectQuery extends Query {
045: private static final Logger log = Log.open(SelectQuery.class);
046:
047: private Expr[] _results;
048: private String[] _resultNames;
049:
050: private boolean[] _groupFields;
051:
052: private Order _order;
053: private int _limit = Integer.MAX_VALUE / 2;
054:
055: SelectQuery(Database db, String sql) throws SQLException {
056: super (db, sql);
057: }
058:
059: SelectQuery(Database db, String sql, FromItem[] fromItems)
060: throws SQLException {
061: super (db, sql, fromItems);
062: }
063:
064: void setResults(Expr[] resultExprs) throws SQLException {
065: _results = new Expr[resultExprs.length];
066:
067: for (int i = 0; i < resultExprs.length; i++) {
068: _results[i] = resultExprs[i];
069: }
070:
071: setDataFields(resultExprs.length);
072: }
073:
074: Expr[] getResults() {
075: return _results;
076: }
077:
078: /**
079: * Sets the result item as group.
080: */
081: public void setGroupResult(int index) {
082: if (_groupFields == null)
083: _groupFields = new boolean[_results.length];
084:
085: _groupFields[index] = true;
086: }
087:
088: protected void bind() throws SQLException {
089: super .bind();
090:
091: for (int i = 0; i < _results.length; i++) {
092: _results[i] = _results[i].bind(this );
093: }
094:
095: if (isGroup()) {
096: for (int i = 0; i < _results.length; i++) {
097: if (isGroup() && !(_results[i] instanceof GroupExpr))
098: _results[i] = new GroupResultExpr(i, _results[i]);
099: }
100: }
101:
102: for (int i = 0; i < _results.length; i++) {
103: _results[i] = _results[i].bind(this );
104: }
105:
106: _resultNames = new String[_results.length];
107:
108: for (int i = 0; i < _resultNames.length; i++)
109: _resultNames[i] = _results[i].getName();
110: }
111:
112: void setOrder(Order order) {
113: _order = order;
114: }
115:
116: @Override
117: public void setLimit(int limit) {
118: _limit = limit;
119: }
120:
121: /**
122: * Returns true for select queries.
123: */
124: public boolean isSelect() {
125: return true;
126: }
127:
128: /**
129: * Returns the type of the child.
130: */
131: Class getType() {
132: if (_results.length == 1)
133: return _results[0].getType();
134: else
135: return Object.class;
136: }
137:
138: /**
139: * Executes the query.
140: */
141: public void execute(QueryContext context, Transaction xa)
142: throws SQLException {
143: SelectResult result = SelectResult.create(_results, _order);
144: FromItem[] fromItems = getFromItems();
145: TableIterator[] rows = null;
146:
147: try {
148: rows = result.initRows(fromItems);
149: context.init(xa, rows, isReadOnly());
150:
151: if (isGroup())
152: executeGroup(result, rows, context, xa);
153: else
154: execute(result, rows, context, xa);
155:
156: result.initRead();
157:
158: context.setResult(result);
159: } catch (IOException e) {
160: throw new SQLExceptionWrapper(e);
161: } finally {
162: // autoCommitRead must be before freeRows in case freeRows
163: // throws an exception
164: context.unlock();
165:
166: if (rows != null)
167: freeRows(rows, rows.length);
168: }
169: }
170:
171: /**
172: * Executes the query.
173: */
174: private void execute(SelectResult result, TableIterator[] rows,
175: QueryContext context, Transaction xa) throws SQLException,
176: IOException {
177: FromItem[] fromItems = getFromItems();
178: int rowLength = fromItems.length;
179:
180: int limit = _limit;
181: int contextLimit = context.getLimit();
182: if (contextLimit > 0)
183: limit = contextLimit;
184:
185: if (start(rows, rowLength, context, xa)) {
186: do {
187: result.startRow();
188: for (int i = 0; i < _results.length; i++) {
189: _results[i].evalToResult(context, result);
190: }
191: } while (nextTuple(rows, rowLength, context, xa)
192: && --_limit > 0);
193: }
194: }
195:
196: private void executeGroup(SelectResult result,
197: TableIterator[] rows, QueryContext context,
198: Transaction transaction) throws SQLException, IOException {
199: FromItem[] fromItems = getFromItems();
200: int rowLength = fromItems.length;
201:
202: Expr[] results = _results;
203: int resultsLength = results.length;
204:
205: /*
206: for (int i = 0; i < results.length; i++)
207: results[i].initGroup(context);
208: */
209:
210: if (_groupFields == null)
211: _groupFields = new boolean[0];
212:
213: boolean[] groupByFields = _groupFields;
214: int groupByLength = _groupFields.length;
215:
216: if (start(rows, rowLength, context, transaction)) {
217: do {
218: context.initGroup(getDataFields(), _groupFields);
219:
220: for (int i = 0; i < groupByLength; i++) {
221: if (groupByFields[i])
222: results[i].evalGroup(context);
223: }
224:
225: context.selectGroup();
226:
227: for (int i = 0; i < resultsLength; i++) {
228: if (!(i < groupByLength && groupByFields[i]))
229: results[i].evalGroup(context);
230: }
231: } while (nextTuple(rows, rowLength, context, transaction));
232: }
233:
234: Iterator<GroupItem> groupIter = context.groupResults();
235:
236: while (groupIter.hasNext()) {
237: GroupItem item = groupIter.next();
238:
239: context.setGroupItem(item);
240:
241: result.startRow();
242: for (int i = 0; i < results.length; i++) {
243: results[i].evalToResult(context, result);
244: }
245: }
246: }
247:
248: public String toString() {
249: CharBuffer cb = CharBuffer.allocate();
250: cb.append("SelectQuery[");
251: cb.append("SELECT ");
252: for (int i = 0; i < _results.length; i++) {
253: if (i != 0)
254: cb.append(",");
255: cb.append(_results[i]);
256: }
257: cb.append(" FROM ");
258:
259: FromItem[] fromItems = getFromItems();
260: for (int i = 0; i < fromItems.length; i++) {
261: if (i != 0)
262: cb.append(",");
263: cb.append(fromItems[i]);
264: }
265:
266: if (_whereExpr != null) {
267: cb.append(" WHERE " + _whereExpr);
268: }
269: cb.append("]");
270:
271: return cb.close();
272: }
273: }
|