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.IOException;
042:
043: import java.util.Vector;
044:
045: import java.sql.SQLException;
046:
047: import com.quadcap.sql.file.BlockFile;
048: import com.quadcap.sql.file.ByteUtil;
049:
050: import com.quadcap.sql.index.Btree;
051: import com.quadcap.sql.index.BCursor;
052:
053: import com.quadcap.sql.types.Value;
054: import com.quadcap.sql.types.ValueLong;
055: import com.quadcap.sql.types.ValueNull;
056:
057: import com.quadcap.util.Debug;
058:
059: /**
060: * Implementation of SQL <b>ADD COLUMN</b> statement.
061: *
062: * @author Stan Bailes
063: */
064: public class StmtAddColumn implements Stmt {
065: String tableName;
066: Column column;
067: String aname;
068:
069: /**
070: * Explicit constructor from table name and Column
071: */
072: public StmtAddColumn(String tableName, Column column, String aname) {
073: this .tableName = tableName;
074: this .column = column;
075: this .aname = aname;
076: }
077:
078: /**
079: * Stmt.execute()
080: *
081: * For ADD COLUMN, we need to update the table definition, of course.
082: * But then, we need to update *all* of the rows!
083: */
084: public void execute(Session session) throws IOException,
085: SQLException {
086: // First, acquire the schema and table locks
087: Database db = session.getDatabase();
088: session.getTableWriteLock("#Schema");
089: session.getTableWriteLock(tableName);
090:
091: // Make a cursor from the original schema
092: Table table = (Table) db.getRelation(tableName);
093: if (table == null) {
094: throw new SQLException("Table not found: " + tableName);
095: }
096:
097: if (table.getColumnIndex(column.getName()) >= 1) {
098: throw new SQLException("Add Column: a column named '"
099: + column.getName() + "' already exists int table '"
100: + tableName + "'");
101: }
102:
103: int newpos = table.getColumnCount() + 1;
104: if (aname != null) {
105: if (aname.equals("")) {
106: newpos = 1;
107: } else {
108: newpos = table.getColumnIndex(aname) + 1;
109: if (newpos <= 0) {
110: throw new SQLException("Bad column name: " + aname);
111: }
112: }
113: }
114: column.setColumn(newpos);
115:
116: // Update every row in the table with the new column value
117: BCursor bc = null;
118: try {
119: long id = 0;
120: BlockFile file = db.getFile();
121: Expression defaultExpr = column.getDefault();
122: Value columnDefault = defaultExpr == null ? ValueNull.valueNull
123: : defaultExpr.getValue(session, null);
124:
125: IndexConstraint ic = table.getAnyIndex(session);
126: Btree index = ic.getIndex(db);
127: bc = index.getCursor(false);
128: LazyRow row1 = new LazyRow(table.getColumnCount());
129: Row row2 = new Row(table.getColumnCount() + 1);
130: while (bc.next()) {
131: long rowId = bc.getValAsLong();
132: db.getRow(rowId, row1, false);
133: int offset = 0;
134: for (int i = 1; i <= row2.size(); i++) {
135: if (i == newpos) {
136: if (column.isAutoIncrement()) {
137: columnDefault = new ValueLong(++id);
138: }
139: row2.set(i, columnDefault);
140: offset = 1;
141: } else {
142: row2.set(i, row1.item(i - offset));
143: }
144: }
145: UpdateRow update = null;
146: if (db.inMemory()) {
147: update = new UpdateRow(session, rowId, row1, row2);
148: row2 = new Row(table.getColumnCount() + 1);
149: row1 = new LazyRow(table.getColumnCount());
150: } else {
151: byte[] oldRowBytes = row1.getBytes();
152: byte[] rowBytes = LazyRow.writeRow(session, null,
153: row2);
154: update = new UpdateRow(session, table, rowId,
155: oldRowBytes, rowBytes);
156: }
157: session.doStep(update);
158: }
159: if (column.isAutoIncrement()) {
160: session.doStep(new AutoNumberStep(session, table,
161: id + 1));
162: }
163: } finally {
164: if (bc != null)
165: bc.release();
166: }
167:
168: // This changes the table schema
169: session.doStep(new AddColumn(session, table, column, newpos));
170:
171: Vector cv = column.getConstraints();
172: if (cv != null)
173: for (int i = 0; i < cv.size(); i++) {
174: Constraint constraint = (Constraint) cv.elementAt(i);
175: session.doStep(new AddConstraint(session, table,
176: constraint));
177: }
178:
179: table.resetColumnConstraints();
180: }
181: }
|