001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.command.ddl;
007:
008: import java.sql.SQLException;
009:
010: import org.h2.command.Prepared;
011: import org.h2.command.dml.Insert;
012: import org.h2.command.dml.Query;
013: import org.h2.constant.ErrorCode;
014: import org.h2.engine.Database;
015: import org.h2.engine.Session;
016: import org.h2.expression.Expression;
017: import org.h2.message.Message;
018: import org.h2.schema.Schema;
019: import org.h2.schema.Sequence;
020: import org.h2.table.Column;
021: import org.h2.table.IndexColumn;
022: import org.h2.table.TableData;
023: import org.h2.util.ObjectArray;
024: import org.h2.value.DataType;
025:
026: /**
027: * This class represents the statement
028: * CREATE TABLE
029: */
030: public class CreateTable extends SchemaCommand {
031:
032: private String tableName;
033: private ObjectArray constraintCommands = new ObjectArray();
034: private ObjectArray columns = new ObjectArray();
035: private IndexColumn[] pkColumns;
036: private boolean ifNotExists;
037: private boolean persistent = true;
038: private boolean temporary;
039: private boolean globalTemporary;
040: private boolean onCommitDrop;
041: private boolean onCommitTruncate;
042: private Query asQuery;
043: private String comment;
044: private boolean clustered;
045:
046: public CreateTable(Session session, Schema schema) {
047: super (session, schema);
048: }
049:
050: public void setQuery(Query query) {
051: this .asQuery = query;
052: }
053:
054: public void setTemporary(boolean temporary) {
055: this .temporary = temporary;
056: }
057:
058: public void setTableName(String tableName) {
059: this .tableName = tableName;
060: }
061:
062: /**
063: * Add a column to this table.
064: *
065: * @param column the column to add
066: */
067: public void addColumn(Column column) {
068: if (columns == null) {
069: columns = new ObjectArray();
070: }
071: columns.add(column);
072: }
073:
074: /**
075: * Add a constraint statement to this statement.
076: * The primary key definition is one possible constraint statement.
077: *
078: * @param command the statement to add
079: */
080: public void addConstraintCommand(Prepared command)
081: throws SQLException {
082: if (command instanceof CreateIndex) {
083: constraintCommands.add(command);
084: } else {
085: AlterTableAddConstraint con = (AlterTableAddConstraint) command;
086: boolean alreadySet;
087: if (con.getType() == AlterTableAddConstraint.PRIMARY_KEY) {
088: alreadySet = setPrimaryKeyColumns(con.getIndexColumns());
089: } else {
090: alreadySet = false;
091: }
092: if (!alreadySet) {
093: constraintCommands.add(command);
094: }
095: }
096: }
097:
098: public void setIfNotExists(boolean ifNotExists) {
099: this .ifNotExists = ifNotExists;
100: }
101:
102: public int update() throws SQLException {
103: // TODO rights: what rights are required to create a table?
104: session.commit(true);
105: Database db = session.getDatabase();
106: if (!db.isPersistent()) {
107: persistent = false;
108: }
109: if (getSchema().findTableOrView(session, tableName) != null) {
110: if (ifNotExists) {
111: return 0;
112: }
113: throw Message
114: .getSQLException(
115: ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
116: tableName);
117: }
118: if (asQuery != null) {
119: asQuery.prepare();
120: if (columns.size() == 0) {
121: generateColumnFromQuery();
122: } else if (columns.size() != asQuery.getColumnCount()) {
123: throw Message
124: .getSQLException(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
125: }
126: }
127: if (pkColumns != null) {
128: int len = pkColumns.length;
129: for (int i = 0; i < columns.size(); i++) {
130: Column c = (Column) columns.get(i);
131: for (int j = 0; j < len; j++) {
132: if (c.getName().equals(pkColumns[j].columnName)) {
133: c.setNullable(false);
134: }
135: }
136: }
137: }
138: ObjectArray sequences = new ObjectArray();
139: for (int i = 0; i < columns.size(); i++) {
140: Column c = (Column) columns.get(i);
141: if (c.getAutoIncrement()) {
142: int objId = getObjectId(true, true);
143: c.convertAutoIncrementToSequence(session, getSchema(),
144: objId, temporary);
145: }
146: Sequence seq = c.getSequence();
147: if (seq != null) {
148: sequences.add(seq);
149: }
150: }
151: int id = getObjectId(true, true);
152: TableData table = getSchema().createTable(tableName, id,
153: columns, persistent, clustered);
154: table.setComment(comment);
155: table.setTemporary(temporary);
156: table.setGlobalTemporary(globalTemporary);
157: if (temporary && !globalTemporary) {
158: if (onCommitDrop) {
159: table.setOnCommitDrop(true);
160: }
161: if (onCommitTruncate) {
162: table.setOnCommitTruncate(true);
163: }
164: session.addLocalTempTable(table);
165: } else {
166: db.addSchemaObject(session, table);
167: }
168: try {
169: for (int i = 0; i < columns.size(); i++) {
170: Column c = (Column) columns.get(i);
171: c.prepareExpression(session);
172: }
173: for (int i = 0; i < sequences.size(); i++) {
174: Sequence sequence = (Sequence) sequences.get(i);
175: table.addSequence(sequence);
176: }
177: for (int i = 0; i < constraintCommands.size(); i++) {
178: Prepared command = (Prepared) constraintCommands.get(i);
179: command.update();
180: }
181: if (asQuery != null) {
182: boolean old = session.getUndoLogEnabled();
183: try {
184: session.setUndoLogEnabled(false);
185: Insert insert = null;
186: insert = new Insert(session);
187: insert.setQuery(asQuery);
188: insert.setTable(table);
189: insert.prepare();
190: insert.update();
191: } finally {
192: session.setUndoLogEnabled(old);
193: }
194: }
195: } catch (SQLException e) {
196: db.checkPowerOff();
197: db.removeSchemaObject(session, table);
198: throw e;
199: }
200: return 0;
201: }
202:
203: private void generateColumnFromQuery() throws SQLException {
204: int columnCount = asQuery.getColumnCount();
205: ObjectArray expressions = asQuery.getExpressions();
206: for (int i = 0; i < columnCount; i++) {
207: Expression expr = (Expression) expressions.get(i);
208: int type = expr.getType();
209: String name = expr.getColumnName();
210: long precision = expr.getPrecision();
211: int displaySize = expr.getDisplaySize();
212: DataType dt = DataType.getDataType(type);
213: if (precision > 0
214: && (dt.defaultPrecision == 0 || (dt.defaultPrecision > precision && dt.defaultPrecision < Byte.MAX_VALUE))) {
215: // dont' set precision to MAX_VALUE if this is the default
216: precision = dt.defaultPrecision;
217: }
218: int scale = expr.getScale();
219: if (scale > 0
220: && (dt.defaultScale == 0 || dt.defaultScale > scale)) {
221: scale = dt.defaultScale;
222: }
223: Column col = new Column(name, type, precision, scale,
224: displaySize);
225: addColumn(col);
226: }
227: }
228:
229: /**
230: * Sets the primary key columns, but also check if a primary key
231: * with different columns is already defined.
232: *
233: * @param columns the primary key columns
234: * @return true if the same primary key columns where already set
235: */
236: private boolean setPrimaryKeyColumns(IndexColumn[] columns)
237: throws SQLException {
238: if (pkColumns != null) {
239: if (columns.length != pkColumns.length) {
240: throw Message
241: .getSQLException(ErrorCode.SECOND_PRIMARY_KEY);
242: }
243: for (int i = 0; i < columns.length; i++) {
244: if (!columns[i].columnName
245: .equals(pkColumns[i].columnName)) {
246: throw Message
247: .getSQLException(ErrorCode.SECOND_PRIMARY_KEY);
248: }
249: }
250: return true;
251: }
252: this .pkColumns = columns;
253: return false;
254: }
255:
256: public void setPersistent(boolean persistent) {
257: this .persistent = persistent;
258: }
259:
260: public void setGlobalTemporary(boolean globalTemporary) {
261: this .globalTemporary = globalTemporary;
262: }
263:
264: /**
265: * This temporary table is dropped on commit.
266: */
267: public void setOnCommitDrop() {
268: this .onCommitDrop = true;
269: }
270:
271: /**
272: * This temporary table is truncated on commit.
273: */
274: public void setOnCommitTruncate() {
275: this .onCommitTruncate = true;
276: }
277:
278: public void setComment(String comment) {
279: this .comment = comment;
280: }
281:
282: public void setClustered(boolean clustered) {
283: this.clustered = clustered;
284: }
285:
286: }
|