Merge lp:~nwilliams/akiban-server/alter-generated into lp:~akiban-technologies/akiban-server/trunk
- alter-generated
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Mike McMahon |
Approved revision: | 2628 |
Merged at revision: | 2624 |
Proposed branch: | lp:~nwilliams/akiban-server/alter-generated |
Merge into: | lp:~akiban-technologies/akiban-server/trunk |
Diff against target: |
1014 lines (+399/-106) 20 files modified
src/main/java/com/akiban/ais/model/AISBuilder.java (+3/-3) src/main/java/com/akiban/ais/model/AISMerge.java (+61/-22) src/main/java/com/akiban/ais/model/AkibanInformationSchema.java (+1/-1) src/main/java/com/akiban/ais/model/DefaultNameGenerator.java (+3/-1) src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java (+13/-7) src/main/java/com/akiban/ais/model/aisb2/NewUserTableBuilder.java (+11/-1) src/main/java/com/akiban/ais/util/ChangedTableDescription.java (+8/-1) src/main/java/com/akiban/ais/util/TableChangeValidator.java (+14/-10) src/main/java/com/akiban/server/error/ColumnAlreadyGeneratedException.java (+31/-0) src/main/java/com/akiban/server/error/ColumnNotGeneratedException.java (+29/-0) src/main/java/com/akiban/server/error/ErrorCode.java (+2/-0) src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java (+2/-1) src/main/java/com/akiban/sql/aisddl/AlterTableDDL.java (+77/-36) src/main/java/com/akiban/sql/aisddl/TableDDL.java (+16/-15) src/main/java/com/akiban/sql/aisddl/ViewDDL.java (+1/-1) src/main/resources/com/akiban/server/error/error_code.properties (+2/-0) src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java (+8/-4) src/test/java/com/akiban/sql/aisddl/AlterTableDDLTest.java (+103/-2) src/test/java/com/akiban/sql/aisddl/TableDDLIT.java (+1/-1) src/test/resources/com/akiban/sql/pg/yaml/functional/test-identity.yaml (+13/-0) |
To merge this branch: | bzr merge lp:~nwilliams/akiban-server/alter-generated |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike McMahon | Approve | ||
Review via email: mp+158990@code.launchpad.net |
Commit message
Description of the change
Support SET INCREMENT and GENERATED ALTER actions.
A little tweaking in handling DEFAULT nodes in AlterTableDDL and a little propagation of new sequences through the validator and merger.
Minor tweaks and helper methods elsewhere.
- 2626. By Nathan Williams
-
Remove dead variable
Nathan Williams (nwilliams) wrote : | # |
Indeed it was. Removed.
Mike McMahon (mmcm) wrote : | # |
Uncovered trying to update the client-tools test for this: DumpClient assumes that identity sequences are named _sequence-XXX, whereas one added by ALTER is still called temp-sequence-1. I assume that name will cause other kinds of trouble, but it is possible to alter the dumper, of course.
Nathan Williams (nwilliams) wrote : | # |
Wasn't using as much of the helper as I thought I was. Fixed.
Good catch. Why does DumpClient assume that? Is there no other indication that it is an identity column?
- 2627. By Nathan Williams
-
Use helper for sequence name.
- 2628. By Nathan Williams
-
Cleanup
Preview Diff
1 | === modified file 'src/main/java/com/akiban/ais/model/AISBuilder.java' |
2 | --- src/main/java/com/akiban/ais/model/AISBuilder.java 2013-03-22 20:05:57 +0000 |
3 | +++ src/main/java/com/akiban/ais/model/AISBuilder.java 2013-04-15 20:33:27 +0000 |
4 | @@ -75,12 +75,12 @@ |
5 | return nameGenerator; |
6 | } |
7 | |
8 | - public void sequence (String schemaName, String sequenceName, |
9 | - long start, long increment, |
10 | - long minValue, long maxValue, boolean cycle) { |
11 | + public Sequence sequence(String schemaName, String sequenceName, |
12 | + long start, long increment, long minValue, long maxValue, boolean cycle) { |
13 | LOG.trace("sequence: {}.{} ", schemaName,sequenceName); |
14 | Sequence identityGenerator = Sequence.create(ais, schemaName, sequenceName, start, increment, minValue, maxValue, cycle); |
15 | identityGenerator.setTreeName(nameGenerator.generateSequenceTreeName(identityGenerator)); |
16 | + return identityGenerator; |
17 | } |
18 | |
19 | public UserTable userTable(String schemaName, String tableName) { |
20 | |
21 | === modified file 'src/main/java/com/akiban/ais/model/AISMerge.java' |
22 | --- src/main/java/com/akiban/ais/model/AISMerge.java 2013-04-11 03:40:21 +0000 |
23 | +++ src/main/java/com/akiban/ais/model/AISMerge.java 2013-04-15 20:33:27 +0000 |
24 | @@ -86,6 +86,20 @@ |
25 | } |
26 | } |
27 | |
28 | + private static class IdentityInfo { |
29 | + public final TableName tableName; |
30 | + public final String columnName; |
31 | + public final boolean defaultIdentity; |
32 | + public final Sequence sequence; |
33 | + |
34 | + public IdentityInfo(TableName tableName, String columnName, boolean defaultIdentity, Sequence sequence) { |
35 | + this.tableName = tableName; |
36 | + this.columnName = columnName; |
37 | + this.defaultIdentity = defaultIdentity; |
38 | + this.sequence = sequence; |
39 | + } |
40 | + } |
41 | + |
42 | private static final Logger LOG = LoggerFactory.getLogger(AISMerge.class); |
43 | |
44 | /* state */ |
45 | @@ -95,16 +109,17 @@ |
46 | private final MergeType mergeType; |
47 | private final List<JoinChange> changedJoins; |
48 | private final Map<IndexName,IndexInfo> indexesToFix; |
49 | + private final List<IdentityInfo> identityToFix; |
50 | |
51 | |
52 | /** Legacy test constructor. Creates an AISMerge for adding a table with a new {@link DefaultNameGenerator}. */ |
53 | AISMerge(AkibanInformationSchema sourceAIS, UserTable newTable) { |
54 | - this(new DefaultNameGenerator(sourceAIS), copyAISForAdd(sourceAIS), newTable, MergeType.ADD_TABLE, null, null); |
55 | + this(new DefaultNameGenerator(sourceAIS), copyAISForAdd(sourceAIS), newTable, MergeType.ADD_TABLE, null, null, null); |
56 | } |
57 | |
58 | /** Create a new AISMerge to be used for adding a new table. */ |
59 | public static AISMerge newForAddTable(NameGenerator generator, AkibanInformationSchema sourceAIS, UserTable newTable) { |
60 | - return new AISMerge(generator, copyAISForAdd(sourceAIS), newTable, MergeType.ADD_TABLE, null, null); |
61 | + return new AISMerge(generator, copyAISForAdd(sourceAIS), newTable, MergeType.ADD_TABLE, null, null, null); |
62 | } |
63 | |
64 | /** Create a new AISMerge to be used for modifying a table. */ |
65 | @@ -112,27 +127,30 @@ |
66 | Collection<ChangedTableDescription> alteredTables) { |
67 | List<JoinChange> changedJoins = new ArrayList<>(); |
68 | Map<IndexName,IndexInfo> indexesToFix = new HashMap<>(); |
69 | - AkibanInformationSchema targetAIS = copyAISForModify(sourceAIS, indexesToFix, changedJoins, alteredTables); |
70 | - return new AISMerge(generator, targetAIS, null, MergeType.MODIFY_TABLE, changedJoins, indexesToFix); |
71 | + List<IdentityInfo> identityToFix = new ArrayList<>(); |
72 | + AkibanInformationSchema targetAIS = copyAISForModify(sourceAIS, indexesToFix, changedJoins, identityToFix, alteredTables); |
73 | + return new AISMerge(generator, targetAIS, null, MergeType.MODIFY_TABLE, changedJoins, indexesToFix, identityToFix); |
74 | } |
75 | |
76 | /** Create a new AISMerge to be used for adding one, or more, index to a table. Also see {@link #mergeIndex(Index)}. */ |
77 | public static AISMerge newForAddIndex(NameGenerator generator, AkibanInformationSchema sourceAIS) { |
78 | - return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.ADD_INDEX, null, null); |
79 | + return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.ADD_INDEX, null, null, null); |
80 | } |
81 | |
82 | public static AISMerge newForOther(NameGenerator generator, AkibanInformationSchema sourceAIS) { |
83 | - return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.OTHER, null, null); |
84 | + return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.OTHER, null, null, null); |
85 | } |
86 | |
87 | private AISMerge(NameGenerator nameGenerator, AkibanInformationSchema targetAIS, UserTable sourceTable, |
88 | - MergeType mergeType, List<JoinChange> changedJoins, Map<IndexName,IndexInfo> indexesToFix) { |
89 | + MergeType mergeType, List<JoinChange> changedJoins, Map<IndexName,IndexInfo> indexesToFix, |
90 | + List<IdentityInfo> identityToFix) { |
91 | this.nameGenerator = nameGenerator; |
92 | this.targetAIS = targetAIS; |
93 | this.sourceTable = sourceTable; |
94 | this.mergeType = mergeType; |
95 | this.changedJoins = changedJoins; |
96 | this.indexesToFix = indexesToFix; |
97 | + this.identityToFix = identityToFix; |
98 | } |
99 | |
100 | |
101 | @@ -143,6 +161,7 @@ |
102 | private static AkibanInformationSchema copyAISForModify(AkibanInformationSchema oldAIS, |
103 | Map<IndexName,IndexInfo> indexesToFix, |
104 | final List<JoinChange> joinsToFix, |
105 | + List<IdentityInfo> identityToFix, |
106 | Collection<ChangedTableDescription> changedTables) |
107 | { |
108 | final Set<Sequence> excludedSequences = new HashSet<>(); |
109 | @@ -218,6 +237,11 @@ |
110 | for(TableName name : desc.getDroppedSequences()) { |
111 | excludedSequences.add(oldAIS.getSequence(name)); |
112 | } |
113 | + |
114 | + for(String name : desc.getIdentityAdded()) { |
115 | + Column col = newTable.getColumn(name); |
116 | + identityToFix.add(new IdentityInfo(desc.getNewName(), name, col.getDefaultIdentity(), col.getIdentityGenerator())); |
117 | + } |
118 | } |
119 | |
120 | return AISCloner.clone( |
121 | @@ -481,6 +505,11 @@ |
122 | index.setTreeName((info.tree != null) ? info.tree : nameGenerator.generateIndexTreeName(index)); |
123 | } |
124 | |
125 | + for(IdentityInfo info : identityToFix) { |
126 | + addIdentitySequence(builder, info.tableName.getSchemaName(), info.tableName.getTableName(), info.columnName, |
127 | + info.defaultIdentity, info.sequence); |
128 | + } |
129 | + |
130 | builder.akibanInformationSchema().validate(AISValidations.LIVE_AIS_VALIDATIONS).throwIfNecessary(); |
131 | builder.akibanInformationSchema().freeze(); |
132 | } |
133 | @@ -529,16 +558,8 @@ |
134 | newColumn.setInitialAutoIncrementValue(column.getInitialAutoIncrementValue()); |
135 | } |
136 | if (column.getDefaultIdentity() != null) { |
137 | - TableName sequenceName = nameGenerator.generateIdentitySequenceName(new TableName(schemaName, tableName)); |
138 | - Sequence sequence = column.getIdentityGenerator(); |
139 | - builder.sequence(sequenceName.getSchemaName(), sequenceName.getTableName(), |
140 | - sequence.getStartsWith(), |
141 | - sequence.getIncrement(), |
142 | - sequence.getMinValue(), |
143 | - sequence.getMaxValue(), |
144 | - sequence.isCycle()); |
145 | - builder.columnAsIdentity(schemaName, tableName, column.getName(), sequenceName.getTableName(), column.getDefaultIdentity()); |
146 | - LOG.debug("Generated sequence: {}, with tree name; {}", sequenceName, sequence.getTreeName()); |
147 | + addIdentitySequence(builder, schemaName, tableName, column.getName(), |
148 | + column.getDefaultIdentity(), column.getIdentityGenerator()); |
149 | } |
150 | // Proactively cache, can go away if Column ever cleans itself up |
151 | newColumn.getMaxStorageSize(); |
152 | @@ -546,6 +567,19 @@ |
153 | } |
154 | } |
155 | |
156 | + private void addIdentitySequence(AISBuilder builder, String schemaName, String tableName, String column, |
157 | + boolean defaultIdentity, Sequence sequence) { |
158 | + TableName sequenceName = nameGenerator.generateIdentitySequenceName(new TableName(schemaName, tableName)); |
159 | + Sequence newSeq = builder.sequence(sequenceName.getSchemaName(), sequenceName.getTableName(), |
160 | + sequence.getStartsWith(), |
161 | + sequence.getIncrement(), |
162 | + sequence.getMinValue(), |
163 | + sequence.getMaxValue(), |
164 | + sequence.isCycle()); |
165 | + builder.columnAsIdentity(schemaName, tableName, column, sequenceName.getTableName(), defaultIdentity); |
166 | + LOG.debug("Generated sequence: {}, with tree name; {}", sequenceName, newSeq.getTreeName()); |
167 | + } |
168 | + |
169 | private void addNewGroup (AISBuilder builder, UserTable rootTable) { |
170 | TableName groupName = rootTable.getName(); |
171 | builder.createGroup(groupName.getTableName(), groupName.getSchemaName()); |
172 | @@ -650,13 +684,18 @@ |
173 | |
174 | public AkibanInformationSchema mergeSequence(Sequence sequence) |
175 | { |
176 | + mergeSequenceInternal(sequence); |
177 | + targetAIS.validate(AISValidations.LIVE_AIS_VALIDATIONS).throwIfNecessary(); |
178 | + targetAIS.freeze(); |
179 | + return targetAIS; |
180 | + } |
181 | + |
182 | + private Sequence mergeSequenceInternal(Sequence sequence) |
183 | + { |
184 | Sequence newSeq = Sequence.create(targetAIS, sequence); |
185 | newSeq.setTreeName(nameGenerator.generateSequenceTreeName(newSeq)); |
186 | - targetAIS.addSequence(newSeq); |
187 | - targetAIS.validate(AISValidations.LIVE_AIS_VALIDATIONS).throwIfNecessary(); |
188 | - targetAIS.freeze(); |
189 | - return targetAIS; |
190 | - } |
191 | + return newSeq; |
192 | + } |
193 | |
194 | public static AkibanInformationSchema mergeRoutine(AkibanInformationSchema oldAIS, |
195 | Routine routine) { |
196 | |
197 | === modified file 'src/main/java/com/akiban/ais/model/AkibanInformationSchema.java' |
198 | --- src/main/java/com/akiban/ais/model/AkibanInformationSchema.java 2013-03-22 20:05:57 +0000 |
199 | +++ src/main/java/com/akiban/ais/model/AkibanInformationSchema.java 2013-04-15 20:33:27 +0000 |
200 | @@ -642,7 +642,7 @@ |
201 | invalidateTableIdMap(); |
202 | } |
203 | |
204 | - void removeSequence (TableName name) { |
205 | + public void removeSequence (TableName name) { |
206 | sequences.remove(name); |
207 | Schema schema = getSchema(name.getSchemaName()); |
208 | if (schema != null) { |
209 | |
210 | === modified file 'src/main/java/com/akiban/ais/model/DefaultNameGenerator.java' |
211 | --- src/main/java/com/akiban/ais/model/DefaultNameGenerator.java 2013-03-22 20:05:57 +0000 |
212 | +++ src/main/java/com/akiban/ais/model/DefaultNameGenerator.java 2013-04-15 20:33:27 +0000 |
213 | @@ -34,6 +34,8 @@ |
214 | public class DefaultNameGenerator implements NameGenerator { |
215 | private static final Logger LOG = LoggerFactory.getLogger(DefaultNameGenerator.class); |
216 | |
217 | + public static final String IDENTITY_SEQUENCE_PREFIX = "_sequence-"; |
218 | + |
219 | // Use 1 as default offset because the AAM uses tableID 0 as a marker value. |
220 | static final int USER_TABLE_ID_OFFSET = 1; |
221 | static final int IS_TABLE_ID_OFFSET = 1000000000; |
222 | @@ -99,7 +101,7 @@ |
223 | |
224 | @Override |
225 | public TableName generateIdentitySequenceName(TableName tableName) { |
226 | - TableName seqName = new TableName(tableName.getSchemaName(), "_sequence-" + tableName.hashCode()); |
227 | + TableName seqName = new TableName(tableName.getSchemaName(), IDENTITY_SEQUENCE_PREFIX + tableName.hashCode()); |
228 | return makeUnique(sequenceNames, seqName); |
229 | } |
230 | |
231 | |
232 | === modified file 'src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java' |
233 | --- src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java 2013-04-10 23:46:56 +0000 |
234 | +++ src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java 2013-04-15 20:33:27 +0000 |
235 | @@ -214,29 +214,35 @@ |
236 | |
237 | @Override |
238 | public NewUserTableBuilder colLong(String name) { |
239 | - return colLong(name, NULLABLE_DEFAULT, null); |
240 | + return colLong(name, NULLABLE_DEFAULT, null, null); |
241 | } |
242 | |
243 | @Override |
244 | public NewUserTableBuilder colLong(String name, boolean nullable) { |
245 | - return colLong(name, nullable, null); |
246 | + return colLong(name, nullable, null, null); |
247 | } |
248 | |
249 | @Override |
250 | public NewUserTableBuilder autoIncLong(String name, int initialValue) { |
251 | - return colLong(name, false, initialValue); |
252 | - } |
253 | - |
254 | - private NewUserTableBuilder colLong(String name, boolean nullable, Integer initialAutoInc) { |
255 | + return colLong(name, false, initialValue, true); |
256 | + } |
257 | + |
258 | + @Override |
259 | + public NewUserTableBuilder autoIncLong(String name, int initialValue, boolean always) { |
260 | + return colLong(name, false, initialValue, !always); |
261 | + } |
262 | + |
263 | + private NewUserTableBuilder colLong(String name, boolean nullable, Integer initialAutoInc, Boolean defaultIdentity) { |
264 | checkUsable(); |
265 | aisb.column(schema, userTable, name, uTableColumnPos++, "INT", 10L, null, nullable, false, null, null); |
266 | if (initialAutoInc != null) { |
267 | + assert defaultIdentity != null; |
268 | String sequenceName = "temp-seq-" + userTable + "-" + name; |
269 | long initValue = initialAutoInc.longValue(); |
270 | aisb.sequence(schema, sequenceName, |
271 | initValue, 1L, initValue, Long.MAX_VALUE, |
272 | false); |
273 | - aisb.columnAsIdentity(schema, userTable, name, sequenceName, true); |
274 | + aisb.columnAsIdentity(schema, userTable, name, sequenceName, defaultIdentity); |
275 | aisb.akibanInformationSchema(). |
276 | getUserTable(schema, userTable). |
277 | getColumn(name). |
278 | |
279 | === modified file 'src/main/java/com/akiban/ais/model/aisb2/NewUserTableBuilder.java' |
280 | --- src/main/java/com/akiban/ais/model/aisb2/NewUserTableBuilder.java 2013-04-01 18:36:36 +0000 |
281 | +++ src/main/java/com/akiban/ais/model/aisb2/NewUserTableBuilder.java 2013-04-15 20:33:27 +0000 |
282 | @@ -67,13 +67,23 @@ |
283 | NewUserTableBuilder colLong(String name, boolean nullable); |
284 | |
285 | /** |
286 | - * Adds a non-nullable, sequence backed, auto-incrementing column |
287 | + * Adds a non-nullable, sequence backed, auto-incrementing BY DEFAULT identity column |
288 | * @param name the column's name |
289 | + * @param initialValue the START WITH value |
290 | * @return this |
291 | */ |
292 | NewUserTableBuilder autoIncLong(String name, int initialValue); |
293 | |
294 | /** |
295 | + * Adds a non-nullable, sequence backed, auto-incrementing identity column |
296 | + * @param name the column's name |
297 | + * @param initialValue the START WITH value |
298 | + * @param always ALWAYS if <code>true</code>, otherwise DEFAULT |
299 | + * @return this |
300 | + */ |
301 | + NewUserTableBuilder autoIncLong(String name, int initialValue, boolean always); |
302 | + |
303 | + /** |
304 | * Adds an optionally nullable boolean column |
305 | * @param name the column's name |
306 | * @param nullable whether the column is nullable |
307 | |
308 | === modified file 'src/main/java/com/akiban/ais/util/ChangedTableDescription.java' |
309 | --- src/main/java/com/akiban/ais/util/ChangedTableDescription.java 2013-03-22 20:05:57 +0000 |
310 | +++ src/main/java/com/akiban/ais/util/ChangedTableDescription.java 2013-04-15 20:33:27 +0000 |
311 | @@ -38,6 +38,7 @@ |
312 | private final Map<String,String> parentColNames; |
313 | private final Map<String,String> preserveIndexes; |
314 | private final Collection<TableName> droppedSequences; |
315 | + private final Collection<String> identityAdded; |
316 | |
317 | /** |
318 | * @param tableName Current name of the table being changed. |
319 | @@ -46,7 +47,8 @@ |
320 | */ |
321 | public ChangedTableDescription(TableName tableName, UserTable newDefinition, Map<String,String> colNames, |
322 | ParentChange parentChange, TableName parentName, Map<String,String> parentColNames, |
323 | - Map<String, String> preserveIndexes, Collection<TableName> droppedSequences) { |
324 | + Map<String, String> preserveIndexes, Collection<TableName> droppedSequences, |
325 | + Collection<String> identityAdded) { |
326 | ArgumentValidation.notNull("tableName", tableName); |
327 | ArgumentValidation.notNull("preserveIndexes", preserveIndexes); |
328 | this.tableName = tableName; |
329 | @@ -57,6 +59,7 @@ |
330 | this.parentColNames = parentColNames; |
331 | this.preserveIndexes = preserveIndexes; |
332 | this.droppedSequences = droppedSequences; |
333 | + this.identityAdded = identityAdded; |
334 | } |
335 | |
336 | public TableName getOldName() { |
337 | @@ -95,6 +98,10 @@ |
338 | return droppedSequences; |
339 | } |
340 | |
341 | + public Collection<String> getIdentityAdded() { |
342 | + return identityAdded; |
343 | + } |
344 | + |
345 | public boolean isNewGroup() { |
346 | return (parentChange != ParentChange.NONE); |
347 | } |
348 | |
349 | === modified file 'src/main/java/com/akiban/ais/util/TableChangeValidator.java' |
350 | --- src/main/java/com/akiban/ais/util/TableChangeValidator.java 2013-04-11 04:48:29 +0000 |
351 | +++ src/main/java/com/akiban/ais/util/TableChangeValidator.java 2013-04-15 20:33:27 +0000 |
352 | @@ -393,9 +393,9 @@ |
353 | primaryKeyChanged = containsOldOrNew(indexChanges, Index.PRIMARY_KEY_CONSTRAINT); |
354 | |
355 | List<TableName> droppedSequences = new ArrayList<>(); |
356 | + List<String> addedIdentity = new ArrayList<>(); |
357 | Map<String,String> renamedColumns = new HashMap<>(); |
358 | for(TableChange change : columnChanges) { |
359 | - Sequence seqToDrop = null; |
360 | switch(change.getChangeType()) { |
361 | case MODIFY: { |
362 | if(!change.getOldName().equals(change.getNewName())) { |
363 | @@ -403,20 +403,24 @@ |
364 | } |
365 | Column oldColumn = oldTable.getColumn(change.getOldName()); |
366 | Column newColumn = newTable.getColumn(change.getNewName()); |
367 | - if((oldColumn != null) && (oldColumn.getIdentityGenerator() != null) && (newColumn.getIdentityGenerator() == null)) { |
368 | - seqToDrop = oldColumn.getIdentityGenerator(); |
369 | + if((oldColumn != null)) { |
370 | + Sequence oldSeq = oldColumn.getIdentityGenerator(); |
371 | + Sequence newSeq = newColumn.getIdentityGenerator(); |
372 | + if((oldSeq == null) && (newSeq != null)) { |
373 | + addedIdentity.add(newColumn.getName()); |
374 | + } else if((oldSeq != null) && (newSeq == null)) { |
375 | + droppedSequences.add(oldSeq.getSequenceName()); |
376 | + } |
377 | + // else both not null and not equal, not yet supported |
378 | } |
379 | } break; |
380 | case DROP: { |
381 | Column oldColumn = oldTable.getColumn(change.getOldName()); |
382 | - if(oldColumn != null) { |
383 | - seqToDrop = oldColumn.getIdentityGenerator(); |
384 | + if((oldColumn != null) && (oldColumn.getIdentityGenerator() != null)) { |
385 | + droppedSequences.add(oldColumn.getIdentityGenerator().getSequenceName()); |
386 | } |
387 | } break; |
388 | } |
389 | - if(seqToDrop != null) { |
390 | - droppedSequences.add(seqToDrop.getSequenceName()); |
391 | - } |
392 | } |
393 | |
394 | boolean renamed = !oldTable.getName().equals(newTable.getName()) || !renamedColumns.isEmpty(); |
395 | @@ -425,7 +429,7 @@ |
396 | TableName parentName = (newTable.getParentJoin() != null) ? newTable.getParentJoin().getParent().getName() : null; |
397 | changedTables.add(new ChangedTableDescription(oldTable.getName(), newTable, renamedColumns, |
398 | parentChange, parentName, EMPTY_STRING_MAP, preserveIndexes, |
399 | - droppedSequences)); |
400 | + droppedSequences, addedIdentity)); |
401 | |
402 | if(!isParentChanged() && !primaryKeyChanged) { |
403 | for(Index index : newTable.getIndexesIncludingInternal()) { |
404 | @@ -507,7 +511,7 @@ |
405 | parentRenames = (parentRenames != null) ? parentRenames : EMPTY_STRING_MAP; |
406 | changedTables.add(new ChangedTableDescription(table.getName(), null, EMPTY_STRING_MAP, |
407 | parentChange, parentName, parentRenames, preserved, |
408 | - EMPTY_TABLE_NAME_LIST)); |
409 | + EMPTY_TABLE_NAME_LIST, Collections.<String>emptyList())); |
410 | } |
411 | |
412 | private static boolean containsOldOrNew(List<TableChange> changes, String name) { |
413 | |
414 | === added file 'src/main/java/com/akiban/server/error/ColumnAlreadyGeneratedException.java' |
415 | --- src/main/java/com/akiban/server/error/ColumnAlreadyGeneratedException.java 1970-01-01 00:00:00 +0000 |
416 | +++ src/main/java/com/akiban/server/error/ColumnAlreadyGeneratedException.java 2013-04-15 20:33:27 +0000 |
417 | @@ -0,0 +1,31 @@ |
418 | +/** |
419 | + * Copyright (C) 2009-2013 Akiban Technologies, Inc. |
420 | + * |
421 | + * This program is free software: you can redistribute it and/or modify |
422 | + * it under the terms of the GNU Affero General Public License as published by |
423 | + * the Free Software Foundation, either version 3 of the License, or |
424 | + * (at your option) any later version. |
425 | + * |
426 | + * This program is distributed in the hope that it will be useful, |
427 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
428 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
429 | + * GNU Affero General Public License for more details. |
430 | + * |
431 | + * You should have received a copy of the GNU Affero General Public License |
432 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
433 | + */ |
434 | + |
435 | +package com.akiban.server.error; |
436 | + |
437 | +import com.akiban.ais.model.Column; |
438 | + |
439 | +public class ColumnAlreadyGeneratedException extends InvalidOperationException { |
440 | + public ColumnAlreadyGeneratedException(Column column) { |
441 | + super(ErrorCode.COLUMN_ALREADY_GENERATED, |
442 | + column.getColumnar().getName().getSchemaName(), |
443 | + column.getColumnar().getName().getTableName(), |
444 | + column.getName(), |
445 | + column.getIdentityGenerator().getSchemaName(), |
446 | + column.getIdentityGenerator().getSequenceName().getTableName()); |
447 | + } |
448 | +} |
449 | |
450 | === added file 'src/main/java/com/akiban/server/error/ColumnNotGeneratedException.java' |
451 | --- src/main/java/com/akiban/server/error/ColumnNotGeneratedException.java 1970-01-01 00:00:00 +0000 |
452 | +++ src/main/java/com/akiban/server/error/ColumnNotGeneratedException.java 2013-04-15 20:33:27 +0000 |
453 | @@ -0,0 +1,29 @@ |
454 | +/** |
455 | + * Copyright (C) 2009-2013 Akiban Technologies, Inc. |
456 | + * |
457 | + * This program is free software: you can redistribute it and/or modify |
458 | + * it under the terms of the GNU Affero General Public License as published by |
459 | + * the Free Software Foundation, either version 3 of the License, or |
460 | + * (at your option) any later version. |
461 | + * |
462 | + * This program is distributed in the hope that it will be useful, |
463 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
464 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
465 | + * GNU Affero General Public License for more details. |
466 | + * |
467 | + * You should have received a copy of the GNU Affero General Public License |
468 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
469 | + */ |
470 | + |
471 | +package com.akiban.server.error; |
472 | + |
473 | +import com.akiban.ais.model.Column; |
474 | + |
475 | +public class ColumnNotGeneratedException extends InvalidOperationException { |
476 | + public ColumnNotGeneratedException(Column column) { |
477 | + super(ErrorCode.COLUMN_NOT_GENERATED, |
478 | + column.getColumnar().getName().getSchemaName(), |
479 | + column.getColumnar().getName().getTableName(), |
480 | + column.getName()); |
481 | + } |
482 | +} |
483 | |
484 | === modified file 'src/main/java/com/akiban/server/error/ErrorCode.java' |
485 | --- src/main/java/com/akiban/server/error/ErrorCode.java 2013-04-15 14:38:06 +0000 |
486 | +++ src/main/java/com/akiban/server/error/ErrorCode.java 2013-04-15 20:33:27 +0000 |
487 | @@ -373,6 +373,8 @@ |
488 | INVALID_ROUTINE ("50", "024", Importance.DEBUG, InvalidRoutineException.class), |
489 | INVALID_INDEX_ID ("50", "025", Importance.DEBUG, InvalidIndexIDException.class), |
490 | MODEL_BUILDER_ERROR ("50", "026", Importance.DEBUG, ModelBuilderException.class), |
491 | + COLUMN_NOT_GENERATED ("50", "027", Importance.DEBUG, ColumnNotGeneratedException.class), |
492 | + COLUMN_ALREADY_GENERATED ("50", "028", Importance.DEBUG, ColumnAlreadyGeneratedException.class), |
493 | |
494 | // Class 51 - Internal problems created by user configuration |
495 | STALE_AIS ("51", "001", Importance.TRACE, OldAISException.class), |
496 | |
497 | === modified file 'src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java' |
498 | --- src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-11 18:35:20 +0000 |
499 | +++ src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-15 20:33:27 +0000 |
500 | @@ -31,6 +31,7 @@ |
501 | |
502 | import com.akiban.ais.model.AkibanInformationSchema; |
503 | import com.akiban.ais.model.Column; |
504 | +import com.akiban.ais.model.DefaultNameGenerator; |
505 | import com.akiban.ais.model.Group; |
506 | import com.akiban.ais.model.GroupIndex; |
507 | import com.akiban.ais.model.Index; |
508 | @@ -752,7 +753,7 @@ |
509 | for (Sequence sequence : schema.getSequences().values()) { |
510 | // Drop the sequences in this schema, but not the |
511 | // generator sequences, which will be dropped with the table. |
512 | - if (!(sequence.getSequenceName().getTableName().startsWith("_sequence-"))) { |
513 | + if (!(sequence.getSequenceName().getTableName().startsWith(DefaultNameGenerator.IDENTITY_SEQUENCE_PREFIX))) { |
514 | sequencesToDrop.add(sequence); |
515 | } |
516 | } |
517 | |
518 | === modified file 'src/main/java/com/akiban/sql/aisddl/AlterTableDDL.java' |
519 | --- src/main/java/com/akiban/sql/aisddl/AlterTableDDL.java 2013-03-22 20:05:57 +0000 |
520 | +++ src/main/java/com/akiban/sql/aisddl/AlterTableDDL.java 2013-04-15 20:33:27 +0000 |
521 | @@ -17,7 +17,10 @@ |
522 | |
523 | package com.akiban.sql.aisddl; |
524 | |
525 | +import com.akiban.ais.model.Sequence; |
526 | import com.akiban.server.error.AkibanInternalException; |
527 | +import com.akiban.server.error.ColumnAlreadyGeneratedException; |
528 | +import com.akiban.server.error.ColumnNotGeneratedException; |
529 | import com.akiban.sql.parser.AlterTableRenameColumnNode; |
530 | import com.akiban.sql.parser.AlterTableRenameNode; |
531 | import com.akiban.ais.AISCloner; |
532 | @@ -122,8 +125,7 @@ |
533 | List<ColumnDefinitionNode> columnDefNodes = new ArrayList<>(); |
534 | List<FKConstraintDefinitionNode> fkDefNodes= new ArrayList<>(); |
535 | List<ConstraintDefinitionNode> conDefNodes = new ArrayList<>(); |
536 | - List<String> newCols = null; |
537 | - |
538 | + |
539 | for(TableElementNode node : elements) { |
540 | switch(node.getNodeType()) { |
541 | case NodeTypes.COLUMN_DEFINITION_NODE: { |
542 | @@ -181,7 +183,6 @@ |
543 | } break; |
544 | |
545 | case NodeTypes.AT_RENAME_NODE: |
546 | - |
547 | TableName newName = DDLHelper.convertName(defaultSchema, |
548 | ((AlterTableRenameNode)node).newName()); |
549 | TableName oldName = table.getName(); |
550 | @@ -189,18 +190,14 @@ |
551 | return ChangeLevel.METADATA; |
552 | |
553 | case NodeTypes.AT_RENAME_COLUMN_NODE: |
554 | - |
555 | AlterTableRenameColumnNode alterRenameCol = (AlterTableRenameColumnNode) node; |
556 | String oldColName = alterRenameCol.getName(); |
557 | String newColName = alterRenameCol.newName(); |
558 | final Column oldCol = table.getColumn(oldColName); |
559 | if (oldCol == null) |
560 | throw new NoSuchColumnException(oldColName); |
561 | - if (newCols == null) |
562 | - newCols = new ArrayList<>(); |
563 | - newCols.add(newColName); |
564 | columnChanges.add(TableChange.createModify(oldColName, newColName)); |
565 | - break; |
566 | + break; |
567 | |
568 | default: |
569 | return null; // Something unsupported |
570 | @@ -216,38 +213,11 @@ |
571 | for(ColumnDefinitionNode cdn : columnDefNodes) { |
572 | if(cdn instanceof ModifyColumnNode) { |
573 | ModifyColumnNode modNode = (ModifyColumnNode) cdn; |
574 | - Column column = tableCopy.getColumn(modNode.getColumnName()); |
575 | - if(column == null) { |
576 | - throw new NoSuchColumnException(modNode.getColumnName()); |
577 | - } |
578 | - switch(modNode.getNodeType()) { |
579 | - case NodeTypes.MODIFY_COLUMN_DEFAULT_NODE: |
580 | - column.setDefaultValue(TableDDL.getColumnDefault(modNode)); |
581 | - break; |
582 | - case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE: // Type only comes from NULL |
583 | - column.setNullable(true); |
584 | - break; |
585 | - case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE: // Type only comes from NOT NULL |
586 | - column.setNullable(false); |
587 | - break; |
588 | - case NodeTypes.MODIFY_COLUMN_TYPE_NODE: |
589 | - tableCopy.dropColumn(modNode.getColumnName()); |
590 | - TableDDL.addColumn(builder, table.getName().getSchemaName(), table.getName().getTableName(), |
591 | - column.getName(), column.getPosition(), cdn.getType(), column.getNullable(), |
592 | - column.getInitialAutoIncrementValue() != null, |
593 | - column.getDefaultValue()); |
594 | - break; |
595 | - default: |
596 | - throw new IllegalStateException("Unexpected node type: " + modNode); |
597 | - } |
598 | + handleModifyColumnNode(modNode, builder, tableCopy); |
599 | } else { |
600 | TableDDL.addColumn(builder, cdn, table.getName().getSchemaName(), table.getName().getTableName(), pos++); |
601 | } |
602 | } |
603 | - if (newCols != null) |
604 | - for (String name : newCols) |
605 | - if (tableCopy.getColumn(name) == null) |
606 | - throw new AkibanInternalException("New Columns " + newCols + " not created successfully"); |
607 | copyTableIndexes(table, tableCopy, columnChanges, indexChanges); |
608 | |
609 | IndexNameGenerator indexNamer = DefaultIndexNameGenerator.forTable(tableCopy); |
610 | @@ -283,6 +253,77 @@ |
611 | return ddl.alterTable(session, table.getName(), tableCopy, columnChanges, indexChanges, context); |
612 | } |
613 | |
614 | + private static void handleModifyColumnNode(ModifyColumnNode modNode, AISBuilder builder, UserTable tableCopy) { |
615 | + AkibanInformationSchema aisCopy = tableCopy.getAIS(); |
616 | + Column column = tableCopy.getColumn(modNode.getColumnName()); |
617 | + if(column == null) { |
618 | + throw new NoSuchColumnException(modNode.getColumnName()); |
619 | + } |
620 | + switch(modNode.getNodeType()) { |
621 | + case NodeTypes.MODIFY_COLUMN_DEFAULT_NODE: |
622 | + if(modNode.isAutoincrementColumn()) { |
623 | + int autoIncType = (int)modNode.getAutoinc_create_or_modify_Start_Increment(); |
624 | + switch(autoIncType) { |
625 | + case ColumnDefinitionNode.CREATE_AUTOINCREMENT: { |
626 | + if(column.getIdentityGenerator() != null) { |
627 | + throw new ColumnAlreadyGeneratedException(column); |
628 | + } |
629 | + TableName name = tableCopy.getName(); |
630 | + TableDDL.setAutoIncrement(builder, name.getSchemaName(), name.getTableName(), modNode); |
631 | + } |
632 | + break; |
633 | + case ColumnDefinitionNode.MODIFY_AUTOINCREMENT_INC_VALUE: { |
634 | + Sequence curSeq = column.getIdentityGenerator(); |
635 | + if(curSeq == null) { |
636 | + throw new ColumnNotGeneratedException(column); |
637 | + } |
638 | + aisCopy.removeSequence(curSeq.getSequenceName()); |
639 | + Sequence newSeq = Sequence.create(aisCopy, |
640 | + curSeq.getSchemaName(), |
641 | + curSeq.getSequenceName().getTableName(), |
642 | + curSeq.getStartsWith(), |
643 | + modNode.getAutoincrementIncrement(), |
644 | + curSeq.getMinValue(), |
645 | + curSeq.getMaxValue(), |
646 | + curSeq.isCycle()); |
647 | + aisCopy.addSequence(newSeq); |
648 | + column.setIdentityGenerator(newSeq); |
649 | + } |
650 | + break; |
651 | + case ColumnDefinitionNode.MODIFY_AUTOINCREMENT_RESTART_VALUE: |
652 | + // Requires Accumulator reset |
653 | + throw new UnsupportedSQLException("Not yet implemented", modNode); |
654 | + default: |
655 | + throw new IllegalStateException("Unknown autoIncType: " + autoIncType); |
656 | + } |
657 | + } else { |
658 | + // DROP DEFAULT will come though as a NULL default, clears both GENERATED and DEFAULT |
659 | + Sequence seq = column.getIdentityGenerator(); |
660 | + if(seq != null) { |
661 | + column.setDefaultIdentity(null); |
662 | + column.setIdentityGenerator(null); |
663 | + aisCopy.removeSequence(seq.getSequenceName()); |
664 | + } |
665 | + column.setDefaultValue(TableDDL.getColumnDefault(modNode)); |
666 | + } |
667 | + break; |
668 | + case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NODE: // Type only comes from NULL |
669 | + column.setNullable(true); |
670 | + break; |
671 | + case NodeTypes.MODIFY_COLUMN_CONSTRAINT_NOT_NULL_NODE: // Type only comes from NOT NULL |
672 | + column.setNullable(false); |
673 | + break; |
674 | + case NodeTypes.MODIFY_COLUMN_TYPE_NODE: |
675 | + tableCopy.dropColumn(modNode.getColumnName()); |
676 | + TableDDL.addColumn(builder, tableCopy.getName().getSchemaName(), tableCopy.getName().getTableName(), |
677 | + column.getName(), column.getPosition(), modNode.getType(), column.getNullable(), |
678 | + column.getDefaultValue()); |
679 | + break; |
680 | + default: |
681 | + throw new IllegalStateException("Unexpected node type: " + modNode); |
682 | + } |
683 | + } |
684 | + |
685 | private static void checkColumnChange(UserTable table, String columnName) { |
686 | Column column = table.getColumn(columnName); |
687 | if(column == null) { |
688 | |
689 | === modified file 'src/main/java/com/akiban/sql/aisddl/TableDDL.java' |
690 | --- src/main/java/com/akiban/sql/aisddl/TableDDL.java 2013-04-11 05:21:42 +0000 |
691 | +++ src/main/java/com/akiban/sql/aisddl/TableDDL.java 2013-04-15 20:33:27 +0000 |
692 | @@ -213,7 +213,7 @@ |
693 | // BIGINT NOT NULL |
694 | DataTypeDescriptor bigint = new DataTypeDescriptor (TypeId.BIGINT_ID, false); |
695 | addColumn (builder, schemaName, tableName, cdn.getColumnName(), colpos, |
696 | - bigint, false, true, getColumnDefault(cdn)); |
697 | + bigint, false, getColumnDefault(cdn)); |
698 | // GENERATED ALWAYS AS IDENTITY |
699 | setAutoIncrement (builder, schemaName, tableName, cdn.getColumnName(), false, 1, 1); |
700 | // UNIQUE (KEY) |
701 | @@ -221,24 +221,25 @@ |
702 | builder.index(schemaName, tableName, cdn.getColumnName(), true, constraint); |
703 | builder.indexColumn(schemaName, tableName, cdn.getColumnName(), cdn.getColumnName(), 0, true, null); |
704 | } else { |
705 | - boolean autoIncrement = cdn.isAutoincrementColumn(); |
706 | - |
707 | addColumn(builder, schemaName, tableName, cdn.getColumnName(), colpos, |
708 | - cdn.getType(), cdn.getType().isNullable(), autoIncrement, getColumnDefault(cdn)); |
709 | + cdn.getType(), cdn.getType().isNullable(), getColumnDefault(cdn)); |
710 | |
711 | - if (autoIncrement) { |
712 | - // if the cdn has a default node-> GENERATE BY DEFAULT |
713 | - // if no default node -> GENERATE ALWAYS |
714 | - Boolean defaultIdentity = cdn.getDefaultNode() != null; |
715 | - setAutoIncrement (builder, schemaName, tableName, cdn.getColumnName(), |
716 | - defaultIdentity, cdn.getAutoincrementStart(), cdn.getAutoincrementIncrement()); |
717 | + if (cdn.isAutoincrementColumn()) { |
718 | + setAutoIncrement(builder, schemaName, tableName, cdn); |
719 | } |
720 | } |
721 | } |
722 | |
723 | - static void setAutoIncrement (final AISBuilder builder, |
724 | - String schemaName, String tableName, String columnName, boolean defaultIdentity, |
725 | - long start, long increment) { |
726 | + public static void setAutoIncrement(AISBuilder builder, String schema, String table, ColumnDefinitionNode cdn) { |
727 | + // if the cdn has a default node-> GENERATE BY DEFAULT |
728 | + // if no default node -> GENERATE ALWAYS |
729 | + Boolean defaultIdentity = cdn.getDefaultNode() != null; |
730 | + setAutoIncrement(builder, schema, table, cdn.getColumnName(), |
731 | + defaultIdentity, cdn.getAutoincrementStart(), cdn.getAutoincrementIncrement()); |
732 | + } |
733 | + |
734 | + public static void setAutoIncrement(AISBuilder builder, String schemaName, String tableName, String columnName, |
735 | + boolean defaultIdentity, long start, long increment) { |
736 | // The merge process will generate a real sequence name |
737 | final String sequenceName = "temp-sequence-1"; |
738 | builder.sequence(schemaName, sequenceName, |
739 | @@ -267,7 +268,7 @@ |
740 | |
741 | static void addColumn(final AISBuilder builder, |
742 | final String schemaName, final String tableName, final String columnName, |
743 | - int colpos, DataTypeDescriptor type, boolean nullable, boolean autoIncrement, |
744 | + int colpos, DataTypeDescriptor type, boolean nullable, |
745 | final String defaultValue) { |
746 | Long[] typeParameters = new Long[2]; |
747 | Type builderType = columnType(type, typeParameters, schemaName, tableName, columnName); |
748 | @@ -280,7 +281,7 @@ |
749 | colpos, |
750 | builderType.name(), typeParameters[0], typeParameters[1], |
751 | nullable, |
752 | - autoIncrement, |
753 | + false, |
754 | charset, collation, |
755 | defaultValue); |
756 | } |
757 | |
758 | === modified file 'src/main/java/com/akiban/sql/aisddl/ViewDDL.java' |
759 | --- src/main/java/com/akiban/sql/aisddl/ViewDDL.java 2013-03-22 20:05:57 +0000 |
760 | +++ src/main/java/com/akiban/sql/aisddl/ViewDDL.java 2013-04-15 20:33:27 +0000 |
761 | @@ -86,7 +86,7 @@ |
762 | type = new DataTypeDescriptor(TypeId.CHAR_ID, true, 0); |
763 | } |
764 | TableDDL.addColumn(builder, schemaName, viewName, rc.getName(), colpos++, |
765 | - type, type.isNullable(), false, null); |
766 | + type, type.isNullable(), null); |
767 | } |
768 | View view = builder.akibanInformationSchema().getView(schemaName, viewName); |
769 | ddlFunctions.createView(session, view); |
770 | |
771 | === modified file 'src/main/resources/com/akiban/server/error/error_code.properties' |
772 | --- src/main/resources/com/akiban/server/error/error_code.properties 2013-04-15 14:38:06 +0000 |
773 | +++ src/main/resources/com/akiban/server/error/error_code.properties 2013-04-15 20:33:27 +0000 |
774 | @@ -249,6 +249,8 @@ |
775 | INVALID_ROUTINE = Invalid procedure `{0}.`{1}`: {2} |
776 | INVALID_INDEX_ID = Index `{0}.`{1}`.`{2}` has an invalid ID: {3} |
777 | MODEL_BUILDER_ERROR = Error building model for `{0}`.`{1}`: {2} |
778 | +COLUMN_NOT_GENERATED = Column `{0}`.`{1}`.`{2}` is not generated |
779 | +COLUMN_ALREADY_GENERATED = Column `{0}`.`{1}`.`{2}` already generated by sequence `{3}`.`{4}` |
780 | # |
781 | # Class 51 - Internal problems created by user configuration |
782 | # |
783 | |
784 | === modified file 'src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java' |
785 | --- src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java 2013-04-11 04:48:29 +0000 |
786 | +++ src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java 2013-04-15 20:33:27 +0000 |
787 | @@ -21,6 +21,7 @@ |
788 | import com.akiban.ais.model.AISBuilder; |
789 | import com.akiban.ais.model.AkibanInformationSchema; |
790 | import com.akiban.ais.model.Column; |
791 | +import com.akiban.ais.model.DefaultNameGenerator; |
792 | import com.akiban.ais.model.Index; |
793 | import com.akiban.ais.model.Sequence; |
794 | import com.akiban.ais.model.TableName; |
795 | @@ -1180,12 +1181,15 @@ |
796 | Sequence seq = column.getIdentityGenerator(); |
797 | assertNotNull("id column has sequence", seq); |
798 | |
799 | - AkibanInformationSchema copy = AISCloner.clone(ais()); |
800 | - copy.getUserTable(id).getColumn("id").setDefaultIdentity(false); |
801 | - runAlter(ChangeLevel.METADATA, C_NAME, copy.getUserTable(id), |
802 | - Arrays.asList(TableChange.createModify("id", "id")), Arrays.<TableChange>asList()); |
803 | + runAlter(ChangeLevel.METADATA, "ALTER TABLE c ALTER COLUMN id DROP DEFAULT"); |
804 | + assertNull("Old seq was dropped", ais().getSequence(seq.getSequenceName())); |
805 | |
806 | + runAlter(ChangeLevel.METADATA, "ALTER TABLE c ALTER COLUMN id SET GENERATED ALWAYS AS IDENTITY"); |
807 | Column newColumn = getUserTable(id).getColumn("id"); |
808 | assertEquals("altered is always", false, newColumn.getDefaultIdentity()); |
809 | + seq = newColumn.getIdentityGenerator(); |
810 | + assertEquals("Sequence name prefix", |
811 | + true, |
812 | + seq.getSequenceName().getTableName().startsWith(DefaultNameGenerator.IDENTITY_SEQUENCE_PREFIX)); |
813 | } |
814 | } |
815 | |
816 | === modified file 'src/test/java/com/akiban/sql/aisddl/AlterTableDDLTest.java' |
817 | --- src/test/java/com/akiban/sql/aisddl/AlterTableDDLTest.java 2013-03-22 20:05:57 +0000 |
818 | +++ src/test/java/com/akiban/sql/aisddl/AlterTableDDLTest.java 2013-04-15 20:33:27 +0000 |
819 | @@ -24,6 +24,7 @@ |
820 | import com.akiban.ais.model.IndexColumn; |
821 | import com.akiban.ais.model.Join; |
822 | import com.akiban.ais.model.JoinColumn; |
823 | +import com.akiban.ais.model.Sequence; |
824 | import com.akiban.ais.model.TableName; |
825 | import com.akiban.ais.model.UserTable; |
826 | import com.akiban.ais.model.aisb2.AISBBasedBuilder; |
827 | @@ -31,6 +32,8 @@ |
828 | import com.akiban.ais.util.TableChange; |
829 | import com.akiban.qp.operator.QueryContext; |
830 | import com.akiban.server.api.ddl.DDLFunctionsMockBase; |
831 | +import com.akiban.server.error.ColumnAlreadyGeneratedException; |
832 | +import com.akiban.server.error.ColumnNotGeneratedException; |
833 | import com.akiban.server.error.DuplicateColumnNameException; |
834 | import com.akiban.server.error.DuplicateIndexException; |
835 | import com.akiban.server.error.JoinColumnMismatchException; |
836 | @@ -42,6 +45,7 @@ |
837 | import com.akiban.server.error.NoSuchTableException; |
838 | import com.akiban.server.error.NoSuchUniqueException; |
839 | import com.akiban.server.error.UnsupportedCheckConstraintException; |
840 | +import com.akiban.server.error.UnsupportedSQLException; |
841 | import com.akiban.server.service.session.Session; |
842 | import com.akiban.server.types3.Types3Switch; |
843 | import com.akiban.sql.StandardException; |
844 | @@ -208,7 +212,7 @@ |
845 | expectColumnChanges("ADD:new"); |
846 | expectIndexChanges(); |
847 | if (Types3Switch.ON) { |
848 | - expectFinalTable(A_NAME, "aid MCOMPAT_ BIGINT(21) NOT NULL", "new MCOMPAT_ BIGINT(21) NOT NULL", "UNIQUE new(new)"); |
849 | + expectFinalTable(A_NAME, "aid MCOMPAT_ BIGINT(21) NOT NULL", "new MCOMPAT_ BIGINT(21) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)", "UNIQUE new(new)"); |
850 | } else { |
851 | expectFinalTable(A_NAME, "aid bigint NOT NULL", "new bigint NOT NULL", "UNIQUE new(new)"); |
852 | } |
853 | @@ -221,7 +225,7 @@ |
854 | expectColumnChanges("ADD:new"); |
855 | expectIndexChanges("ADD:PRIMARY"); |
856 | if (Types3Switch.ON) { |
857 | - expectFinalTable(A_NAME, "aid MCOMPAT_ BIGINT(21) NOT NULL", "new MCOMPAT_ BIGINT(21) NOT NULL", "UNIQUE new(new)", "PRIMARY(new)"); |
858 | + expectFinalTable(A_NAME, "aid MCOMPAT_ BIGINT(21) NOT NULL", "new MCOMPAT_ BIGINT(21) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1)", "UNIQUE new(new)", "PRIMARY(new)"); |
859 | } else { |
860 | expectFinalTable(A_NAME, "aid bigint NOT NULL", "new bigint NOT NULL", "UNIQUE new(new)", "PRIMARY(new)"); |
861 | } |
862 | @@ -540,6 +544,84 @@ |
863 | } |
864 | |
865 | // |
866 | + // ALTER COLUMN DROP DEFAULT (where default is generated) |
867 | + // |
868 | + @Test |
869 | + public void alterColumnDropDefaultGenerated() throws StandardException { |
870 | + buildCWithGeneratedID(1, true); |
871 | + parseAndRun("ALTER TABLE c ALTER COLUMN id DROP DEFAULT"); |
872 | + expectColumnChanges("MODIFY:id->id"); |
873 | + expectIndexChanges(); |
874 | + expectFinalTable(C_NAME, "id MCOMPAT_ INTEGER(11) NOT NULL", "PRIMARY(id)"); |
875 | + } |
876 | + |
877 | + // |
878 | + // ALTER COLUMN SET INCREMENT BY <number> |
879 | + // |
880 | + |
881 | + @Test |
882 | + public void alterColumnSetIncrementByLess() throws StandardException { |
883 | + buildCWithGeneratedID(1, true); |
884 | + parseAndRun("ALTER TABLE c ALTER COLUMN id SET INCREMENT BY -1"); |
885 | + expectColumnChanges("MODIFY:id->id"); |
886 | + expectIndexChanges(); |
887 | + expectFinalTable(C_NAME, "id MCOMPAT_ INTEGER(11) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY -1)", "PRIMARY(id)"); |
888 | + } |
889 | + |
890 | + @Test |
891 | + public void alterColumnSetIncrementByMore() throws StandardException { |
892 | + buildCWithGeneratedID(1, true); |
893 | + parseAndRun("ALTER TABLE c ALTER COLUMN id SET INCREMENT BY 5"); |
894 | + expectColumnChanges("MODIFY:id->id"); |
895 | + expectIndexChanges(); |
896 | + expectFinalTable(C_NAME, "id MCOMPAT_ INTEGER(11) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 5)", "PRIMARY(id)"); |
897 | + } |
898 | + |
899 | + @Test(expected=ColumnNotGeneratedException.class) |
900 | + public void alterColumnSetIncrementInvalid() throws StandardException { |
901 | + buildCWithID(); |
902 | + parseAndRun("ALTER TABLE c ALTER COLUMN id SET INCREMENT BY 5"); |
903 | + } |
904 | + |
905 | + // |
906 | + // ALTER COLUMN RESTART WITH <number> |
907 | + // |
908 | + |
909 | + @Test(expected=UnsupportedSQLException.class) |
910 | + public void alterColumnRestartWith() throws StandardException { |
911 | + buildCWithGeneratedID(1, true); |
912 | + parseAndRun("ALTER TABLE c ALTER COLUMN id RESTART WITH 10"); |
913 | + } |
914 | + |
915 | + // |
916 | + // ALTER COLUMN [SET] GENERATED <BY DEFAULT | ALWAYS> |
917 | + // |
918 | + |
919 | + @Test |
920 | + public void alterColumnSetGeneratedByDefault() throws StandardException { |
921 | + buildCWithID(); |
922 | + parseAndRun("ALTER TABLE c ALTER COLUMN id SET GENERATED BY DEFAULT AS IDENTITY (START WITH 10, INCREMENT BY 50)"); |
923 | + expectColumnChanges("MODIFY:id->id"); |
924 | + expectIndexChanges(); |
925 | + expectFinalTable(C_NAME, "id MCOMPAT_ INTEGER(11) NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 10, INCREMENT BY 50)", "PRIMARY(id)"); |
926 | + } |
927 | + |
928 | + @Test |
929 | + public void alterColumnSetGeneratedAlways() throws StandardException { |
930 | + buildCWithID(); |
931 | + parseAndRun("ALTER TABLE c ALTER COLUMN id SET GENERATED ALWAYS AS IDENTITY (START WITH 42, INCREMENT BY 100)"); |
932 | + expectColumnChanges("MODIFY:id->id"); |
933 | + expectIndexChanges(); |
934 | + expectFinalTable(C_NAME, "id MCOMPAT_ INTEGER(11) NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 42, INCREMENT BY 100)", "PRIMARY(id)"); |
935 | + } |
936 | + |
937 | + @Test(expected=ColumnAlreadyGeneratedException.class) |
938 | + public void alterColumnSetGeneratedAlreadyGenerated() throws StandardException { |
939 | + buildCWithGeneratedID(1, true); |
940 | + parseAndRun("ALTER TABLE c ALTER COLUMN id SET GENERATED ALWAYS AS IDENTITY (START WITH 42, INCREMENT BY 100)"); |
941 | + } |
942 | + |
943 | + // |
944 | // ADD [CONSTRAINT] UNIQUE |
945 | // |
946 | |
947 | @@ -1155,6 +1237,14 @@ |
948 | builder.userTable(A_NAME).colBigInt("id", false).colBigInt("other_id", true).pk("id"); |
949 | } |
950 | |
951 | + private void buildCWithGeneratedID(int startWith, boolean always) { |
952 | + builder.userTable(C_NAME).autoIncLong("id", startWith, always).pk("id"); |
953 | + } |
954 | + |
955 | + private void buildCWithID() { |
956 | + builder.userTable(C_NAME).colLong("id", false).pk("id"); |
957 | + } |
958 | + |
959 | private static class DDLFunctionsMock extends DDLFunctionsMockBase { |
960 | final AkibanInformationSchema ais; |
961 | final List<String> columnChangeDesc = new ArrayList<>(); |
962 | @@ -1212,6 +1302,17 @@ |
963 | sb.append(" DEFAULT "); |
964 | sb.append(defaultVal); |
965 | } |
966 | + Boolean identity = col.getDefaultIdentity(); |
967 | + if(identity != null) { |
968 | + Sequence seq = col.getIdentityGenerator(); |
969 | + sb.append(" GENERATED "); |
970 | + sb.append(identity ? "BY DEFAULT" : "ALWAYS"); |
971 | + sb.append(" AS IDENTITY (START WITH "); |
972 | + sb.append(seq.getStartsWith()); |
973 | + sb.append(", INCREMENT BY "); |
974 | + sb.append(seq.getIncrement()); |
975 | + sb.append(')'); |
976 | + } |
977 | } |
978 | for(Index index : table.getIndexes()) { |
979 | sb.append(", "); |
980 | |
981 | === modified file 'src/test/java/com/akiban/sql/aisddl/TableDDLIT.java' |
982 | --- src/test/java/com/akiban/sql/aisddl/TableDDLIT.java 2013-04-11 05:21:42 +0000 |
983 | +++ src/test/java/com/akiban/sql/aisddl/TableDDLIT.java 2013-04-15 20:33:27 +0000 |
984 | @@ -106,7 +106,7 @@ |
985 | assertNotNull(table); |
986 | assertEquals(table.getColumn(0).getType(), Types.INT); |
987 | assertEquals(table.getPrimaryKey().getColumns().get(0), table.getColumn(0)); |
988 | - assertEquals(1000L, table.getColumn(0).getInitialAutoIncrementValue().longValue()); |
989 | + assertEquals(1000L, table.getColumn(0).getIdentityGenerator().getStartsWith()); |
990 | } |
991 | |
992 | @Test |
993 | |
994 | === modified file 'src/test/resources/com/akiban/sql/pg/yaml/functional/test-identity.yaml' |
995 | --- src/test/resources/com/akiban/sql/pg/yaml/functional/test-identity.yaml 2012-09-26 03:50:12 +0000 |
996 | +++ src/test/resources/com/akiban/sql/pg/yaml/functional/test-identity.yaml 2013-04-15 20:33:27 +0000 |
997 | @@ -146,4 +146,17 @@ |
998 | --- |
999 | - Statement: select * from t |
1000 | - output: [[1, 1, null]] |
1001 | +--- |
1002 | +- DropTable: t |
1003 | + |
1004 | +--- |
1005 | +- CreateTable: t (id int not null primary key) |
1006 | +--- |
1007 | +- Statement: ALTER TABLE t ALTER COLUMN id SET GENERATED BY DEFAULT AS IDENTITY (START WITH 42, INCREMENT BY 5) |
1008 | +--- |
1009 | +- Statement: INSERT INTO t VALUES (NULL),(NULL),(NULL) |
1010 | +--- |
1011 | +- Statement: SELECT * FROM t |
1012 | +- output: [[42],[47],[52]] |
1013 | + |
1014 | ... |
Looks right and passes new tests. Is line 87 leftover from an earlier stage of tracking the change? newSequences doesn't seem to get used.