1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.constraint; |
7 | |
8 | import java.util.HashSet; |
9 | import org.h2.command.Parser; |
10 | import org.h2.engine.Session; |
11 | import org.h2.index.Index; |
12 | import org.h2.result.Row; |
13 | import org.h2.schema.Schema; |
14 | import org.h2.table.Column; |
15 | import org.h2.table.IndexColumn; |
16 | import org.h2.table.Table; |
17 | import org.h2.util.New; |
18 | import org.h2.util.StatementBuilder; |
19 | import org.h2.util.StringUtils; |
20 | |
21 | /** |
22 | * A unique constraint. This object always backed by a unique index. |
23 | */ |
24 | public class ConstraintUnique extends Constraint { |
25 | |
26 | private Index index; |
27 | private boolean indexOwner; |
28 | private IndexColumn[] columns; |
29 | private final boolean primaryKey; |
30 | |
31 | public ConstraintUnique(Schema schema, int id, String name, Table table, |
32 | boolean primaryKey) { |
33 | super(schema, id, name, table); |
34 | this.primaryKey = primaryKey; |
35 | } |
36 | |
37 | @Override |
38 | public String getConstraintType() { |
39 | return primaryKey ? Constraint.PRIMARY_KEY : Constraint.UNIQUE; |
40 | } |
41 | |
42 | @Override |
43 | public String getCreateSQLForCopy(Table forTable, String quotedName) { |
44 | return getCreateSQLForCopy(forTable, quotedName, true); |
45 | } |
46 | |
47 | private String getCreateSQLForCopy(Table forTable, String quotedName, |
48 | boolean internalIndex) { |
49 | StatementBuilder buff = new StatementBuilder("ALTER TABLE "); |
50 | buff.append(forTable.getSQL()).append(" ADD CONSTRAINT "); |
51 | if (forTable.isHidden()) { |
52 | buff.append("IF NOT EXISTS "); |
53 | } |
54 | buff.append(quotedName); |
55 | if (comment != null) { |
56 | buff.append(" COMMENT ").append(StringUtils.quoteStringSQL(comment)); |
57 | } |
58 | buff.append(' ').append(getTypeName()).append('('); |
59 | for (IndexColumn c : columns) { |
60 | buff.appendExceptFirst(", "); |
61 | buff.append(Parser.quoteIdentifier(c.column.getName())); |
62 | } |
63 | buff.append(')'); |
64 | if (internalIndex && indexOwner && forTable == this.table) { |
65 | buff.append(" INDEX ").append(index.getSQL()); |
66 | } |
67 | return buff.toString(); |
68 | } |
69 | |
70 | private String getTypeName() { |
71 | if (primaryKey) { |
72 | return "PRIMARY KEY"; |
73 | } |
74 | return "UNIQUE"; |
75 | } |
76 | |
77 | @Override |
78 | public String getCreateSQLWithoutIndexes() { |
79 | return getCreateSQLForCopy(table, getSQL(), false); |
80 | } |
81 | |
82 | @Override |
83 | public String getCreateSQL() { |
84 | return getCreateSQLForCopy(table, getSQL()); |
85 | } |
86 | |
87 | public void setColumns(IndexColumn[] columns) { |
88 | this.columns = columns; |
89 | } |
90 | |
91 | public IndexColumn[] getColumns() { |
92 | return columns; |
93 | } |
94 | |
95 | /** |
96 | * Set the index to use for this unique constraint. |
97 | * |
98 | * @param index the index |
99 | * @param isOwner true if the index is generated by the system and belongs |
100 | * to this constraint |
101 | */ |
102 | public void setIndex(Index index, boolean isOwner) { |
103 | this.index = index; |
104 | this.indexOwner = isOwner; |
105 | } |
106 | |
107 | @Override |
108 | public void removeChildrenAndResources(Session session) { |
109 | table.removeConstraint(this); |
110 | if (indexOwner) { |
111 | table.removeIndexOrTransferOwnership(session, index); |
112 | } |
113 | database.removeMeta(session, getId()); |
114 | index = null; |
115 | columns = null; |
116 | table = null; |
117 | invalidate(); |
118 | } |
119 | |
120 | @Override |
121 | public void checkRow(Session session, Table t, Row oldRow, Row newRow) { |
122 | // unique index check is enough |
123 | } |
124 | |
125 | @Override |
126 | public boolean usesIndex(Index idx) { |
127 | return idx == index; |
128 | } |
129 | |
130 | @Override |
131 | public void setIndexOwner(Index index) { |
132 | indexOwner = true; |
133 | } |
134 | |
135 | @Override |
136 | public HashSet<Column> getReferencedColumns(Table table) { |
137 | HashSet<Column> result = New.hashSet(); |
138 | for (IndexColumn c : columns) { |
139 | result.add(c.column); |
140 | } |
141 | return result; |
142 | } |
143 | |
144 | @Override |
145 | public boolean isBefore() { |
146 | return true; |
147 | } |
148 | |
149 | @Override |
150 | public void checkExistingData(Session session) { |
151 | // no need to check: when creating the unique index any problems are |
152 | // found |
153 | } |
154 | |
155 | @Override |
156 | public Index getUniqueIndex() { |
157 | return index; |
158 | } |
159 | |
160 | @Override |
161 | public void rebuild() { |
162 | // nothing to do |
163 | } |
164 | |
165 | } |