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.HashMap;
21 import java.util.Map;
22
23 import com.healthmarketscience.jackcess.impl.ColumnImpl;
24 import com.healthmarketscience.jackcess.impl.DatabaseImpl;
25 import com.healthmarketscience.jackcess.impl.JetFormat;
26 import com.healthmarketscience.jackcess.impl.PropertyMapImpl;
27 import com.healthmarketscience.jackcess.impl.TableImpl;
28 import com.healthmarketscience.jackcess.impl.TableUpdater;
29
30
31
32
33
34
35
36
37
38
39 public class ColumnBuilder {
40
41
42 private String _name;
43
44 private DataType _type;
45
46 private Short _length;
47
48 private Byte _precision;
49
50 private Byte _scale;
51
52 private boolean _autoNumber;
53
54 private boolean _compressedUnicode;
55
56 private boolean _calculated;
57
58 private boolean _hyperlink;
59
60 private short _columnNumber;
61
62 private ColumnImpl.SortOrder _sortOrder;
63
64 private Map<String,PropertyMap.Property> _props;
65
66
67 public ColumnBuilder(String name) {
68 this(name, null);
69 }
70
71 public ColumnBuilder(String name, DataType type) {
72 _name = name;
73 _type = type;
74 }
75
76 public String getName() {
77 return _name;
78 }
79
80
81
82
83 public ColumnBuilder setType(DataType type) {
84 _type = type;
85 return this;
86 }
87
88 public DataType getType() {
89 return _type;
90 }
91
92
93
94
95 public ColumnBuilder setSQLType(int type) throws IOException {
96 return setSQLType(type, 0, null);
97 }
98
99
100
101
102
103 public ColumnBuilder setSQLType(int type, int lengthInUnits)
104 throws IOException
105 {
106 return setSQLType(type, lengthInUnits, null);
107 }
108
109
110
111
112
113 public ColumnBuilder setSQLType(int type, int lengthInUnits,
114 Database.FileFormat fileFormat)
115 throws IOException
116 {
117 return setType(DataType.fromSQLType(type, lengthInUnits, fileFormat));
118 }
119
120
121
122
123 public ColumnBuilder setPrecision(int newPrecision) {
124 _precision = (byte)newPrecision;
125 return this;
126 }
127
128 public byte getPrecision() {
129 return ((_precision != null) ? _precision : (byte)_type.getDefaultPrecision());
130 }
131
132
133
134
135
136 public ColumnBuilder setMaxPrecision() {
137 if(_type.getHasScalePrecision()) {
138 setPrecision(_type.getMaxPrecision());
139 }
140 return this;
141 }
142
143
144
145
146 public ColumnBuilder setScale(int newScale) {
147 _scale = (byte)newScale;
148 return this;
149 }
150
151 public byte getScale() {
152 return ((_scale != null) ? _scale : (byte)_type.getDefaultScale());
153 }
154
155
156
157
158
159 public ColumnBuilder setMaxScale() {
160 if(_type.getHasScalePrecision()) {
161 setScale(_type.getMaxScale());
162 }
163 return this;
164 }
165
166
167
168
169 public ColumnBuilder setLength(int length) {
170 _length = (short)length;
171 return this;
172 }
173
174 public short getLength() {
175 return ((_length != null) ? _length :
176 (short)(!_type.isVariableLength() ? _type.getFixedSize() :
177 _type.getDefaultSize()));
178 }
179
180
181
182
183 public ColumnBuilder setLengthInUnits(int unitLength) {
184 return setLength(_type.fromUnitSize(unitLength));
185 }
186
187
188
189
190
191 public ColumnBuilder setMaxLength() {
192
193 if(_type.isVariableLength()) {
194 setLength(_type.getMaxSize());
195 }
196 return this;
197 }
198
199
200
201
202 public ColumnBuilder setAutoNumber(boolean autoNumber) {
203 _autoNumber = autoNumber;
204 return this;
205 }
206
207 public boolean isAutoNumber() {
208 return _autoNumber;
209 }
210
211
212
213
214 public ColumnBuilder setCompressedUnicode(boolean compressedUnicode) {
215 _compressedUnicode = compressedUnicode;
216 return this;
217 }
218
219 public boolean isCompressedUnicode() {
220 return _compressedUnicode;
221 }
222
223
224
225
226 public ColumnBuilder setCalculated(boolean calculated) {
227 _calculated = calculated;
228 return this;
229 }
230
231 public boolean isCalculated() {
232 return _calculated;
233 }
234
235
236
237
238
239 public ColumnBuilder setCalculatedInfo(String expression) {
240 setCalculated(true);
241 putProperty(PropertyMap.EXPRESSION_PROP, expression);
242 return putProperty(PropertyMap.RESULT_TYPE_PROP, getType().getValue());
243 }
244
245 public boolean isVariableLength() {
246
247 return(getType().isVariableLength() || isCalculated());
248 }
249
250
251
252
253 public ColumnBuilder setHyperlink(boolean hyperlink) {
254 _hyperlink = hyperlink;
255 return this;
256 }
257
258 public boolean isHyperlink() {
259 return _hyperlink;
260 }
261
262
263
264
265
266
267
268 public ColumnBuilder putProperty(String name, Object value) {
269 return putProperty(name, null, value);
270 }
271
272
273
274
275 public ColumnBuilder putProperty(String name, DataType type, Object value) {
276 setProperty(name, PropertyMapImpl.createProperty(name, type, value));
277 return this;
278 }
279
280 public Map<String,PropertyMap.Property> getProperties() {
281 return _props;
282 }
283
284 private void setProperty(String name, PropertyMap.Property prop) {
285 if(prop == null) {
286 return;
287 }
288 if(_props == null) {
289 _props = new HashMap<String,PropertyMap.Property>();
290 }
291 _props.put(name, prop);
292 }
293
294 private PropertyMap.Property getProperty(String name) {
295 return ((_props != null) ? _props.get(name) : null);
296 }
297
298
299
300
301
302 public ColumnBuilder setFromColumn(Column template)
303 throws IOException
304 {
305 DataType type = template.getType();
306 setType(type);
307 setLengthInUnits(template.getLengthInUnits());
308 setAutoNumber(template.isAutoNumber());
309 if(type.getHasScalePrecision()) {
310 setScale(template.getScale());
311 setPrecision(template.getPrecision());
312 }
313 setCalculated(template.isCalculated());
314 setCompressedUnicode(template.isCompressedUnicode());
315 setHyperlink(template.isHyperlink());
316 if(template instanceof ColumnImpl) {
317 setTextSortOrder(((ColumnImpl)template).getTextSortOrder());
318 }
319
320 PropertyMap colProps = template.getProperties();
321 for(PropertyMap.Property colProp : colProps) {
322
323 if(!PropertyMap.GUID_PROP.equalsIgnoreCase(colProp.getName())) {
324 setProperty(colProp.getName(), colProp);
325 }
326 }
327
328 return this;
329 }
330
331
332
333
334 public ColumnBuilderm/healthmarketscience/jackcess/ColumnBuilder.html#ColumnBuilder">ColumnBuilder setFromColumn(ColumnBuilder template) {
335 DataType type = template.getType();
336 _type = type;
337 _length = template._length;
338 _autoNumber = template._autoNumber;
339 if(type.getHasScalePrecision()) {
340 _scale = template._scale;
341 _precision = template._precision;
342 }
343 _calculated = template._calculated;
344 _compressedUnicode = template._compressedUnicode;
345 _hyperlink = template._hyperlink;
346 _sortOrder = template._sortOrder;
347
348 if(template._props != null) {
349 _props = new HashMap<String,PropertyMap.Property>(template._props);
350 }
351
352 return this;
353 }
354
355
356
357
358 public ColumnBuilder escapeName() {
359 _name = TableBuilder.escapeIdentifier(_name);
360 return this;
361 }
362
363
364
365
366 public short getColumnNumber() {
367 return _columnNumber;
368 }
369
370
371
372
373 public void setColumnNumber(short newColumnNumber) {
374 _columnNumber = newColumnNumber;
375 }
376
377
378
379
380 public ColumnImpl.SortOrder getTextSortOrder() {
381 return _sortOrder;
382 }
383
384
385
386
387 public void setTextSortOrder(ColumnImpl.SortOrder newTextSortOrder) {
388 _sortOrder = newTextSortOrder;
389 }
390
391
392
393
394
395
396
397 public void validate(JetFormat format) {
398 DatabaseImpl.validateIdentifierName(
399 getName(), format.MAX_COLUMN_NAME_LENGTH, "column");
400
401 if(getType() == null) {
402 throw new IllegalArgumentException(withErrorContext("must have type"));
403 }
404 if(getType().isUnsupported()) {
405 throw new IllegalArgumentException(withErrorContext(
406 "Cannot create column with unsupported type " + getType()));
407 }
408 if(!format.isSupportedDataType(getType())) {
409 throw new IllegalArgumentException(withErrorContext(
410 "Database format " + format + " does not support type " + getType()));
411 }
412
413 if(!getType().isVariableLength()) {
414 if(getLength() < getType().getFixedSize()) {
415 throw new IllegalArgumentException(withErrorContext(
416 "Invalid fixed length size " + getLength()));
417 }
418 } else if(!getType().isLongValue()) {
419 if(!getType().isValidSize(getLength())) {
420 throw new IllegalArgumentException(withErrorContext(
421 "Var length must be from " + getType().getMinSize() + " to " +
422 getType().getMaxSize() + " inclusive, found " + getLength()));
423 }
424 }
425
426 if(getType().getHasScalePrecision()) {
427 if(!getType().isValidScale(getScale())) {
428 throw new IllegalArgumentException(withErrorContext(
429 "Scale must be from " + getType().getMinScale() + " to " +
430 getType().getMaxScale() + " inclusive, found " + getScale()));
431 }
432 if(!getType().isValidPrecision(getPrecision())) {
433 throw new IllegalArgumentException(withErrorContext(
434 "Precision must be from " + getType().getMinPrecision() + " to " +
435 getType().getMaxPrecision() + " inclusive, found " +
436 getPrecision()));
437 }
438 }
439
440 if(isAutoNumber()) {
441 if(!getType().mayBeAutoNumber()) {
442 throw new IllegalArgumentException(withErrorContext(
443 "Auto number column must be long integer or guid"));
444 }
445 }
446
447 if(isCompressedUnicode()) {
448 if(!getType().isTextual()) {
449 throw new IllegalArgumentException(withErrorContext(
450 "Only textual columns allow unicode compression (text/memo)"));
451 }
452 }
453
454 if(isHyperlink()) {
455 if(getType() != DataType.MEMO) {
456 throw new IllegalArgumentException(withErrorContext(
457 "Only memo columns can be hyperlinks"));
458 }
459 }
460
461 if(isCalculated()) {
462 if(!format.isSupportedCalculatedDataType(getType())) {
463 throw new IllegalArgumentException(withErrorContext(
464 "Database format " + format + " does not support calculated type " +
465 getType()));
466 }
467
468
469 if(getProperty(PropertyMap.EXPRESSION_PROP) == null) {
470 throw new IllegalArgumentException(withErrorContext(
471 "No expression provided for calculated type " + getType()));
472 }
473
474
475 if(getProperty(PropertyMap.RESULT_TYPE_PROP) == null) {
476 putProperty(PropertyMap.RESULT_TYPE_PROP, getType().getValue());
477 }
478 }
479 }
480
481
482
483
484 public ColumnBuilder toColumn() {
485
486 return this;
487 }
488
489
490
491
492
493 public Column addToTable(Table table) throws IOException {
494 return addToTableDefinition(table);
495 }
496
497
498
499
500
501 public Column addToTableDefinition(TableDefinition table) throws IOException {
502 return new TableUpdater((TableImpl)table).addColumn(this);
503 }
504
505 private String withErrorContext(String msg) {
506 return msg + "(Column=" + getName() + ")";
507 }
508 }