org.h2.command.ddl.CreateTable Maven / Gradle / Ivy
/*
* Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.command.ddl;
import java.util.ArrayList;
import java.util.HashSet;
import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface;
import org.h2.command.dml.Insert;
import org.h2.command.dml.Query;
import org.h2.engine.Database;
import org.h2.engine.DbObject;
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.Table;
import org.h2.util.ColumnNamer;
import org.h2.value.Value;
/**
* This class represents the statement
* CREATE TABLE
*/
public class CreateTable extends CommandWithColumns {
private final CreateTableData data = new CreateTableData();
private boolean ifNotExists;
private boolean onCommitDrop;
private boolean onCommitTruncate;
private Query asQuery;
private String comment;
private boolean sortedInsertMode;
private boolean withNoData;
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;
}
@Override
public void addColumn(Column column) {
data.columns.add(column);
}
public ArrayList getColumns() {
return data.columns;
}
public void setIfNotExists(boolean ifNotExists) {
this.ifNotExists = ifNotExists;
}
@Override
public int update() {
if (!transactional) {
session.commit(true);
}
Database db = session.getDatabase();
if (!db.isPersistent()) {
data.persistIndexes = false;
}
boolean isSessionTemporary = data.temporary && !data.globalTemporary;
if (!isSessionTemporary) {
db.lockMeta(session);
}
if (getSchema().resolveTableOrView(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.isEmpty()) {
generateColumnsFromQuery();
} else if (data.columns.size() != asQuery.getColumnCount()) {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} else {
ArrayList columns = data.columns;
for (int i = 0; i < columns.size(); i++) {
Column column = columns.get(i);
if (column.getType().getValueType() == Value.UNKNOWN) {
columns.set(i, new Column(column.getName(), asQuery.getExpressions().get(i).getType()));
}
}
}
}
changePrimaryKeysToNotNull(data.columns);
data.id = getObjectId();
data.create = create;
data.session = session;
Table table = getSchema().createTable(data);
ArrayList sequences = generateSequences(data.columns, data.temporary);
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);
}
createConstraints();
if (asQuery != null && !withNoData) {
boolean old = session.isUndoLogEnabled();
try {
session.setUndoLogEnabled(false);
session.startStatementWithinTransaction(null);
Insert insert = new Insert(session);
insert.setSortedInsertMode(sortedInsertMode);
insert.setQuery(asQuery);
insert.setTable(table);
insert.setInsertFromSelect(true);
insert.prepare();
insert.update();
} finally {
session.endStatement();
session.setUndoLogEnabled(old);
}
}
HashSet set = new HashSet<>();
table.addDependencies(set);
for (DbObject obj : set) {
if (obj == table) {
continue;
}
if (obj.getType() == DbObject.TABLE_OR_VIEW) {
if (obj instanceof Table) {
Table t = (Table) obj;
if (t.getId() > table.getId()) {
throw DbException.get(
ErrorCode.FEATURE_NOT_SUPPORTED_1,
"Table depends on another table " +
"with a higher ID: " + t +
", this is currently not supported, " +
"as it would prevent the database from " +
"being re-opened");
}
}
}
}
} catch (DbException e) {
try {
db.checkPowerOff();
db.removeSchemaObject(session, table);
if (!transactional) {
session.commit(true);
}
} catch (Throwable ex) {
e.addSuppressed(ex);
}
throw e;
}
return 0;
}
private void generateColumnsFromQuery() {
int columnCount = asQuery.getColumnCount();
ArrayList expressions = asQuery.getExpressions();
ColumnNamer columnNamer= new ColumnNamer(session);
for (int i = 0; i < columnCount; i++) {
Expression expr = expressions.get(i);
String name = columnNamer.getColumnName(expr, i, expr.getAlias());
Column col = new Column(name, expr.getType());
addColumn(col);
}
}
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 setWithNoData(boolean withNoData) {
this.withNoData = withNoData;
}
public void setTableEngine(String tableEngine) {
data.tableEngine = tableEngine;
}
public void setTableEngineParams(ArrayList tableEngineParams) {
data.tableEngineParams = tableEngineParams;
}
public void setHidden(boolean isHidden) {
data.isHidden = isHidden;
}
@Override
public int getType() {
return CommandInterface.CREATE_TABLE;
}
}