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.io.Externalizable;
042: import java.io.IOException;
043: import java.io.ObjectInput;
044: import java.io.ObjectOutput;
045:
046: import java.util.Hashtable;
047: import java.util.Vector;
048:
049: import java.sql.ResultSetMetaData;
050: import java.sql.SQLException;
051:
052: import com.quadcap.sql.index.Btree;
053:
054: import com.quadcap.sql.types.Value;
055: import com.quadcap.sql.types.ValueBoolean;
056:
057: import com.quadcap.util.Debug;
058:
059: /**
060: * A SQL <b>VIEW</b>.
061: *
062: * @author Stan Bailes
063: */
064: public class View extends TupleImpl implements Relation, Externalizable {
065: Vector viewColumns;
066: TableExpression select;
067:
068: static final int NOCHECK = -1;
069: static final int CASCADED = 0;
070: static final int LOCAL = 1;
071:
072: int check;
073:
074: /**
075: * Default constructor
076: */
077: public View() {
078: }
079:
080: /**
081: * Explicit constructor from name, columns, select expression,
082: * VIEW CHECK state
083: */
084: public View(String name, Vector columns, TableExpression select,
085: int check) {
086: super (name);
087: this .viewColumns = columns;
088: this .select = select;
089: this .check = check;
090: }
091:
092: /**
093: * Lazy build the view's columns list
094: */
095: public void addColumns(Session session) throws SQLException {
096: if (columns.size() == 0) {
097: Cursor c = getCursor(session, null, null, null);
098: try {
099: addColumns(session, c);
100: } finally {
101: c.close();
102: }
103: }
104: }
105:
106: /**
107: * Check a base row to see if it's contained in the view
108: */
109: public void checkRow(Session session, Cursor cursor, Row row)
110: throws SQLException {
111: if ((check != NOCHECK || session.getViewCheck())
112: && select.isUpdatable()) {
113: session.setViewCheck();
114: StaticCursor s = new StaticCursor(session, this , row);
115: s.next();
116: Expression w = select.getWhere();
117: if (w != null) {
118: Value v = w.getValue(session, s);
119: if (v instanceof ValueBoolean
120: && ((ValueBoolean) v).isTrue()) {
121: // ok
122: } else {
123: throw new SQLException(
124: "View check option violation", "44000");
125: }
126: }
127: }
128: }
129:
130: /**
131: * Externalizable.readExternal(): Read me from a stream.
132: */
133: public void readExternal(ObjectInput in) throws IOException,
134: ClassNotFoundException {
135: super .readExternal(in);
136: this .viewColumns = (Vector) in.readObject();
137: this .select = (TableExpression) in.readObject();
138: this .check = in.readInt();
139: }
140:
141: /**
142: * Externalizable.writeExternal(): Write me to a stream.
143: */
144: public void writeExternal(ObjectOutput out) throws IOException {
145: super .writeExternal(out);
146: out.writeObject(viewColumns);
147: out.writeObject(select);
148: out.writeInt(check);
149: }
150:
151: /**
152: * Get the view's cursor
153: */
154: public Cursor getCursor(Session session, Expression where,
155: String asName, Cursor cursor) throws SQLException {
156: Cursor c = select.getCursor(session, cursor);
157:
158: String qualName = asName;
159: if (qualName == null)
160: qualName = getName();
161: String qPrefix = qualName;
162: if (qPrefix.length() > 0)
163: qPrefix = qPrefix + ".";
164:
165: Vector cols = viewColumns;
166: if (cols == null) {
167: cols = new Vector();
168: Hashtable t = new Hashtable();
169: for (int i = 1; i <= c.getColumnCount(); i++) {
170: String name = c.getColumn(i).getName();
171: int idx = name.lastIndexOf('.');
172: if (idx >= 0)
173: name = name.substring(idx + 1);
174: name = qPrefix + name;
175: if (t.get(name) != null) {
176: throw new SQLException(
177: "A view column list must be specified if multiple "
178: + "columns have the same name: "
179: + name, "42000");
180: }
181: cols.addElement(name);
182: t.put(name, name);
183: }
184: } else {
185: cols = new Vector();
186: for (int i = 0; i < viewColumns.size(); i++) {
187: cols.addElement(qPrefix
188: + viewColumns.elementAt(i).toString());
189: }
190: }
191: c = new ViewCursor(session, this , c, cols);
192: return c;
193: }
194:
195: public void insertRow(Session session, Row row)
196: throws SQLException, IOException {
197: Cursor c = getCursor(session, null, null, null);
198: try {
199: session.clearViewCheck();
200: c.insertRow(row);
201: } finally {
202: c.close();
203: }
204: }
205:
206: public boolean isUpdatable() {
207: return select.isUpdatable();
208: }
209:
210: public boolean hasBlobs() {
211: return false; // XXX test insert into view with blobs.
212: }
213:
214: public Vector getBaseTables() {
215: Vector v = new Vector();
216: select.getBaseTables(v);
217: return v;
218: }
219:
220: public Expression getViewExpression() {
221: return select;
222: }
223:
224: public String getType() {
225: return "VIEW";
226: }
227:
228: public void delete(Session session) {
229: }
230:
231: public String toString() {
232: StringBuffer sb = new StringBuffer("VIEW ");
233: sb.append(getName());
234: if (columns != null) {
235: sb.append('(');
236: for (int i = 0; i < columns.size(); i++) {
237: if (i > 0)
238: sb.append(',');
239: Column col = (Column) columns.get(i);
240: sb.append(col.getShortName());
241: }
242: sb.append(')');
243: }
244: sb.append(" AS ");
245: sb.append(select.toString());
246: return sb.toString();
247: }
248:
249: }
|