private void copyData() {
   if (table.isTemporary()) {
     throw DbException.getUnsupportedException("TEMP TABLE");
   }
   Database db = session.getDatabase();
   String baseName = table.getName();
   String tempName = db.getTempTableName(baseName, session);
   Column[] columns = table.getColumns();
   ArrayList<Column> newColumns = New.arrayList();
   Table newTable = cloneTableStructure(columns, db, tempName, newColumns);
   try {
     // check if a view would become invalid
     // (because the column to drop is referenced or so)
     checkViews(table, newTable);
   } catch (DbException e) {
     execute("DROP TABLE " + newTable.getName(), true);
     throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, e, getSQL(), e.getMessage());
   }
   String tableName = table.getName();
   ArrayList<TableView> views = table.getViews();
   if (views != null) {
     views = New.arrayList(views);
     for (TableView view : views) {
       table.removeView(view);
     }
   }
   execute("DROP TABLE " + table.getSQL() + " IGNORE", true);
   db.renameSchemaObject(session, newTable, tableName);
   for (DbObject child : newTable.getChildren()) {
     if (child instanceof Sequence) {
       continue;
     }
     String name = child.getName();
     if (name == null || child.getCreateSQL() == null) {
       continue;
     }
     if (name.startsWith(tempName + "_")) {
       name = name.substring(tempName.length() + 1);
       SchemaObject so = (SchemaObject) child;
       if (so instanceof Constraint) {
         if (so.getSchema().findConstraint(session, name) != null) {
           name = so.getSchema().getUniqueConstraintName(session, newTable);
         }
       } else if (so instanceof Index) {
         if (so.getSchema().findIndex(session, name) != null) {
           name = so.getSchema().getUniqueIndexName(session, newTable, name);
         }
       }
       db.renameSchemaObject(session, so, name);
     }
   }
   if (views != null) {
     for (TableView view : views) {
       String sql = view.getCreateSQL(true, true);
       execute(sql, true);
     }
   }
 }
Exemple #2
0
 /**
  * Get all objects.
  *
  * @return a (possible empty) list of all objects
  */
 public ArrayList<SchemaObject> getAll() {
   ArrayList<SchemaObject> all = New.arrayList();
   all.addAll(getMap(DbObjectType.TABLE_OR_VIEW).values());
   all.addAll(getMap(DbObjectType.SEQUENCE).values());
   all.addAll(getMap(DbObjectType.INDEX).values());
   all.addAll(getMap(DbObjectType.TRIGGER).values());
   all.addAll(getMap(DbObjectType.CONSTRAINT).values());
   all.addAll(getMap(DbObjectType.CONSTANT).values());
   all.addAll(getMap(DbObjectType.FUNCTION_ALIAS).values());
   return all;
 }
Exemple #3
0
 @Override
 public void removeChildrenAndResources(ServerSession session) {
   while (triggers != null && triggers.size() > 0) {
     TriggerObject obj = (TriggerObject) triggers.values().toArray()[0];
     database.removeSchemaObject(session, obj);
   }
   while (constraints != null && constraints.size() > 0) {
     Constraint obj = (Constraint) constraints.values().toArray()[0];
     database.removeSchemaObject(session, obj);
   }
   // There can be dependencies between tables e.g. using computed columns,
   // so we might need to loop over them multiple times.
   boolean runLoopAgain = false;
   do {
     runLoopAgain = false;
     if (tablesAndViews != null) {
       // Loop over a copy because the map is modified underneath us.
       for (Table obj : New.arrayList(tablesAndViews.values())) {
         // Check for null because multiple tables might be deleted
         // in one go underneath us.
         if (obj.getName() != null) {
           if (database.getDependentTable(obj, obj) == null) {
             database.removeSchemaObject(session, obj);
           } else {
             runLoopAgain = true;
           }
         }
       }
     }
   } while (runLoopAgain);
   while (indexes != null && indexes.size() > 0) {
     Index obj = (Index) indexes.values().toArray()[0];
     database.removeSchemaObject(session, obj);
   }
   while (sequences != null && sequences.size() > 0) {
     Sequence obj = (Sequence) sequences.values().toArray()[0];
     database.removeSchemaObject(session, obj);
   }
   while (constants != null && constants.size() > 0) {
     Constant obj = (Constant) constants.values().toArray()[0];
     database.removeSchemaObject(session, obj);
   }
   while (functions != null && functions.size() > 0) {
     FunctionAlias obj = (FunctionAlias) functions.values().toArray()[0];
     database.removeSchemaObject(session, obj);
   }
   owner = null;
   super.removeChildrenAndResources(session);
 }
