private void checkDefaultReferencesTable(Expression defaultExpression) {
   if (defaultExpression == null) {
     return;
   }
   HashSet<DbObject> dependencies = New.hashSet();
   ExpressionVisitor visitor = ExpressionVisitor.getDependenciesVisitor(dependencies);
   defaultExpression.isEverything(visitor);
   if (dependencies.contains(table)) {
     throw DbException.get(ErrorCode.COLUMN_IS_REFERENCED_1, defaultExpression.getSQL());
   }
 }
Example #2
0
 private void generateColumnsFromQuery() {
   int columnCount = asQuery.getColumnCount();
   ArrayList<Expression> expressions = asQuery.getExpressions();
   for (int i = 0; i < columnCount; i++) {
     Expression expr = expressions.get(i);
     int type = expr.getType();
     String name = expr.getAlias();
     long precision = expr.getPrecision();
     int displaySize = expr.getDisplaySize();
     DataType dt = DataType.getDataType(type);
     if (precision > 0
         && (dt.defaultPrecision == 0
             || (dt.defaultPrecision > precision && dt.defaultPrecision < Byte.MAX_VALUE))) {
       // dont' set precision to MAX_VALUE if this is the default
       precision = dt.defaultPrecision;
     }
     int scale = expr.getScale();
     if (scale > 0
         && (dt.defaultScale == 0 || (dt.defaultScale > scale && dt.defaultScale < precision))) {
       scale = dt.defaultScale;
     }
     if (scale > precision) {
       precision = scale;
     }
     Column col = new Column(name, type, precision, scale, displaySize);
     addColumn(col);
   }
 }
