1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.healthmarketscience.jackcess;
18
19 import java.io.IOException;
20 import java.util.ArrayList;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Set;
24
25 import com.healthmarketscience.jackcess.impl.DatabaseImpl;
26 import com.healthmarketscience.jackcess.impl.IndexData;
27 import com.healthmarketscience.jackcess.impl.IndexImpl;
28 import com.healthmarketscience.jackcess.impl.JetFormat;
29 import com.healthmarketscience.jackcess.impl.TableImpl;
30 import com.healthmarketscience.jackcess.impl.TableUpdater;
31
32
33
34
35
36
37
38
39
40
41 public class IndexBuilder
42 {
43
44 public static final String PRIMARY_KEY_NAME = "PrimaryKey";
45
46
47 private String _name;
48
49 private byte _type;
50
51
52 private byte _flags = IndexData.UNKNOWN_INDEX_FLAG;
53
54 private final List<Column> _columns = new ArrayList<Column>();
55
56 private int _indexNumber;
57
58 public IndexBuilder(String name) {
59 _name = name;
60 }
61
62 public String getName() {
63 return _name;
64 }
65
66 public byte getType() {
67 return _type;
68 }
69
70 public byte getFlags() {
71 return _flags;
72 }
73
74 public boolean isPrimaryKey() {
75 return (getType() == IndexImpl.PRIMARY_KEY_INDEX_TYPE);
76 }
77
78 public boolean isUnique() {
79 return ((getFlags() & IndexData.UNIQUE_INDEX_FLAG) != 0);
80 }
81
82 public boolean isIgnoreNulls() {
83 return ((getFlags() & IndexData.IGNORE_NULLS_INDEX_FLAG) != 0);
84 }
85
86 public List<Column> getColumns() {
87 return _columns;
88 }
89
90
91
92
93 public IndexBuilder setName(String name) {
94 _name = name;
95 return this;
96 }
97
98
99
100
101 public IndexBuilder addColumns(String... names) {
102 return addColumns(true, names);
103 }
104
105
106
107
108 public IndexBuilder addColumns(boolean ascending, String... names) {
109 if(names != null) {
110 for(String name : names) {
111 _columns.add(new Column(name, ascending));
112 }
113 }
114 return this;
115 }
116
117
118
119
120
121 public IndexBuilder setPrimaryKey() {
122 _type = IndexImpl.PRIMARY_KEY_INDEX_TYPE;
123 setRequired();
124 return setUnique();
125 }
126
127
128
129
130 public IndexBuilder setType(byte type) {
131 _type = type;
132 return this;
133 }
134
135
136
137
138 public IndexBuilder setUnique() {
139 _flags |= IndexData.UNIQUE_INDEX_FLAG;
140 return this;
141 }
142
143
144
145
146 public IndexBuilder setRequired() {
147 _flags |= IndexData.REQUIRED_INDEX_FLAG;
148 return this;
149 }
150
151
152
153
154 public IndexBuilder setIgnoreNulls() {
155 _flags |= IndexData.IGNORE_NULLS_INDEX_FLAG;
156 return this;
157 }
158
159
160
161
162 public int getIndexNumber() {
163 return _indexNumber;
164 }
165
166
167
168
169 public void setIndexNumber(int newIndexNumber) {
170 _indexNumber = newIndexNumber;
171 }
172
173
174
175
176
177
178
179 public void validate(Set<String> tableColNames, JetFormat format) {
180
181 DatabaseImpl.validateIdentifierName(
182 getName(), format.MAX_INDEX_NAME_LENGTH, "index");
183
184 if(getColumns().isEmpty()) {
185 throw new IllegalArgumentException(withErrorContext(
186 "index has no columns"));
187 }
188 if(getColumns().size() > IndexData.MAX_COLUMNS) {
189 throw new IllegalArgumentException(withErrorContext(
190 "index has too many columns, max " + IndexData.MAX_COLUMNS));
191 }
192
193 Set<String> idxColNames = new HashSet<String>();
194 for(Column col : getColumns()) {
195 String idxColName = col.getName().toUpperCase();
196 if(!idxColNames.add(idxColName)) {
197 throw new IllegalArgumentException(withErrorContext(
198 "duplicate column name " + col.getName() + " in index"));
199 }
200 if(!tableColNames.contains(idxColName)) {
201 throw new IllegalArgumentException(withErrorContext(
202 "column named " + col.getName() + " not found in table"));
203 }
204 }
205 }
206
207
208
209
210
211 public Index addToTable(Table table) throws IOException {
212 return addToTableDefinition(table);
213 }
214
215
216
217
218
219 public Index addToTableDefinition(TableDefinition table) throws IOException {
220 return new TableUpdater((TableImpl)table).addIndex(this);
221 }
222
223 private String withErrorContext(String msg) {
224 return msg + "(Index=" + getName() + ")";
225 }
226
227
228
229
230 public static class Column
231 {
232
233 private String _name;
234
235 private byte _flags;
236
237 private Column(String name, boolean ascending) {
238 _name = name;
239 _flags = (ascending ? IndexData.ASCENDING_COLUMN_FLAG : 0);
240 }
241
242 public String getName() {
243 return _name;
244 }
245
246 public Column setName(String name) {
247 _name = name;
248 return this;
249 }
250
251 public boolean isAscending() {
252 return ((getFlags() & IndexData.ASCENDING_COLUMN_FLAG) != 0);
253 }
254
255 public byte getFlags() {
256 return _flags;
257 }
258 }
259
260 }