/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.command.ddl; import java.util.ArrayList; import org.h2.command.CommandInterface; import org.h2.command.dml.Insert; import org.h2.command.dml.Query; import org.h2.constant.ErrorCode; import org.h2.engine.Database; import org.h2.engine.Session; import org.h2.expression.Expression; import org.h2.message.DbException; import org.h2.schema.Schema; import org.h2.schema.Sequence; import org.h2.table.Column; import org.h2.table.IndexColumn; import org.h2.table.Table; import org.h2.util.New; import org.h2.value.DataType; /** * This class represents the statement * CREATE TABLE */ public class CreateTable extends SchemaCommand { private CreateTableData data = new CreateTableData(); private ArrayList<DefineCommand> constraintCommands = New.arrayList(); private IndexColumn[] pkColumns; private boolean ifNotExists; private boolean onCommitDrop; private boolean onCommitTruncate; private Query asQuery; private String comment; private boolean sortedInsertMode; public CreateTable(Session session, Schema schema) { super(session, schema); data.persistIndexes = true; data.persistData = true; } public void setQuery(Query query) { this.asQuery = query; } public void setTemporary(boolean temporary) { data.temporary = temporary; } public void setTableName(String tableName) { data.tableName = tableName; } /** * Add a column to this table. * * @param column the column to add */ public void addColumn(Column column) { data.columns.add(column); } /** * Add a constraint statement to this statement. * The primary key definition is one possible constraint statement. * * @param command the statement to add */ public void addConstraintCommand(DefineCommand command) { if (command instanceof CreateIndex) { constraintCommands.add(command); } else { AlterTableAddConstraint con = (AlterTableAddConstraint) command; boolean alreadySet; if (con.getType() == CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY) { alreadySet = setPrimaryKeyColumns(con.getIndexColumns()); } else { alreadySet = false; } if (!alreadySet) { constraintCommands.add(command); } } } public void setIfNotExists(boolean ifNotExists) { this.ifNotExists = ifNotExists; } public int update() { if (!transactional) { session.commit(true); } Database db = session.getDatabase(); if (!db.isPersistent()) { data.persistIndexes = false; } if (getSchema().findTableOrView(session, data.tableName) != null) { if (ifNotExists) { return 0; } throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.tableName); } if (asQuery != null) { asQuery.prepare(); if (data.columns.size() == 0) { generateColumnsFromQuery(); } else if (data.columns.size() != asQuery.getColumnCount()) { throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); } } if (pkColumns != null) { for (Column c : data.columns) { for (IndexColumn idxCol : pkColumns) { if (c.getName().equals(idxCol.columnName)) { c.setNullable(false); } } } } data.id = getObjectId(); data.create = create; data.session = session; boolean isSessionTemporary = data.temporary && !data.globalTemporary; if (!isSessionTemporary) { db.lockMeta(session); } Table table = getSchema().createTable(data); ArrayList<Sequence> sequences = New.arrayList(); for (Column c : data.columns) { if (c.isAutoIncrement()) { int objId = getObjectId(); c.convertAutoIncrementToSequence(session, getSchema(), objId, data.temporary); } Sequence seq = c.getSequence(); if (seq != null) { sequences.add(seq); } } table.setComment(comment); if (isSessionTemporary) { if (onCommitDrop) { table.setOnCommitDrop(true); } if (onCommitTruncate) { table.setOnCommitTruncate(true); } session.addLocalTempTable(table); } else { db.lockMeta(session); db.addSchemaObject(session, table); } try { for (Column c : data.columns) { c.prepareExpression(session); } for (Sequence sequence : sequences) { table.addSequence(sequence); } for (DefineCommand command : constraintCommands) { command.setTransactional(transactional); command.update(); } if (asQuery != null) { boolean old = session.isUndoLogEnabled(); try { session.setUndoLogEnabled(false); Insert insert = null; insert = new Insert(session); insert.setSortedInsertMode(sortedInsertMode); insert.setQuery(asQuery); insert.setTable(table); insert.setInsertFromSelect(true); insert.prepare(); insert.update(); } finally { session.setUndoLogEnabled(old); } } } catch (DbException e) { db.checkPowerOff(); db.removeSchemaObject(session, table); if (!transactional) { session.commit(true); } throw e; } return 0; } private void generateColumnsFromQuery() { int columnCount = asQuery.getColumnCount(); ArrayList<Expression> expressions = asQuery.getExpressions(); for (int i = 0; i < columnCount; i++) { Expression expr = expressions.get(i); int type = expr.getType(); String name = expr.getAlias(); long precision = expr.getPrecision(); int displaySize = expr.getDisplaySize(); DataType dt = DataType.getDataType(type); if (precision > 0 && (dt.defaultPrecision == 0 || (dt.defaultPrecision > precision && dt.defaultPrecision < Byte.MAX_VALUE))) { // dont' set precision to MAX_VALUE if this is the default precision = dt.defaultPrecision; } int scale = expr.getScale(); if (scale > 0 && (dt.defaultScale == 0 || (dt.defaultScale > scale && dt.defaultScale < precision))) { scale = dt.defaultScale; } if (scale > precision) { precision = scale; } Column col = new Column(name, type, precision, scale, displaySize); addColumn(col); } } /** * Sets the primary key columns, but also check if a primary key * with different columns is already defined. * * @param columns the primary key columns * @return true if the same primary key columns where already set */ private boolean setPrimaryKeyColumns(IndexColumn[] columns) { if (pkColumns != null) { int len = columns.length; if (len != pkColumns.length) { throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY); } for (int i = 0; i < len; i++) { if (!columns[i].columnName.equals(pkColumns[i].columnName)) { throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY); } } return true; } this.pkColumns = columns; return false; } public void setPersistIndexes(boolean persistIndexes) { data.persistIndexes = persistIndexes; } public void setGlobalTemporary(boolean globalTemporary) { data.globalTemporary = globalTemporary; } /** * This temporary table is dropped on commit. */ public void setOnCommitDrop() { this.onCommitDrop = true; } /** * This temporary table is truncated on commit. */ public void setOnCommitTruncate() { this.onCommitTruncate = true; } public void setComment(String comment) { this.comment = comment; } public void setPersistData(boolean persistData) { data.persistData = persistData; if (!persistData) { data.persistIndexes = false; } } public void setSortedInsertMode(boolean sortedInsertMode) { this.sortedInsertMode = sortedInsertMode; } public void setTableEngine(String tableEngine) { data.tableEngine = tableEngine; } public void setHidden(boolean isHidden) { data.isHidden = isHidden; } public int getType() { return CommandInterface.CREATE_TABLE; } }