Exemple #4
0
  private ArrayList<BTreeChunk> compactGetOldChunks(int targetFillRate, int write) {
    if (lastChunk == null) {
      // nothing to do
      return null;
    }

    readAllChunks();

    // calculate the fill rate
    long maxLengthSum = 0;
    long maxLengthLiveSum = 0;

    long time = getTimeSinceCreation();

    for (BTreeChunk c : chunks.values()) {
      // ignore young chunks, because we don't optimize those
      if (c.time + retentionTime > time) {
        continue;
      }
      maxLengthSum += c.maxLen;
      maxLengthLiveSum += c.maxLenLive;
    }
    if (maxLengthLiveSum < 0) {
      // no old data
      return null;
    }
    // the fill rate of all chunks combined
    if (maxLengthSum <= 0) {
      // avoid division by 0
      maxLengthSum = 1;
    }
    int fillRate = (int) (100 * maxLengthLiveSum / maxLengthSum);
    if (fillRate >= targetFillRate) {
      return null;
    }

    // the 'old' list contains the chunks we want to free up
    ArrayList<BTreeChunk> old = New.arrayList();
    BTreeChunk last = chunks.get(lastChunk.id);
    for (BTreeChunk c : chunks.values()) {
      // only look at chunk older than the retention time
      // (it's possible to compact chunks earlier, but right
      // now we don't do that)
      if (c.time + retentionTime > time) {
        continue;
      }
      long age = last.version - c.version + 1;
      c.collectPriority = (int) (c.getFillRate() * 1000 / age);
      old.add(c);
    }
    if (old.size() == 0) {
      return null;
    }

    // sort the list, so the first entry should be collected first
    Collections.sort(
        old,
        new Comparator<BTreeChunk>() {

          @Override
          public int compare(BTreeChunk o1, BTreeChunk o2) {
            int comp = new Integer(o1.collectPriority).compareTo(o2.collectPriority);
            if (comp == 0) {
              comp = new Long(o1.maxLenLive).compareTo(o2.maxLenLive);
            }
            return comp;
          }
        });
    // find out up to were in the old list we need to move
    long written = 0;
    int chunkCount = 0;
    BTreeChunk move = null;
    for (BTreeChunk c : old) {
      if (move != null) {
        if (c.collectPriority > 0 && written > write) {
          break;
        }
      }
      written += c.maxLenLive;
      chunkCount++;
      move = c;
    }
    if (chunkCount < 1) {
      return null;
    }
    // remove the chunks we want to keep from this list
    boolean remove = false;
    for (Iterator<BTreeChunk> it = old.iterator(); it.hasNext(); ) {
      BTreeChunk c = it.next();
      if (move == c) {
        remove = true;
      } else if (remove) {
        it.remove();
      }
    }
    return old;
  }
Exemple #5
0
 /**
  * Get all tables and views.
  *
  * @return a (possible empty) list of all objects
  */
 public ArrayList<Table> getAllTablesAndViews() {
   synchronized (database) {
     return New.arrayList(tablesAndViews.values());
   }
 }
Exemple #6
0
 /**
  * Get all objects of the given type.
  *
  * @param type the object type
  * @return a (possible empty) list of all objects
  */
 public ArrayList<SchemaObject> getAll(DbObjectType type) {
   HashMap<String, SchemaObject> map = getMap(type);
   return New.arrayList(map.values());
 }
  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;
  }
