001: /*
002: * $Id: InsertIntoClause.java,v 1.19 2005/12/23 01:32:25 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: package org.axiondb.engine.commands;
041:
042: import java.util.ArrayList;
043: import java.util.Iterator;
044: import java.util.List;
045:
046: import org.axiondb.AxionException;
047: import org.axiondb.ColumnIdentifier;
048: import org.axiondb.DataType;
049: import org.axiondb.Database;
050: import org.axiondb.Row;
051: import org.axiondb.RowDecorator;
052: import org.axiondb.Selectable;
053: import org.axiondb.Table;
054: import org.axiondb.TableIdentifier;
055: import org.axiondb.engine.SnapshotIsolationTransaction;
056: import org.axiondb.engine.rows.SimpleRow;
057: import org.axiondb.engine.visitors.FindBindVariableVisitor;
058: import org.axiondb.jdbc.AxionResultSet;
059:
060: /**
061: * An <tt>INSERT INTO</tt> Clause.
062: *
063: * @author Ahimanikya Satapathy
064: * @author Ritesh Adval
065: */
066: public abstract class InsertIntoClause extends BaseAxionCommand {
067:
068: public InsertIntoClause(DMLWhenClause when, TableIdentifier tid,
069: List cols, List vals) {
070: _whenClause = when;
071: _tableId = tid;
072: _tables = new TableIdentifier[] { _tableId };
073: _cols = (null == cols ? new ArrayList() : cols);
074: _vals = (null == vals ? new ArrayList() : vals);
075: }
076:
077: public InsertIntoClause(DMLWhenClause when, TableIdentifier tid,
078: List cols, boolean useDefaultValues) {
079: this (when, tid, cols, null);
080: _useDefaultValues = useDefaultValues;
081: }
082:
083: public boolean execute(Database db) throws AxionException {
084: throw new UnsupportedOperationException("Not Implemented...");
085: }
086:
087: public AxionResultSet executeQuery(Database db)
088: throws AxionException {
089: throw new UnsupportedOperationException("Not Implemented...");
090: }
091:
092: public int executeUpdate(Database db) throws AxionException {
093: throw new UnsupportedOperationException("Not Implemented...");
094: }
095:
096: public final Iterator getColumnIterator() {
097: return _cols.iterator();
098: }
099:
100: public final int getProcessedRowCount() {
101: return _count;
102: }
103:
104: public TableIdentifier getTargetTableId() {
105: return _tableId;
106: }
107:
108: public final Iterator getValueIterator() {
109: return _vals.iterator();
110: }
111:
112: public boolean insertMatchingRow(Database db, RowDecorator dec,
113: Row srcRow) throws AxionException {
114: if (_whenClause != null) {
115: // if current row does not match when condition return
116: if (!_whenClause.evaluate(dec)) {
117: return false;
118: }
119: }
120:
121: if (_vals != null && !_vals.isEmpty()) {
122: addRowToTable(db, null, dec);
123: } else {
124: addRowToTable(db, srcRow, dec);
125: }
126:
127: _count++;
128: commitIfRequired(db);
129: return true;
130: }
131:
132: public void preProcess(Database db) throws AxionException {
133: _count = 0;
134: _table = db.getTable(_tableId);
135: if (null == _table) {
136: throw new AxionException("Table " + _tableId
137: + " not found.");
138: }
139: setDeferAllConstraintIfRequired(_table);
140: }
141:
142: protected void addRowToTable(Database db, Row srcRow,
143: RowDecorator dec) throws AxionException {
144:
145: Row row = new SimpleRow(_table.getColumnCount());
146: if (dec.getRow() == null) {
147: dec.setRow(row);
148: }
149:
150: int size = (srcRow != null ? srcRow.size() : _vals.size());
151: for (int i = 0; i < size; i++) {
152: setValue((srcRow != null ? srcRow.get(i) : _vals.get(i)),
153: dec, row, i);
154: }
155:
156: RowDecorator trgtDec = makeRowDecorator();
157: trgtDec.setRow(row);
158: populateDefaultValues(db, _table, _tableId, trgtDec);
159: if (_populateSequence) {
160: _populateSequence = populateSequenceColumns(db, _table, row);
161: }
162: _table.addRow(row);
163: }
164:
165: private void setValue(Object val, RowDecorator dec, Row row, int i)
166: throws AxionException {
167: ColumnIdentifier colid = (ColumnIdentifier) (_cols.get(i));
168: DataType type = colid.getDataType();
169:
170: // if we have a non-null selectable, evaluate it
171: if (val instanceof Selectable) {
172: val = ((Selectable) val).evaluate(dec);
173: }
174: val = attemptToConvertValue(val, type, colid);
175: row.set(_colIndex[i], val);
176: }
177:
178: // If values are not specified we need to assume that all the identifers in sub
179: // select needs to be inserted.
180: protected void assertRules(Table source) throws AxionException {
181: // Currently we don't support DEFAULT VALUES for multi table insert
182: // But one could tweak the grammar to support this,
183: // uncomment the following line in such case
184: // if(_useDefaultValues) {return;}
185:
186: // if no values clause specified
187: String errMsg = "Number of columns and values must match.";
188: if (_vals.isEmpty()) {
189: // number of selectables in subselect
190: // should be same as number of columns in target table
191: if (getColumnCount() != source.getColumnCount()) {
192: throw new IllegalArgumentException(errMsg);
193: }
194: } else {
195: // if columns are also specified then number of selectables in
196: // columns should be same as number of selectables in values clause
197: if (getColumnCount() != getValueCount()) {
198: throw new IllegalArgumentException(errMsg);
199: }
200: }
201: }
202:
203: protected void buildBindVariables() {
204: setBindVariableVisitor(new FindBindVariableVisitor());
205: getBindVariableVisitor().visit(this );
206: }
207:
208: protected final int getColumnCount() {
209: return _cols.size();
210: }
211:
212: protected final Table getTargetTable() {
213: return _table;
214: }
215:
216: protected final int getValueCount() {
217: return _vals.size();
218: }
219:
220: protected final List getValues() {
221: return _vals;
222: }
223:
224: public final DMLWhenClause getWhenClause() {
225: return _whenClause;
226: }
227:
228: protected boolean isTargetTablePartOfSubQuery()
229: throws AxionException {
230: return false;
231: }
232:
233: protected void resolve(Database db) throws AxionException {
234: resolveSelectableList(_cols, db, _tables);
235: resolveGeneratedColumns(_table, _tableId, _cols,
236: _useDefaultValues);
237:
238: if (_colIndex == null) {
239: _colIndex = new int[_cols.size()];
240: for (int i = 0, I = _cols.size(); i < I; i++) {
241: _colIndex[i] = _table
242: .getColumnIndex(((ColumnIdentifier) _cols
243: .get(i)).getName());
244: }
245: }
246: }
247:
248: private void commitIfRequired(Database db) throws AxionException {
249: if (getCommitSize(db) == 0 || isTargetTablePartOfSubQuery()) {
250: return;
251: }
252:
253: if (db instanceof SnapshotIsolationTransaction
254: && (_count % getCommitSize(db)) == 0) {
255: _table = ((SnapshotIsolationTransaction) db)
256: .commit(_tableId);
257: }
258: }
259:
260: protected final RowDecorator makeRowDecorator() {
261: if (_dec == null) {
262: _dec = _table.makeRowDecorator();
263: }
264: return _dec;
265: }
266:
267: private List _cols;
268: private transient int[] _colIndex;
269: private Table _table;
270: private RowDecorator _dec;
271: private List _vals;
272: private boolean _useDefaultValues = false;
273: private boolean _populateSequence = true;
274:
275: private int _count = 0;
276: private TableIdentifier _tableId;
277: private TableIdentifier[] _tables;
278:
279: private DMLWhenClause _whenClause;
280: }
|