Merge lp:~nwilliams/akiban-server/alter-generated into lp:~akiban-technologies/akiban-server/trunk

Proposed by Nathan Williams
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
Reviewer Review Type Date Requested Status
Mike McMahon Approve
Review via email: mp+158990@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Mike McMahon (mmcm) wrote :

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.

review: Needs Information
2626. By Nathan Williams

Remove dead variable

Revision history for this message
Nathan Williams (nwilliams) wrote :

Indeed it was. Removed.

Revision history for this message
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.

review: Needs Information
Revision history for this message
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

Revision history for this message
Mike McMahon (mmcm) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 ...

Subscribers

People subscribed via source and target branches