1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.healthmarketscience.jackcess.impl;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Set;
22
23 import com.healthmarketscience.jackcess.ColumnBuilder;
24 import com.healthmarketscience.jackcess.DataType;
25 import com.healthmarketscience.jackcess.IndexBuilder;
26
27
28
29
30
31
32
33 public abstract class TableMutator extends DBMutator
34 {
35 private ColumnOffsets _colOffsets;
36
37 protected TableMutator(DatabaseImpl database) {
38 super(database);
39 }
40
41 public void setColumnOffsets(
42 int fixedOffset, int varOffset, int longVarOffset) {
43 if(_colOffsets == null) {
44 _colOffsets = new ColumnOffsets();
45 }
46 _colOffsets.set(fixedOffset, varOffset, longVarOffset);
47 }
48
49 public ColumnOffsets getColumnOffsets() {
50 return _colOffsets;
51 }
52
53 public IndexImpl.ForeignKeyReference getForeignKey(IndexBuilder idx) {
54 return null;
55 }
56
57 protected void validateColumn(Set<String> colNames, ColumnBuilder column) {
58
59
60 if(column.getType() == DataType.COMPLEX_TYPE) {
61 throw new UnsupportedOperationException(withErrorContext(
62 "Complex column creation is not yet implemented"));
63 }
64
65 column.validate(getFormat());
66 if(!colNames.add(DatabaseImpl.toLookupName(column.getName()))) {
67 throw new IllegalArgumentException(withErrorContext(
68 "duplicate column name: " + column.getName()));
69 }
70
71 setColumnSortOrder(column);
72 }
73
74 protected void validateIndex(Set<String> colNames, Set<String> idxNames,
75 boolean[] foundPk, IndexBuilder index) {
76
77 index.validate(colNames, getFormat());
78 if(!idxNames.add(DatabaseImpl.toLookupName(index.getName()))) {
79 throw new IllegalArgumentException(withErrorContext(
80 "duplicate index name: " + index.getName()));
81 }
82 if(index.isPrimaryKey()) {
83 if(foundPk[0]) {
84 throw new IllegalArgumentException(withErrorContext(
85 "found second primary key index: " + index.getName()));
86 }
87 foundPk[0] = true;
88 } else if(index.getType() == IndexImpl.FOREIGN_KEY_INDEX_TYPE) {
89 if(getForeignKey(index) == null) {
90 throw new IllegalArgumentException(withErrorContext(
91 "missing foreign key info for " + index.getName()));
92 }
93 }
94 }
95
96 protected void validateAutoNumberColumn(Set<DataType> autoTypes,
97 ColumnBuilder column)
98 {
99 if(!column.getType().isMultipleAutoNumberAllowed() &&
100 !autoTypes.add(column.getType())) {
101 throw new IllegalArgumentException(withErrorContext(
102 "Can have at most one AutoNumber column of type " + column.getType() +
103 " per table"));
104 }
105 }
106
107 private void setColumnSortOrder(ColumnBuilder column) {
108
109 if(column.getType().isTextual() && (column.getTextSortOrder() == null)) {
110 column.setTextSortOrder(getDbSortOrder());
111 }
112 }
113
114 abstract String getTableName();
115
116 public abstract int getTdefPageNumber();
117
118 abstract short getColumnNumber(String colName);
119
120
121
122
123
124 abstract boolean isComplexColumn(String colName);
125
126 public abstract ColumnState getColumnState(ColumnBuilder col);
127
128 public abstract IndexDataState getIndexDataState(IndexBuilder idx);
129
130 protected abstract String withErrorContext(String msg);
131
132
133
134
135
136 static final class ColumnOffsets
137 {
138 private short _fixedOffset;
139 private short _varOffset;
140 private short _longVarOffset;
141
142 public void set(int fixedOffset, int varOffset, int longVarOffset) {
143 _fixedOffset = (short)fixedOffset;
144 _varOffset = (short)varOffset;
145 _longVarOffset = (short)longVarOffset;
146 }
147
148 public short getNextVariableOffset(ColumnBuilder col) {
149 if(!col.isVariableLength()) {
150 return _varOffset;
151 }
152 if(!col.getType().isLongValue()) {
153 return _varOffset++;
154 }
155 return _longVarOffset++;
156 }
157
158 public short getNextFixedOffset(ColumnBuilder col) {
159 if(col.storeInNullMask()) {
160
161 return 0;
162 }
163 short offset = _fixedOffset;
164 _fixedOffset += col.getFixedDataSize();
165 return offset;
166 }
167 }
168
169
170
171
172
173 static final class ColumnState
174 {
175 private byte _umapOwnedRowNumber;
176 private byte _umapFreeRowNumber;
177
178 private int _umapPageNumber;
179
180 public byte getUmapOwnedRowNumber() {
181 return _umapOwnedRowNumber;
182 }
183
184 public void setUmapOwnedRowNumber(byte newUmapOwnedRowNumber) {
185 _umapOwnedRowNumber = newUmapOwnedRowNumber;
186 }
187
188 public byte getUmapFreeRowNumber() {
189 return _umapFreeRowNumber;
190 }
191
192 public void setUmapFreeRowNumber(byte newUmapFreeRowNumber) {
193 _umapFreeRowNumber = newUmapFreeRowNumber;
194 }
195
196 public int getUmapPageNumber() {
197 return _umapPageNumber;
198 }
199
200 public void setUmapPageNumber(int newUmapPageNumber) {
201 _umapPageNumber = newUmapPageNumber;
202 }
203 }
204
205
206
207
208
209 static final class IndexDataState
210 {
211 private final List<IndexBuilder> _indexes = new ArrayList<>();
212 private int _indexDataNumber;
213 private byte _umapRowNumber;
214 private int _umapPageNumber;
215 private int _rootPageNumber;
216
217 public IndexBuilder getFirstIndex() {
218
219
220 return _indexes.get(0);
221 }
222
223 public List<IndexBuilder> getIndexes() {
224 return _indexes;
225 }
226
227 public void addIndex(IndexBuilder idx) {
228 _indexes.add(idx);
229 }
230
231 public int getIndexDataNumber() {
232 return _indexDataNumber;
233 }
234
235 public void setIndexDataNumber(int newIndexDataNumber) {
236 _indexDataNumber = newIndexDataNumber;
237 }
238
239 public byte getUmapRowNumber() {
240 return _umapRowNumber;
241 }
242
243 public void setUmapRowNumber(byte newUmapRowNumber) {
244 _umapRowNumber = newUmapRowNumber;
245 }
246
247 public int getUmapPageNumber() {
248 return _umapPageNumber;
249 }
250
251 public void setUmapPageNumber(int newUmapPageNumber) {
252 _umapPageNumber = newUmapPageNumber;
253 }
254
255 public int getRootPageNumber() {
256 return _rootPageNumber;
257 }
258
259 public void setRootPageNumber(int newRootPageNumber) {
260 _rootPageNumber = newRootPageNumber;
261 }
262 }
263 }