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   public abstract ColumnState getColumnState(ColumnBuilder col);
121 
122   public abstract IndexDataState getIndexDataState(IndexBuilder idx);
123 
124   protected abstract String withErrorContext(String msg);
125 
126   
127 
128 
129 
130   static final class ColumnOffsets
131   {
132     private short _fixedOffset;
133     private short _varOffset;
134     private short _longVarOffset;
135 
136     public void set(int fixedOffset, int varOffset, int longVarOffset) {
137       _fixedOffset = (short)fixedOffset;
138       _varOffset = (short)varOffset;
139       _longVarOffset = (short)longVarOffset;
140     }
141 
142     public short getNextVariableOffset(ColumnBuilder col) {
143       if(!col.isVariableLength()) {
144         return _varOffset;
145       }
146       if(!col.getType().isLongValue()) {
147         return _varOffset++;
148       }
149       return _longVarOffset++;
150     }
151 
152     public short getNextFixedOffset(ColumnBuilder col) {
153       if(col.storeInNullMask()) {
154         
155         return 0;
156       }
157       short offset = _fixedOffset;
158       _fixedOffset += col.getFixedDataSize();
159       return offset;
160     }
161   }
162 
163   
164 
165 
166 
167   static final class ColumnState
168   {
169     private byte _umapOwnedRowNumber;
170     private byte _umapFreeRowNumber;
171     
172     private int _umapPageNumber;
173 
174     public byte getUmapOwnedRowNumber() {
175       return _umapOwnedRowNumber;
176     }
177 
178     public void setUmapOwnedRowNumber(byte newUmapOwnedRowNumber) {
179       _umapOwnedRowNumber = newUmapOwnedRowNumber;
180     }
181 
182     public byte getUmapFreeRowNumber() {
183       return _umapFreeRowNumber;
184     }
185 
186     public void setUmapFreeRowNumber(byte newUmapFreeRowNumber) {
187       _umapFreeRowNumber = newUmapFreeRowNumber;
188     }
189 
190     public int getUmapPageNumber() {
191       return _umapPageNumber;
192     }
193 
194     public void setUmapPageNumber(int newUmapPageNumber) {
195       _umapPageNumber = newUmapPageNumber;
196     }
197   }
198 
199   
200 
201 
202 
203   static final class IndexDataState
204   {
205     private final List<IndexBuilder> _indexes = new ArrayList<IndexBuilder>();
206     private int _indexDataNumber;
207     private byte _umapRowNumber;
208     private int _umapPageNumber;
209     private int _rootPageNumber;
210 
211     public IndexBuilder getFirstIndex() {
212       
213       
214       return _indexes.get(0);
215     }
216 
217     public List<IndexBuilder> getIndexes() {
218       return _indexes;
219     }
220 
221     public void addIndex(IndexBuilder idx) {
222       _indexes.add(idx);
223     }
224 
225     public int getIndexDataNumber() {
226       return _indexDataNumber;
227     }
228 
229     public void setIndexDataNumber(int newIndexDataNumber) {
230       _indexDataNumber = newIndexDataNumber;
231     }
232 
233     public byte getUmapRowNumber() {
234       return _umapRowNumber;
235     }
236 
237     public void setUmapRowNumber(byte newUmapRowNumber) {
238       _umapRowNumber = newUmapRowNumber;
239     }
240 
241     public int getUmapPageNumber() {
242       return _umapPageNumber;
243     }
244 
245     public void setUmapPageNumber(int newUmapPageNumber) {
246       _umapPageNumber = newUmapPageNumber;
247     }
248 
249     public int getRootPageNumber() {
250       return _rootPageNumber;
251     }
252 
253     public void setRootPageNumber(int newRootPageNumber) {
254       _rootPageNumber = newRootPageNumber;
255     }
256   }
257 }