public PColumn newColumn(int position, ColumnDef def, PrimaryKeyConstraint pkConstraint) throws SQLException { try { Set<String> pkColumnNames = pkConstraint == null ? Collections.<String>emptySet() : pkConstraint.getColumnNames(); String columnName = def.getColumnDefName().getColumnName().getName(); PName familyName = null; if (def.isPK() && !pkColumnNames.isEmpty()) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_ALREADY_EXISTS) .setColumnName(columnName) .build() .buildException(); } boolean isPK = def.isPK() || pkColumnNames.contains(columnName); if (def.getColumnDefName().getFamilyName() != null) { String family = def.getColumnDefName().getFamilyName().getName(); if (isPK) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_WITH_FAMILY_NAME) .setColumnName(columnName) .setFamilyName(family) .build() .buildException(); } else if (!def.isNull()) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.KEY_VALUE_NOT_NULL) .setColumnName(columnName) .setFamilyName(family) .build() .buildException(); } familyName = new PNameImpl(family); } else if (!isPK) { familyName = QueryConstants.DEFAULT_COLUMN_FAMILY_NAME; } ColumnModifier columnModifier = def.getColumnModifier(); if (pkConstraint != null && pkConstraint.getColumnModifier(columnName) != null) { columnModifier = pkConstraint.getColumnModifier(columnName); } PColumn column = new PColumnImpl( new PNameImpl(columnName), familyName, def.getDataType(), def.getMaxLength(), def.getScale(), def.isNull(), position, columnModifier); return column; } catch (IllegalArgumentException e) { // Based on precondition check in constructor throw new SQLException(e); } }
public MutationState addColumn(AddColumnStatement statement) throws SQLException { connection.rollback(); boolean wasAutoCommit = connection.getAutoCommit(); try { connection.setAutoCommit(false); TableName tableNameNode = statement.getTableName(); String schemaName = tableNameNode.getSchemaName(); String tableName = tableNameNode.getTableName(); PTable table = getLatestTable(schemaName, tableName); PSchema schema = connection.getPMetaData().getSchema(schemaName); boolean retried = false; while (true) { int ordinalPosition = table.getColumns().size(); // TODO: disallow adding columns if last column is fixed width and nullable List<PColumn> columns = Lists.newArrayListWithExpectedSize(1); ColumnDef colDef = statement.getColumnDef(); if (!colDef.isNull() && colDef.isPK()) { throw new SQLExceptionInfo.Builder(SQLExceptionCode.NOT_NULLABLE_COLUMN_IN_ROW_KEY) .setColumnName(colDef.getColumnDefName().getColumnName().getName()) .build() .buildException(); } PreparedStatement colUpsert = connection.prepareStatement(INSERT_COLUMN); Pair<byte[], Map<String, Object>> family = null; PColumn column = newColumn(ordinalPosition++, colDef, null); addColumnMutation(schemaName, tableName, column, colUpsert); columns.add(column); if (column.getFamilyName() != null) { family = new Pair<byte[], Map<String, Object>>( column.getFamilyName().getBytes(), statement.getProps()); } final long seqNum = table.getSequenceNumber() + 1; PreparedStatement tableUpsert = connection.prepareStatement(MUTATE_TABLE); tableUpsert.setString(1, schemaName); tableUpsert.setString(2, tableName); tableUpsert.setString(3, table.getType().getSerializedValue()); tableUpsert.setLong(4, seqNum); tableUpsert.setInt(5, ordinalPosition); tableUpsert.execute(); final List<Mutation> tableMetaData = connection.getMutationState().toMutations(); connection.rollback(); byte[] emptyCF = null; if (table.getType() != PTableType.VIEW && family != null && table.getColumnFamilies().isEmpty()) { emptyCF = family.getFirst(); } MetaDataMutationResult result = connection .getQueryServices() .addColumn(tableMetaData, table.getType() == PTableType.VIEW, family); try { MutationCode code = processMutationResult(schemaName, tableName, result); if (code == MutationCode.COLUMN_ALREADY_EXISTS) { connection.addTable(schemaName, result.getTable()); if (!statement.ifNotExists()) { throw new ColumnAlreadyExistsException( schemaName, tableName, SchemaUtil.findExistingColumn(result.getTable(), columns)); } return new MutationState(0, connection); } connection.addColumn(schemaName, tableName, columns, seqNum, result.getMutationTime()); if (emptyCF != null) { Long scn = connection.getSCN(); connection.setAutoCommit(true); // Delete everything in the column. You'll still be able to do queries at earlier // timestamps long ts = (scn == null ? result.getMutationTime() : scn); TableRef tableRef = new TableRef(null, table, schema, ts); MutationPlan plan = new PostDDLCompiler(connection).compile(tableRef, emptyCF, null, ts); return connection.getQueryServices().updateData(plan); } return new MutationState(0, connection); } catch (ConcurrentTableMutationException e) { if (retried) { throw e; } table = connection.getPMetaData().getSchema(schemaName).getTable(tableName); retried = true; } } } finally { connection.setAutoCommit(wasAutoCommit); } }