Exemple #8
0
 @Override
 public int update() {
   if (!transactional) {
     session.commit(true);
   }
   Database db = session.getDatabase();
   if (!db.isPersistent()) {
     data.persistIndexes = false;
   }
   if (getSchema().findTableOrView(session, data.tableName) != null) {
     if (ifNotExists) {
       return 0;
     }
     throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.tableName);
   }
   if (asQuery != null) {
     asQuery.prepare();
     if (data.columns.isEmpty()) {
       generateColumnsFromQuery();
     } else if (data.columns.size() != asQuery.getColumnCount()) {
       throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
     }
   }
   if (pkColumns != null) {
     for (Column c : data.columns) {
       for (IndexColumn idxCol : pkColumns) {
         if (c.getName().equals(idxCol.columnName)) {
           c.setNullable(false);
         }
       }
     }
   }
   data.id = getObjectId();
   data.create = create;
   data.session = session;
   boolean isSessionTemporary = data.temporary && !data.globalTemporary;
   if (!isSessionTemporary) {
     db.lockMeta(session);
   }
   Table table = createTable(data);
   ArrayList<Sequence> sequences = New.arrayList();
   for (Column c : data.columns) {
     if (c.isAutoIncrement()) {
       int objId = getObjectId();
       c.convertAutoIncrementToSequence(session, getSchema(), objId, data.temporary);
     }
     Sequence seq = c.getSequence();
     if (seq != null) {
       sequences.add(seq);
     }
   }
   table.setComment(comment);
   if (isSessionTemporary) {
     if (onCommitDrop) {
       table.setOnCommitDrop(true);
     }
     if (onCommitTruncate) {
       table.setOnCommitTruncate(true);
     }
     session.addLocalTempTable(table);
   } else {
     db.lockMeta(session);
     db.addSchemaObject(session, table);
   }
   try {
     for (Column c : data.columns) {
       c.prepareExpression(session);
     }
     for (Sequence sequence : sequences) {
       table.addSequence(sequence);
     }
     for (DefineCommand command : constraintCommands) {
       command.setTransactional(transactional);
       command.update();
     }
     if (asQuery != null) {
       Insert insert = null;
       insert = new Insert(session);
       insert.setSortedInsertMode(sortedInsertMode);
       insert.setQuery(asQuery);
       insert.setTable(table);
       insert.setInsertFromSelect(true);
       insert.prepare();
       insert.update();
     }
   } catch (DbException e) {
     db.checkPowerOff();
     db.removeSchemaObject(session, table);
     if (!transactional) {
       session.commit(true);
     }
     throw e;
   }
   return 0;
 }
Exemple #9
0
/** This class represents the statement CREATE TABLE */
public class CreateTable extends SchemaCommand {

  protected final CreateTableData data = new CreateTableData();
  protected IndexColumn[] pkColumns;
  protected boolean ifNotExists;

  private final ArrayList<DefineCommand> constraintCommands = New.arrayList();
  private boolean onCommitDrop;
  private boolean onCommitTruncate;
  private Query asQuery;
  private String comment;
  private boolean sortedInsertMode;

  public CreateTable(Session session, Schema schema) {
    super(session, schema);
    data.persistIndexes = true;
    data.persistData = true;
  }

  public void setQuery(Query query) {
    this.asQuery = query;
  }

  public void setTemporary(boolean temporary) {
    data.temporary = temporary;
  }

  public void setTableName(String tableName) {
    data.tableName = tableName;
  }

  /**
   * Add a column to this table.
   *
   * @param column the column to add
   */
  public void addColumn(Column column) {
    data.columns.add(column);
  }

  /**
   * Add a constraint statement to this statement. The primary key definition is one possible
   * constraint statement.
   *
   * @param command the statement to add
   */
  public void addConstraintCommand(DefineCommand command) {
    if (command instanceof CreateIndex) {
      constraintCommands.add(command);
    } else {
      AlterTableAddConstraint con = (AlterTableAddConstraint) command;
      boolean alreadySet;
      if (con.getType() == CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY) {
        alreadySet = setPrimaryKeyColumns(con.getIndexColumns());
      } else {
        alreadySet = false;
      }
      if (!alreadySet) {
        constraintCommands.add(command);
      }
    }
  }

  public void setIfNotExists(boolean ifNotExists) {
    this.ifNotExists = ifNotExists;
  }

