/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.constraint;
import java.util.
HashSet;
import java.util.
Iterator;
import org.h2.api.
ErrorCode;
import org.h2.engine.
Session;
import org.h2.expression.
Expression;
import org.h2.expression.
ExpressionVisitor;
import org.h2.index.
Index;
import org.h2.message.
DbException;
import org.h2.result.
ResultInterface;
import org.h2.result.
Row;
import org.h2.schema.
Schema;
import org.h2.table.
Column;
import org.h2.table.
Table;
import org.h2.table.
TableFilter;
import org.h2.util.
StringUtils;
import org.h2.value.
Value;
import org.h2.value.
ValueNull;
/**
* A check constraint.
*/
public class
ConstraintCheck extends
Constraint {
private
TableFilter filter;
private
Expression expr;
public
ConstraintCheck(
Schema schema, int
id,
String name,
Table table) {
super(
schema,
id,
name,
table);
}
@
Override
public
Type getConstraintType() {
return
Constraint.
Type.
CHECK;
}
public void
setTableFilter(
TableFilter filter) {
this.
filter =
filter;
}
public void
setExpression(
Expression expr) {
this.
expr =
expr;
}
@
Override
public
String getCreateSQLForCopy(
Table forTable,
String quotedName) {
StringBuilder buff = new
StringBuilder("ALTER TABLE ");
buff.
append(
forTable.
getSQL()).
append(" ADD CONSTRAINT ");
if (
forTable.
isHidden()) {
buff.
append("IF NOT EXISTS ");
}
buff.
append(
quotedName);
if (
comment != null) {
buff.
append(" COMMENT ").
append(
StringUtils.
quoteStringSQL(
comment));
}
buff.
append(" CHECK").
append(
StringUtils.
enclose(
expr.
getSQL()))
.
append(" NOCHECK");
return
buff.
toString();
}
private
String getShortDescription() {
return
getName() + ": " +
expr.
getSQL();
}
@
Override
public
String getCreateSQLWithoutIndexes() {
return
getCreateSQL();
}
@
Override
public
String getCreateSQL() {
return
getCreateSQLForCopy(
table,
getSQL());
}
@
Override
public void
removeChildrenAndResources(
Session session) {
table.
removeConstraint(this);
database.
removeMeta(
session,
getId());
filter = null;
expr = null;
table = null;
invalidate();
}
@
Override
public void
checkRow(
Session session,
Table t,
Row oldRow,
Row newRow) {
if (
newRow == null) {
return;
}
filter.
set(
newRow);
boolean
b;
try {
Value v =
expr.
getValue(
session);
// Both TRUE and NULL are ok
b =
v ==
ValueNull.
INSTANCE ||
v.
getBoolean();
} catch (
DbException ex) {
throw
DbException.
get(
ErrorCode.
CHECK_CONSTRAINT_INVALID,
ex,
getShortDescription());
}
if (!
b) {
throw
DbException.
get(
ErrorCode.
CHECK_CONSTRAINT_VIOLATED_1,
getShortDescription());
}
}
@
Override
public boolean
usesIndex(
Index index) {
return false;
}
@
Override
public void
setIndexOwner(
Index index) {
DbException.
throwInternalError(
toString());
}
@
Override
public
HashSet<
Column>
getReferencedColumns(
Table table) {
HashSet<
Column>
columns = new
HashSet<>();
expr.
isEverything(
ExpressionVisitor.
getColumnsVisitor(
columns));
for (
Iterator<
Column>
it =
columns.
iterator();
it.
hasNext();) {
if (
it.
next().
getTable() !=
table) {
it.
remove();
}
}
return
columns;
}
public
Expression getExpression() {
return
expr;
}
@
Override
public boolean
isBefore() {
return true;
}
@
Override
public void
checkExistingData(
Session session) {
if (
session.
getDatabase().
isStarting()) {
// don't check at startup
return;
}
String sql = "SELECT 1 FROM " +
filter.
getTable().
getSQL() +
" WHERE NOT(" +
expr.
getSQL() + ")";
ResultInterface r =
session.
prepare(
sql).
query(1);
if (
r.
next()) {
throw
DbException.
get(
ErrorCode.
CHECK_CONSTRAINT_VIOLATED_1,
getName());
}
}
@
Override
public
Index getUniqueIndex() {
return null;
}
@
Override
public void
rebuild() {
// nothing to do
}
@
Override
public boolean
isEverything(
ExpressionVisitor visitor) {
return
expr.
isEverything(
visitor);
}
}