001: /*
002: * $Id: BaseAxionCommand.java,v 1.37 2005/12/22 09:02:29 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2002-2006 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 java.sql.ResultSet;
044: import java.util.ArrayList;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.Set;
048:
049: import org.axiondb.AxionCommand;
050: import org.axiondb.AxionException;
051: import org.axiondb.BindVariable;
052: import org.axiondb.Column;
053: import org.axiondb.ColumnIdentifier;
054: import org.axiondb.DataType;
055: import org.axiondb.Database;
056: import org.axiondb.Function;
057: import org.axiondb.Row;
058: import org.axiondb.RowDecorator;
059: import org.axiondb.RowIterator;
060: import org.axiondb.Selectable;
061: import org.axiondb.Sequence;
062: import org.axiondb.Table;
063: import org.axiondb.TableIdentifier;
064: import org.axiondb.engine.rowiterators.FilteringRowIterator;
065: import org.axiondb.engine.visitors.FindBindVariableVisitor;
066: import org.axiondb.engine.visitors.ResolveSelectableVisitor;
067: import org.axiondb.functions.ConcreteFunction;
068: import org.axiondb.functions.FunctionIdentifier;
069: import org.axiondb.jdbc.AxionResultSet;
070:
071: /**
072: * Abstract base {@link AxionCommand}implementation.
073: *
074: * @version $Revision: 1.37 $ $Date: 2005/12/22 09:02:29 $
075: * @author Rodney Waldhoff
076: * @author Chuck Burdick
077: * @author Ahimanikya Satapathy
078: */
079: public abstract class BaseAxionCommand implements AxionCommand {
080:
081: /**
082: * Sets the <i>values </i> of all bind variable within this command.
083: *
084: * @param index the one-based index of the variable
085: * @param value the value to bind the variable to
086: */
087: public void bindAll(Object[] vals) throws AxionException {
088: int index = 0;
089: for (Iterator iter = getBindVariableIterator(); iter.hasNext(); index++) {
090: BindVariable var = (BindVariable) (iter.next());
091: var.setValue(vals[index]);
092: }
093: }
094:
095: /**
096: * Clears all bind variables within this command.
097: */
098: public void clearBindings() throws AxionException {
099: for (Iterator iter = getBindVariableIterator(); iter.hasNext();) {
100: BindVariable var = (BindVariable) (iter.next());
101: var.clearBoundValue();
102: }
103: }
104:
105: public AxionResultSet executeQuery(Database db, boolean isReadOnly)
106: throws AxionException {
107: return executeQuery(db);
108: }
109:
110: public List getBindVariables() {
111: if (getBindVariableVisitor() == null) {
112: buildBindVariables();
113: }
114: return getBindVariableVisitor().getBindVariables();
115: }
116:
117: public final int getEffectedRowCount() {
118: return _rowCount;
119: }
120:
121: public final ResultSet getResultSet() {
122: return _rset;
123: }
124:
125: /** Throws an {@link AxionException}if the given {@link Database}is read-only. */
126: protected void assertNotReadOnly(Database db) throws AxionException {
127: if (db.isReadOnly()) {
128: throw new AxionException("The database is read only.");
129: }
130: }
131:
132: protected Object attemptToConvertValue(Object val, DataType type,
133: ColumnIdentifier colid) throws AxionException {
134: try {
135: return type.convert(val);
136: } catch (AxionException e) {
137: throw new AxionException("Invalid value " + "\"" + val
138: + "\"" + " for column " + colid + ", expected "
139: + type + " : " + e.getMessage(), e.getVendorCode());
140: }
141: }
142:
143: protected void buildBindVariables() {
144: setBindVariableVisitor(new FindBindVariableVisitor());
145: }
146:
147: protected final void createResolveSelectableVisitor(Database db) {
148: if (_resolveSel == null) {
149: _resolveSel = new ResolveSelectableVisitor(db);
150: }
151: }
152:
153: /**
154: * Returns an {@link Iterator}over all my {@link BindVariable}s, in the proper
155: * order. Default impl returns empty iterator.
156: */
157: protected Iterator getBindVariableIterator() {
158: if (getBindVariableVisitor() == null) {
159: buildBindVariables();
160: }
161: return getBindVariableVisitor().getBindVariableIterator();
162: }
163:
164: protected Iterator getBindVariableIterator(Selectable sel) {
165: if (getBindVariableVisitor() == null) {
166: setBindVariableVisitor(new FindBindVariableVisitor());
167: getBindVariableVisitor().visit(sel);
168: }
169: return _bvisitor.getBindVariableIterator();
170: }
171:
172: protected final FindBindVariableVisitor getBindVariableVisitor() {
173: return _bvisitor;
174: }
175:
176: protected List getColIdentifierList(Table table, TableIdentifier tid)
177: throws AxionException {
178: int size = table.getColumnCount();
179: List colids = new ArrayList(size);
180: for (int i = 0; i < size; i++) {
181: Column col = table.getColumn(i);
182: colids.add(new ColumnIdentifier(tid, col.getName(), null,
183: col.getDataType()));
184: }
185: return colids;
186: }
187:
188: protected int getCommitSize(Database db) {
189: if (_commitSize == -1) {
190: int commitSize = 0;
191: try {
192: String size = (String) db
193: .getGlobalVariable(Database.COMMIT_SIZE);
194: commitSize = Integer.parseInt(size);
195: commitSize = Math.abs(commitSize);
196: } catch (Throwable e) {
197: }
198: _commitSize = commitSize;
199: }
200: return _commitSize;
201: }
202:
203: protected RowIterator getRowIterator(Database db,
204: TableIdentifier tid, Table table, Selectable whereNode,
205: boolean readOnly, RowDecorator dec) throws AxionException {
206: RowIterator rows = null;
207: Set whereNodes = AxionQueryOptimizer
208: .flatConditionTree(whereNode);
209: Selectable searchNode = AxionQueryOptimizer
210: .findColumnLiteralFunction(tid, table, whereNodes, true);
211:
212: // look for an index
213: if (searchNode != null) {
214: rows = table.getIndexedRows(searchNode, readOnly);
215: if (rows != null) {
216: whereNodes.remove(searchNode);
217: }
218: }
219:
220: if (rows == null) {
221: rows = table.getRowIterator(readOnly);
222: }
223:
224: if (!whereNodes.isEmpty()) {
225: rows = new FilteringRowIterator(rows, dec, whereNode);
226: }
227: return rows;
228: }
229:
230: protected final RowDecorator makeRowDecorator(Table table) {
231: return table.makeRowDecorator();
232: }
233:
234: protected void populateDefaultValues(Database db, Table table,
235: TableIdentifier tableId, RowDecorator dec)
236: throws AxionException {
237: createResolveSelectableVisitor(db);
238: Row row = dec.getRow();
239: for (int i = 0, I = row.size(); i < I; i++) {
240: Column col = table.getColumn(i);
241: if (null == row.get(i) || col.isDerivedColumn()) {
242: if (col.hasDefault()) {
243: Selectable sel = getCanonicalDefault(db, col
244: .getDefault());
245: sel = _resolveSel.visit(sel, null,
246: new TableIdentifier[] { tableId });
247: Object val = sel.evaluate(dec);
248:
249: DataType type = col.isDerivedColumn() ? sel
250: .getDataType() : col.getDataType();
251: val = attemptToConvertValue(val, type, null);
252: row.set(i, val);
253: } else if (col.isIdentityColumn()
254: && col.isGeneratedByDefault()) {
255: Sequence seq = table.getSequence();
256: row.set(i, seq.evaluate());
257: }
258: }
259: }
260: }
261:
262: protected boolean populateSequenceColumns(Database db, Table table,
263: Row row) throws AxionException {
264: boolean result = false;
265: createResolveSelectableVisitor(db);
266: for (int i = 0, size = row.size(); i < size; i++) {
267: Column col = table.getColumn(i);
268: if (col.isGeneratedAlways() && col.isIdentityColumn()) {
269: Sequence seq = table.getSequence();
270: row.set(i, seq.evaluate());
271: result = true;
272: }
273: }
274: return result;
275: }
276:
277: protected void resolveGeneratedColumns(Table table,
278: TableIdentifier tableId, List cols) throws AxionException {
279: resolveGeneratedColumns(table, tableId, cols, false);
280: }
281:
282: protected void resolveGeneratedColumns(Table table,
283: TableIdentifier tableId, List cols, boolean useDefaultValues)
284: throws AxionException {
285: boolean buildColList = cols.isEmpty();
286: for (int i = 0, count = table.getColumnCount(); i < count; i++) {
287: Column col = table.getColumn(i);
288: ColumnIdentifier colid = new ColumnIdentifier(tableId, col
289: .getName(), null, col.getDataType());
290: if (col.isGeneratedAlways() || col.isDerivedColumn()) {
291: if (cols.contains(colid) && !useDefaultValues) {
292: String msg = "Can't insert value to generated/derived column "
293: + col.getName();
294: throw new AxionException(msg);
295: }
296: } else if (buildColList) {
297: cols.add(colid);
298: }
299: }
300: }
301:
302: protected Selectable resolveSelectable(Selectable sel, Database db,
303: List selected, TableIdentifier[] tables)
304: throws AxionException {
305: createResolveSelectableVisitor(db);
306: return _resolveSel.visit(sel, selected, tables);
307: }
308:
309: protected Selectable resolveSelectable(Selectable sel, Database db,
310: TableIdentifier[] tables) throws AxionException {
311: createResolveSelectableVisitor(db);
312: return _resolveSel.visit(sel, null, tables);
313: }
314:
315: protected void resolveSelectableList(List list, Database db,
316: TableIdentifier table) throws AxionException {
317: resolveSelectableList(list, db, new TableIdentifier[] { table });
318: }
319:
320: protected void resolveSelectableList(List list, Database db,
321: TableIdentifier[] tables) throws AxionException {
322: createResolveSelectableVisitor(db);
323: for (int i = 0, I = list.size(); i < I; i++) {
324: list.set(i, _resolveSel.visit((Selectable) list.get(i),
325: null, tables));
326: }
327: }
328:
329: protected final void setBindVariableVisitor(
330: FindBindVariableVisitor visitor) {
331: _bvisitor = visitor;
332: }
333:
334: protected void setDeferAllConstraintIfRequired(Table table) {
335: if (getBindVariables().size() > 0) {
336: table.setDeferAllConstraints(true);
337: }
338: }
339:
340: /**
341: * If sublasses return a number of rows effected, then upon execution, they should set
342: * that number here so it can support {@link #execute}
343: */
344: protected final void setEffectedRowCount(int count) {
345: _rowCount = count;
346: }
347:
348: /**
349: * If subclasses create a {@link org.axiondb.jdbc.AxionResultSet}upon execution, they
350: * should set it here so that they can support {@link #execute}.
351: *
352: * @see #getResultSet
353: */
354: protected final void setResultSet(ResultSet rset) {
355: _rset = rset;
356: }
357:
358: protected void updateGeneratedValues(Database db, Table table,
359: TableIdentifier tableId, Row row) throws AxionException {
360: RowDecorator dec = null;
361: createResolveSelectableVisitor(db);
362: for (int i = 0, size = row.size(); i < size; i++) {
363: Column col = table.getColumn(i);
364: if (col.isDerivedColumn()) {
365: Selectable sel = getCanonicalDefault(db, col
366: .getDefault());
367: sel = _resolveSel.visit(sel, null,
368: new TableIdentifier[] { tableId });
369: if (dec == null) {
370: dec = makeRowDecorator(table);
371: dec.setRow(row);
372: }
373: Object val = sel.evaluate(dec);
374: val = attemptToConvertValue(val, col.getDataType(),
375: null);
376: row.set(i, val);
377: }
378: }
379: }
380:
381: private Selectable getCanonicalDefault(Database db, Selectable sel) {
382: if (sel instanceof ColumnIdentifier) {
383: ColumnIdentifier col = (ColumnIdentifier) sel;
384: if (!(col.getTableName() != null && db.getSequence(col
385: .getTableName()) != null)) {
386: return new ColumnIdentifier(sel.getName());
387: }
388: } else if (sel instanceof ConcreteFunction
389: || sel instanceof FunctionIdentifier) {
390: Function fn = (Function) sel;
391: FunctionIdentifier fnid = new FunctionIdentifier(fn
392: .getName());
393: for (int i = 0, I = fn.getArgumentCount(); i < I; i++) {
394: fnid.addArgument(getCanonicalDefault(db, fn
395: .getArgument(i)));
396: }
397: return fnid;
398: }
399: return sel;
400: }
401:
402: private FindBindVariableVisitor _bvisitor;
403: private int _commitSize = -1;
404: private ResolveSelectableVisitor _resolveSel;
405: private int _rowCount = -1;
406: private ResultSet _rset;
407: }
|