  @Override
  public int update() {
    if (!transactional) {
      session.commit(true);
    }
    Database db = session.getDatabase();
    if (!db.isPersistent()) {
      data.persistIndexes = false;
    }
    if (getSchema().findTableOrView(session, data.tableName) != null) {
      if (ifNotExists) {
        return 0;
      }
      throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.tableName);
    }
    if (asQuery != null) {
      asQuery.prepare();
      if (data.columns.isEmpty()) {
        generateColumnsFromQuery();
      } else if (data.columns.size() != asQuery.getColumnCount()) {
        throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
      }
    }
    if (pkColumns != null) {
      for (Column c : data.columns) {
        for (IndexColumn idxCol : pkColumns) {
          if (c.getName().equals(idxCol.columnName)) {
            c.setNullable(false);
          }
        }
      }
    }
    data.id = getObjectId();
    data.create = create;
    data.session = session;
    boolean isSessionTemporary = data.temporary && !data.globalTemporary;
    if (!isSessionTemporary) {
      db.lockMeta(session);
    }
    Table table = createTable(data);
    ArrayList<Sequence> sequences = New.arrayList();
    for (Column c : data.columns) {
      if (c.isAutoIncrement()) {
        int objId = getObjectId();
        c.convertAutoIncrementToSequence(session, getSchema(), objId, data.temporary);
      }
      Sequence seq = c.getSequence();
      if (seq != null) {
        sequences.add(seq);
      }
    }
    table.setComment(comment);
    if (isSessionTemporary) {
      if (onCommitDrop) {
        table.setOnCommitDrop(true);
      }
      if (onCommitTruncate) {
        table.setOnCommitTruncate(true);
      }
      session.addLocalTempTable(table);
    } else {
      db.lockMeta(session);
      db.addSchemaObject(session, table);
    }
    try {
      for (Column c : data.columns) {
        c.prepareExpression(session);
      }
      for (Sequence sequence : sequences) {
        table.addSequence(sequence);
      }
      for (DefineCommand command : constraintCommands) {
        command.setTransactional(transactional);
        command.update();
      }
      if (asQuery != null) {
        Insert insert = null;
        insert = new Insert(session);
        insert.setSortedInsertMode(sortedInsertMode);
        insert.setQuery(asQuery);
        insert.setTable(table);
        insert.setInsertFromSelect(true);
        insert.prepare();
        insert.update();
      }
    } catch (DbException e) {
      db.checkPowerOff();
      db.removeSchemaObject(session, table);
      if (!transactional) {
        session.commit(true);
      }
      throw e;
    }
    return 0;
  }

  protected Table createTable(CreateTableData data) {
    return getSchema().createTable(data);
  }

  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);
    }
  }

  /**
   * Sets the primary key columns, but also check if a primary key with different columns is already
   * defined.
   *
   * @param columns the primary key columns
   * @return true if the same primary key columns where already set
   */
  private boolean setPrimaryKeyColumns(IndexColumn[] columns) {
    if (pkColumns != null) {
      int len = columns.length;
      if (len != pkColumns.length) {
        throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY);
      }
      for (int i = 0; i < len; i++) {
        if (!columns[i].columnName.equals(pkColumns[i].columnName)) {
          throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY);
        }
      }
      return true;
    }
    this.pkColumns = columns;
    return false;
  }

  public void setPersistIndexes(boolean persistIndexes) {
    data.persistIndexes = persistIndexes;
  }

  public void setGlobalTemporary(boolean globalTemporary) {
    data.globalTemporary = globalTemporary;
  }

  /** This temporary table is dropped on commit. */
  public void setOnCommitDrop() {
    this.onCommitDrop = true;
  }

  /** This temporary table is truncated on commit. */
  public void setOnCommitTruncate() {
    this.onCommitTruncate = true;
  }

  public void setComment(String comment) {
    this.comment = comment;
  }

  public void setPersistData(boolean persistData) {
    data.persistData = persistData;
    if (!persistData) {
      data.persistIndexes = false;
    }
  }

  public void setSortedInsertMode(boolean sortedInsertMode) {
    this.sortedInsertMode = sortedInsertMode;
  }

  public void setStorageEngine(String storageEngine) {
    data.storageEngine = storageEngine;
  }

  public void setHidden(boolean isHidden) {
    data.isHidden = isHidden;
  }

  @Override
  public int getType() {
    return CommandInterface.CREATE_TABLE;
  }
}