001: package com.quadcap.sql;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.util.Vector;
042:
043: import java.io.IOException;
044:
045: import java.sql.SQLException;
046:
047: import com.quadcap.sql.types.Value;
048: import com.quadcap.sql.types.ValueDefault;
049: import com.quadcap.sql.types.ValueNull;
050:
051: /**
052: * Implementation of the SQL <b>INSERT</b> statement.
053: *
054: * @author Stan Bailes
055: */
056:
057: public class StmtInsert implements Stmt {
058: String tableName;
059: Vector columns;
060: Expression values;
061:
062: boolean defaultValues = false;
063: VectorExpression ve = null;
064: Row tempRow = null;
065:
066: Relation table = null;
067:
068: public StmtInsert() {
069: }
070:
071: public StmtInsert(String tableName) {
072: this .tableName = tableName;
073: }
074:
075: public void setDefaultValue() {
076: this .defaultValues = true;
077: }
078:
079: public void setColumns(Vector v) {
080: this .columns = v;
081: }
082:
083: public void setValues(Expression e) {
084: this .values = e;
085: }
086:
087: final Value getDefault(Session session, Cursor cursor, Column c)
088: throws SQLException {
089: Value dflt = ValueNull.valueNull;
090: Expression e = c.getDefault();
091: if (e != null) {
092: dflt = e.getValue(session, cursor);
093: }
094: return dflt;
095: }
096:
097: public void setVrow(Session session, VectorExpression ve)
098: throws IOException, SQLException {
099: if (ve.size() != tempRow.size()) {
100: throw new SQLException("Incorrect number of columns: "
101: + ve.size() + "; expecting " + tempRow.size());
102: }
103: for (int col = 1; col <= tempRow.size(); col++) {
104: Value v = ve.get(col - 1).getValue(session, null);
105: if (v instanceof ValueDefault) {
106: Column c = table.getColumn(col);
107: v = getDefault(session, null, c);
108: }
109: tempRow.set(col, v);
110: }
111: table.insertRow(session, tempRow);
112: }
113:
114: public void execute(Session session) throws IOException,
115: SQLException {
116: Database db = session.getDatabase();
117: if (table == null) {
118: table = db.getRelation(tableName);
119: if (table == null) {
120: throw new SQLException("No table: " + tableName,
121: "42000");
122: }
123: }
124: if (columns == null) {
125: if (ve != null || values instanceof VectorExpression) {
126: // we can do something optimal here....
127: if (ve == null)
128: ve = (VectorExpression) values;
129: if (tempRow == null)
130: tempRow = new Row(table.getColumnCount());
131: if (ve.rank() == 1) {
132: setVrow(session, ve);
133: return;
134: } else if (ve.rank() == 2) {
135: for (int row = 0; row < ve.size(); row++) {
136: VectorExpression vr = (VectorExpression) ve
137: .get(row);
138: setVrow(session, vr);
139: }
140: return;
141: }
142: }
143: }
144:
145: // less-than-optimal but full-featured insert implementation
146: Cursor cursor = null;
147: if (values != null) {
148: cursor = values.getCursor(session, null);
149: }
150:
151: if (isSelfInsert()) {
152: DistinctCursor dc = new DistinctCursor(session, cursor);
153: dc.setDistinct(false);
154: cursor = dc;
155: }
156: try {
157: if (defaultValues) {
158: if (tempRow == null)
159: tempRow = new Row(table.getColumnCount());
160: for (int col = 1; col <= tempRow.size(); col++) {
161: Column c = table.getColumn(col);
162: Value dflt = getDefault(session, cursor, c);
163: tempRow.set(col, dflt);
164: }
165: table.insertRow(session, tempRow);
166: } else if (columns == null) {
167: if (cursor.getColumnCount() != table.getColumnCount()) {
168: throw new SQLException(
169: "Incorrect number of columns: "
170: + cursor.getColumnCount()
171: + "; expecting "
172: + table.getColumnCount());
173: }
174: if (cursor instanceof StaticCursor) {
175: // XXX is this right? Can defaults show up in other
176: // XXX cursor types?
177: while (cursor.next()) {
178: Row r = cursor.getRow();
179: for (int i = 1; i <= r.size(); i++) {
180: Value v = r.item(i);
181: if (v instanceof ValueDefault) {
182: Column c = table.getColumn(i);
183: v = getDefault(session, cursor, c);
184: r.set(i, v);
185: }
186: }
187: table.insertRow(session, r);
188: }
189: } else if (table.hasBlobs()) {
190: // We may have to passivate the blobs, but it's possible
191: // that the rows that we get back aren't updateable
192: // (e.g., insert into TAB select from TAB2, TAB3)
193: if (tempRow == null) {
194: tempRow = new Row(table.getColumnCount());
195: }
196: while (cursor.next()) {
197: Row r = cursor.getRow();
198: for (int i = 1; i <= table.getColumnCount(); i++) {
199: tempRow.set(i, r.item(i));
200: }
201: table.insertRow(session, tempRow);
202: }
203: } else {
204: while (cursor.next()) {
205: Row r = cursor.getRow();
206: table.insertRow(session, r);
207: }
208: }
209: } else {
210: if (tempRow == null) {
211: tempRow = new Row(table.getColumnCount());
212: }
213: int[] map = table.mapColumns(columns);
214: int[] nmap = null;
215: // make a map to quickly find columns that need defaults
216: if (map.length < table.getColumnCount()) {
217: int[] cmap = new int[table.getColumnCount()];
218: for (int i = 0; i < map.length; i++) {
219: cmap[map[i] - 1] = 1;
220: }
221: nmap = new int[cmap.length - map.length];
222: int ncnt = 0;
223: for (int i = 0; i < cmap.length; i++) {
224: if (cmap[i] == 0) {
225: nmap[ncnt++] = i + 1;
226: }
227: }
228: }
229: while (cursor.next()) {
230: Row row = cursor.getRow();
231: for (int i = 0; i < map.length; i++) {
232: Value v = row.item(i + 1);
233: if (v instanceof ValueDefault) {
234: Column c = table.getColumn(map[i]);
235: v = getDefault(session, cursor, c);
236: }
237: tempRow.set(map[i], v);
238: }
239: if (nmap != null) {
240: // fill in null/default values
241: for (int i = 0; i < nmap.length; i++) {
242: int col = nmap[i];
243: Column c = table.getColumn(col);
244: Value dflt = getDefault(session, cursor, c);
245: tempRow.set(col, dflt);
246: }
247: }
248: table.insertRow(session, tempRow);
249: }
250: }
251: } finally {
252: if (cursor != null)
253: cursor.close();
254: }
255: }
256:
257: class IsSelfInsert implements ExpressionVisitor {
258: boolean isit = false;
259:
260: public void visit(Expression sub) {
261: if (!isit) {
262: if (sub instanceof SelectExpression) {
263: Vector v = new Vector();
264: SelectExpression se = (SelectExpression) sub;
265: se.getBaseTables(v);
266: for (int i = 0; !isit && i < v.size(); i++) {
267: String name = v.get(i).toString();
268: isit = name.equalsIgnoreCase(tableName);
269: }
270: } else {
271: sub.visitSubExpressions(this );
272: }
273: }
274: }
275: }
276:
277: boolean isSelfInsert() {
278: boolean ret = false;
279: if (values != null) {
280: IsSelfInsert is = new IsSelfInsert();
281: is.visit(values);
282: ret = is.isit;
283: }
284: return ret;
285: }
286: }
|