Example #3
0
 private Long getLong(Expression expr) {
   if (expr == null) {
     return null;
   }
   return expr.optimize(session).getValue(session).getLong();
 }
 @Override
 public int update() {
   session.commit(true);
   Database db = session.getDatabase();
   session.getUser().checkRight(table, Right.ALL);
   table.checkSupportAlter();
   table.lock(session, true, true);
   Sequence sequence = oldColumn == null ? null : oldColumn.getSequence();
   if (newColumn != null) {
     checkDefaultReferencesTable((Expression) newColumn.getDefaultExpression());
   }
   if (columnsToAdd != null) {
     for (Column column : columnsToAdd) {
       checkDefaultReferencesTable((Expression) column.getDefaultExpression());
     }
   }
   switch (type) {
     case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL:
       {
         if (!oldColumn.isNullable()) {
           // no change
           break;
         }
         checkNoNullValues();
         oldColumn.setNullable(false);
         db.updateMeta(session, table);
         break;
       }
     case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL:
       {
         if (oldColumn.isNullable()) {
           // no change
           break;
         }
         checkNullable();
         oldColumn.setNullable(true);
         db.updateMeta(session, table);
         break;
       }
     case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT:
       {
         checkDefaultReferencesTable(defaultExpression);
         oldColumn.setSequence(null);
         oldColumn.setDefaultExpression(session, defaultExpression);
         removeSequence(sequence);
         db.updateMeta(session, table);
         break;
       }
     case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE:
       {
         // if the change is only increasing the precision, then we don't
         // need to copy the table because the length is only a constraint,
         // and does not affect the storage structure.
         if (oldColumn.isWideningConversion(newColumn)) {
           convertAutoIncrementColumn(newColumn);
           oldColumn.copy(newColumn);
           db.updateMeta(session, table);
         } else {
           oldColumn.setSequence(null);
           oldColumn.setDefaultExpression(session, null);
           oldColumn.setConvertNullToDefault(false);
           if (oldColumn.isNullable() && !newColumn.isNullable()) {
             checkNoNullValues();
           } else if (!oldColumn.isNullable() && newColumn.isNullable()) {
             checkNullable();
           }
           convertAutoIncrementColumn(newColumn);
           copyData();
         }
         break;
       }
     case CommandInterface.ALTER_TABLE_ADD_COLUMN:
       {
         // ifNotExists only supported for single column add
         if (ifNotExists
             && columnsToAdd.size() == 1
             && table.doesColumnExist(columnsToAdd.get(0).getName())) {
           break;
         }
         for (Column column : columnsToAdd) {
           if (column.isAutoIncrement()) {
             int objId = getObjectId();
             column.convertAutoIncrementToSequence(
                 session, getSchema(), objId, table.isTemporary());
           }
         }
         copyData();
         break;
       }
     case CommandInterface.ALTER_TABLE_DROP_COLUMN:
       {
         if (table.getColumns().length == 1) {
           throw DbException.get(ErrorCode.CANNOT_DROP_LAST_COLUMN, oldColumn.getSQL());
         }
         table.dropSingleColumnConstraintsAndIndexes(session, oldColumn);
         copyData();
         break;
       }
     case CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY:
       {
         int value = newSelectivity.optimize(session).getValue(session).getInt();
         oldColumn.setSelectivity(value);
         db.updateMeta(session, table);
         break;
       }
     default:
       DbException.throwInternalError("type=" + type);
   }
   return 0;
 }
  private Table cloneTableStructure(
      Column[] columns, Database db, String tempName, ArrayList<Column> newColumns) {
    for (Column col : columns) {
      newColumns.add(col.getClone());
    }
    if (type == CommandInterface.ALTER_TABLE_DROP_COLUMN) {
      int position = oldColumn.getColumnId();
      newColumns.remove(position);
    } else if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN) {
      int position;
      if (addBefore != null) {
        position = table.getColumn(addBefore).getColumnId();
      } else if (addAfter != null) {
        position = table.getColumn(addAfter).getColumnId() + 1;
      } else {
        position = columns.length;
      }
      for (Column column : columnsToAdd) {
        newColumns.add(position++, column);
      }
    } else if (type == CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE) {
      int position = oldColumn.getColumnId();
      newColumns.remove(position);
      newColumns.add(position, newColumn);
    }

    // create a table object in order to get the SQL statement
    // can't just use this table, because most column objects are 'shared'
    // with the old table
    // still need a new id because using 0 would mean: the new table tries
    // to use the rows of the table 0 (the meta table)
    int id = db.allocateObjectId();
    CreateTableData data = new CreateTableData();
    data.tableName = tempName;
    data.id = id;
    data.columns = newColumns;
    data.temporary = table.isTemporary();
    data.persistData = table.isPersistData();
    data.persistIndexes = table.isPersistIndexes();
    data.isHidden = table.isHidden();
    data.create = true;
    data.session = session;
    data.storageEngineName = table.getStorageEngineName();
    Table newTable = getSchema().createTable(data);
    newTable.setComment(table.getComment());
    StringBuilder buff = new StringBuilder();
    buff.append(newTable.getCreateSQL());

    if (table.supportsAlterColumnWithCopyData()) {
      StringBuilder columnList = new StringBuilder();
      for (Column nc : newColumns) {
        if (columnList.length() > 0) {
          columnList.append(", ");
        }
        if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN && columnsToAdd.contains(nc)) {
          Expression def = (Expression) nc.getDefaultExpression();
          columnList.append(def == null ? "NULL" : def.getSQL());
        } else {
          columnList.append(nc.getSQL());
        }
      }
      buff.append(" AS SELECT ");
      if (columnList.length() == 0) {
        // special case: insert into test select * from
        buff.append('*');
      } else {
        buff.append(columnList);
      }
      buff.append(" FROM ").append(table.getSQL());
    }
    String newTableSQL = buff.toString();
    String newTableName = newTable.getName();
    Schema newTableSchema = newTable.getSchema();
    newTable.removeChildrenAndResources(session);

    execute(newTableSQL, true);
    newTable = newTableSchema.getTableOrView(session, newTableName);
    ArrayList<String> triggers = New.arrayList();
    for (DbObject child : table.getChildren()) {
      if (child instanceof Sequence) {
        continue;
      } else if (child instanceof Index) {
        Index idx = (Index) child;
        if (idx.getIndexType().getBelongsToConstraint()) {
          continue;
        }
      }
      String createSQL = child.getCreateSQL();
      if (createSQL == null) {
        continue;
      }
      if (child instanceof TableView) {
        continue;
      } else if (child.getType() == DbObject.TABLE_OR_VIEW) {
        DbException.throwInternalError();
      }
      String quotedName = Parser.quoteIdentifier(tempName + "_" + child.getName());
      String sql = null;
      if (child instanceof ConstraintReferential) {
        ConstraintReferential r = (ConstraintReferential) child;
        if (r.getTable() != table) {
          sql = r.getCreateSQLForCopy(r.getTable(), newTable, quotedName, false);
        }
      }
      if (sql == null) {
        sql = child.getCreateSQLForCopy(newTable, quotedName);
      }
      if (sql != null) {
        if (child instanceof TriggerObject) {
          triggers.add(sql);
        } else {
          execute(sql, true);
        }
      }
    }
    table.setModified();
    // remove the sequences from the columns (except dropped columns)
    // otherwise the sequence is dropped if the table is dropped
    for (Column col : newColumns) {
      Sequence seq = col.getSequence();
      if (seq != null) {
        table.removeSequence(seq);
        col.setSequence(null);
      }
    }
    for (String sql : triggers) {
      execute(sql, true);
    }
    return newTable;
  }