Beispiel #1
0
 private static void registerDefaultProviders() {
   if (providers == null || defaultProvider == null) {
     // 不使用硬编码包名字符串的方式,重命名包名时常常忘记
     String packageName = FilePath.class.getPackage().getName() + ".";
     Map<String, FilePath> map = Collections.synchronizedMap(New.<String, FilePath>hashMap());
     for (String c :
         new String[] {
           "FilePathDisk",
           "FilePathMem",
           "FilePathMemLZF",
           "FilePathNioMem",
           "FilePathNioMemLZF",
           "FilePathSplit",
           "FilePathNio",
           "FilePathNioMapped",
           "FilePathZip"
         }) {
       try {
         FilePath p = (FilePath) Class.forName(packageName + c).newInstance();
         map.put(p.getScheme(), p);
         if (defaultProvider == null) {
           defaultProvider = p;
         }
       } catch (Exception e) {
         // ignore - the files may be excluded in purpose
       }
     }
     providers = map;
   }
 }
Beispiel #2
0
 public ArrayList<DbObject> getChildren() {
   ArrayList<DbObject> children = New.arrayList();
   ArrayList<Index> indexes = getIndexes();
   if (indexes != null) {
     children.addAll(indexes);
   }
   if (constraints != null) {
     children.addAll(constraints);
   }
   if (triggers != null) {
     children.addAll(triggers);
   }
   if (sequences != null) {
     children.addAll(sequences);
   }
   if (views != null) {
     children.addAll(views);
   }
   ArrayList<Right> rights = database.getAllRights();
   for (Right right : rights) {
     if (right.getGrantedTable() == this) {
       children.add(right);
     }
   }
   return children;
 }
Beispiel #3
0
 private static <T> ArrayList<T> add(ArrayList<T> list, T obj) {
   if (list == null) {
     list = New.arrayList();
   }
   // self constraints are two entries in the list
   list.add(obj);
   return list;
 }
Beispiel #4
0
 /**
  * Check that this column is not referenced by a multi-column constraint or multi-column index. If
  * it is, an exception is thrown. Single-column references and indexes are dropped.
  *
  * @param session the session
  * @param col the column
  * @throws DbException if the column is referenced by multi-column constraints or indexes
  */
 public void dropSingleColumnConstraintsAndIndexes(Session session, Column col) {
   ArrayList<Constraint> constraintsToDrop = New.arrayList();
   if (constraints != null) {
     for (int i = 0, size = constraints.size(); i < size; i++) {
       Constraint constraint = constraints.get(i);
       HashSet<Column> columns = constraint.getReferencedColumns(this);
       if (!columns.contains(col)) {
         continue;
       }
       if (columns.size() == 1) {
         constraintsToDrop.add(constraint);
       } else {
         throw DbException.get(ErrorCode.COLUMN_IS_REFERENCED_1, constraint.getSQL());
       }
     }
   }
   ArrayList<Index> indexesToDrop = New.arrayList();
   ArrayList<Index> indexes = getIndexes();
   if (indexes != null) {
     for (int i = 0, size = indexes.size(); i < size; i++) {
       Index index = indexes.get(i);
       if (index.getCreateSQL() == null) {
         continue;
       }
       if (index.getColumnIndex(col) < 0) {
         continue;
       }
       if (index.getColumns().length == 1) {
         indexesToDrop.add(index);
       } else {
         throw DbException.get(ErrorCode.COLUMN_IS_REFERENCED_1, index.getSQL());
       }
     }
   }
   for (Constraint c : constraintsToDrop) {
     session.getDatabase().removeSchemaObject(session, c);
   }
   for (Index i : indexesToDrop) {
     // the index may already have been dropped when dropping the constraint
     if (getIndexes().contains(i)) {
       session.getDatabase().removeSchemaObject(session, i);
     }
   }
 }
 private static boolean canUseUniqueIndex(Index idx, Table table, IndexColumn[] cols) {
   if (idx.getTable() != table || !idx.getIndexType().isUnique()) {
     return false;
   }
   Column[] indexCols = idx.getColumns();
   if (indexCols.length > cols.length) {
     return false;
   }
   HashSet<Column> set = New.hashSet();
   for (IndexColumn c : cols) {
     set.add(c.column);
   }
   for (Column c : indexCols) {
     // all columns of the index must be part of the list,
     // but not all columns of the list need to be part of the index
     if (!set.contains(c)) {
       return false;
     }
   }
   return true;
 }
Beispiel #6
0
/** This class represents the statement MERGE */
public class Merge extends Prepared {

  protected Table table;
  protected Column[] columns;
  protected Column[] keys;
  protected final ArrayList<Expression[]> list = New.arrayList();
  protected Query query;
  protected Prepared update;

  public Merge(Session session) {
    super(session);
  }

  public void setCommand(Command command) {
    super.setCommand(command);
    if (query != null) {
      query.setCommand(command);
    }
  }

  public void setTable(Table table) {
    this.table = table;
  }

  public void setColumns(Column[] columns) {
    this.columns = columns;
  }

  public void setKeys(Column[] keys) {
    this.keys = keys;
  }

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

  /**
   * Add a row to this merge statement.
   *
   * @param expr the list of values
   */
  public void addRow(Expression[] expr) {
    list.add(expr);
  }

  public int update() {
    int count;
    session.getUser().checkRight(table, Right.INSERT);
    session.getUser().checkRight(table, Right.UPDATE);
    setCurrentRowNumber(0);
    if (list.size() > 0) {
      count = 0;
      for (int x = 0, size = list.size(); x < size; x++) {
        Expression[] expr = list.get(x);
        Row newRow;
        try {
          newRow = createRow(expr, x);
          if (newRow == null) {
            continue;
          }
        } catch (DbException ex) {
          throw setRow(ex, count + 1, getSQL(expr));
        }
        setCurrentRowNumber(++count);
        merge(newRow);
      }
    } else {
      ResultInterface rows = query.query(0);
      count = 0;
      table.fire(session, Trigger.UPDATE | Trigger.INSERT, true);
      table.lock(session, true, false);
      while (rows.next()) {
        Value[] values = rows.currentRow();
        Row newRow;
        try {
          newRow = createRow(values);
          if (newRow == null) {
            continue;
          }
        } catch (DbException ex) {
          throw setRow(ex, count + 1, getSQL(values));
        }
        setCurrentRowNumber(++count);
        merge(newRow);
      }
      rows.close();
      table.fire(session, Trigger.UPDATE | Trigger.INSERT, false);
    }
    return count;
  }

  protected Row createRow(Expression[] expr, int rowId) {
    Row newRow = table.getTemplateRow();
    for (int i = 0, len = columns.length; i < len; i++) {
      Column c = columns[i];
      int index = c.getColumnId();
      Expression e = expr[i];
      if (e != null) {
        // e can be null (DEFAULT)
        try {
          Value v = c.convert(e.getValue(session));
          newRow.setValue(index, v);
        } catch (DbException ex) {
          throw setRow(ex, rowId, getSQL(expr));
        }
      }
    }
    return newRow;
  }

  protected Row createRow(Value[] values) {
    Row newRow = table.getTemplateRow();
    for (int j = 0; j < columns.length; j++) {
      Column c = columns[j];
      int index = c.getColumnId();
      Value v = c.convert(values[j]);
      newRow.setValue(index, v);
    }
    return newRow;
  }

  private void merge(Row row) {
    ArrayList<Parameter> k = update.getParameters();
    for (int i = 0; i < columns.length; i++) {
      Column col = columns[i];
      Value v = row.getValue(col.getColumnId());
      Parameter p = k.get(i);
      p.setValue(v);
    }
    for (int i = 0; i < keys.length; i++) {
      Column col = keys[i];
      Value v = row.getValue(col.getColumnId());
      if (v == null) {
        throw DbException.get(ErrorCode.COLUMN_CONTAINS_NULL_VALUES_1, col.getSQL());
      }
      Parameter p = k.get(columns.length + i);
      p.setValue(v);
    }
    int count = update.update();
    if (count == 0) {
      try {
        table.validateConvertUpdateSequence(session, row);
        boolean done = table.fireBeforeRow(session, null, row);
        if (!done) {
          table.lock(session, true, false);
          table.addRow(session, row);
          session.log(table, UndoLogRecord.INSERT, row);
          table.fireAfterRow(session, null, row, false);
        }
      } catch (DbException e) {
        if (e.getErrorCode() == ErrorCode.DUPLICATE_KEY_1) {
          // possibly a concurrent merge or insert
          Index index = (Index) e.getSource();
          if (index != null) {
            // verify the index columns match the key
            Column[] indexColumns = index.getColumns();
            boolean indexMatchesKeys = false;
            if (indexColumns.length <= keys.length) {
              for (int i = 0; i < indexColumns.length; i++) {
                if (indexColumns[i] != keys[i]) {
                  indexMatchesKeys = false;
                  break;
                }
              }
            }
            if (indexMatchesKeys) {
              throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, table.getName());
            }
          }
        }
        throw e;
      }
    } else if (count != 1) {
      throw DbException.get(ErrorCode.DUPLICATE_KEY_1, table.getSQL());
    }
  }

  public String getPlanSQL() {
    StatementBuilder buff = new StatementBuilder("MERGE INTO ");
    buff.append(table.getSQL()).append('(');
    for (Column c : columns) {
      buff.appendExceptFirst(", ");
      buff.append(c.getSQL());
    }
    buff.append(')');
    if (keys != null) {
      buff.append(" KEY(");
      buff.resetCount();
      for (Column c : keys) {
        buff.appendExceptFirst(", ");
        buff.append(c.getSQL());
      }
      buff.append(')');
    }
    buff.append('\n');
    if (list.size() > 0) {
      buff.append("VALUES ");
      int row = 0;
      for (Expression[] expr : list) {
        if (row++ > 0) {
          buff.append(", ");
        }
        buff.append('(');
        buff.resetCount();
        for (Expression e : expr) {
          buff.appendExceptFirst(", ");
          if (e == null) {
            buff.append("DEFAULT");
          } else {
            buff.append(e.getSQL());
          }
        }
        buff.append(')');
      }
    } else {
      buff.append(query.getPlanSQL());
    }
    return buff.toString();
  }

  public void prepare() {
    if (columns == null) {
      if (list.size() > 0 && list.get(0).length == 0) {
        // special case where table is used as a sequence
        columns = new Column[0];
      } else {
        columns = table.getColumns();
      }
    }
    if (list.size() > 0) {
      for (Expression[] expr : list) {
        if (expr.length != columns.length) {
          throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
        }
        for (int i = 0; i < expr.length; i++) {
          Expression e = expr[i];
          if (e != null) {
            expr[i] = e.optimize(session);
          }
        }
      }
    } else {
      query.prepare();
      if (query.getColumnCount() != columns.length) {
        throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
      }
    }
    if (keys == null) {
      Index idx = table.getPrimaryKey();
      if (idx == null) {
        throw DbException.get(ErrorCode.CONSTRAINT_NOT_FOUND_1, "PRIMARY KEY");
      }
      keys = idx.getColumns();
    }
    StatementBuilder buff = new StatementBuilder("UPDATE ");
    buff.append(table.getSQL()).append(" SET ");
    for (Column c : columns) {
      buff.appendExceptFirst(", ");
      buff.append(c.getSQL()).append("=?");
    }
    buff.append(" WHERE ");
    buff.resetCount();
    for (Column c : keys) {
      buff.appendExceptFirst(" AND ");
      buff.append(c.getSQL()).append("=?");
    }
    String sql = buff.toString();
    update = session.prepare(sql);
  }

  public boolean isTransactional() {
    return true;
  }

  public ResultInterface queryMeta() {
    return null;
  }

  public int getType() {
    return CommandInterface.MERGE;
  }

  public boolean isCacheable() {
    return true;
  }
}
Beispiel #7
0
 public ArrayList<CacheObject> getAllChanged() {
   ArrayList<CacheObject> changed = New.arrayList();
   changed.addAll(lru.getAllChanged());
   changed.addAll(fifo.getAllChanged());
   return changed;
 }
/** This class represents the statement ALTER TABLE ADD CONSTRAINT */
public class AlterTableAddConstraint extends SchemaCommand {

  private int type;
  private String constraintName;
  private String tableName;
  private IndexColumn[] indexColumns;
  private int deleteAction;
  private int updateAction;
  private Schema refSchema;
  private String refTableName;
  private IndexColumn[] refIndexColumns;
  private Expression checkExpression;
  private Index index, refIndex;
  private String comment;
  private boolean checkExisting;
  private boolean primaryKeyHash;
  private final boolean ifNotExists;
  private final ArrayList<Index> createdIndexes = New.arrayList();

  public AlterTableAddConstraint(Session session, Schema schema, boolean ifNotExists) {
    super(session, schema);
    this.ifNotExists = ifNotExists;
  }

  private String generateConstraintName(Table table) {
    if (constraintName == null) {
      constraintName = getSchema().getUniqueConstraintName(session, table);
    }
    return constraintName;
  }

  @Override
  public int update() {
    try {
      return tryUpdate();
    } catch (DbException e) {
      for (Index index : createdIndexes) {
        session.getDatabase().removeSchemaObject(session, index);
      }
      throw e;
    } finally {
      getSchema().freeUniqueName(constraintName);
    }
  }

  /**
   * Try to execute the statement.
   *
   * @return the update count
   */
  private int tryUpdate() {
    if (!transactional) {
      session.commit(true);
    }
    Database db = session.getDatabase();
    Table table = getSchema().getTableOrView(session, tableName);
    if (getSchema().findConstraint(session, constraintName) != null) {
      if (ifNotExists) {
        return 0;
      }
      throw DbException.get(ErrorCode.CONSTRAINT_ALREADY_EXISTS_1, constraintName);
    }
    session.getUser().checkRight(table, Right.ALL);
    db.lockMeta(session);
    table.lock(session, true, true);
    Constraint constraint;
    switch (type) {
      case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_PRIMARY_KEY:
        {
          IndexColumn.mapColumns(indexColumns, table);
          index = table.findPrimaryKey();
          ArrayList<Constraint> constraints = table.getConstraints();
          for (int i = 0; constraints != null && i < constraints.size(); i++) {
            Constraint c = constraints.get(i);
            if (Constraint.PRIMARY_KEY.equals(c.getConstraintType())) {
              throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY);
            }
          }
          if (index != null) {
            // if there is an index, it must match with the one declared
            // we don't test ascending / descending
            IndexColumn[] pkCols = index.getIndexColumns();
            if (pkCols.length != indexColumns.length) {
              throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY);
            }
            for (int i = 0; i < pkCols.length; i++) {
              if (pkCols[i].column != indexColumns[i].column) {
                throw DbException.get(ErrorCode.SECOND_PRIMARY_KEY);
              }
            }
          }
          if (index == null) {
            IndexType indexType =
                IndexType.createPrimaryKey(table.isPersistIndexes(), primaryKeyHash);
            String indexName =
                table.getSchema().getUniqueIndexName(session, table, Constants.PREFIX_PRIMARY_KEY);
            int id = getObjectId();
            try {
              index = table.addIndex(session, indexName, id, indexColumns, indexType, true, null);
            } finally {
              getSchema().freeUniqueName(indexName);
            }
          }
          index.getIndexType().setBelongsToConstraint(true);
          int constraintId = getObjectId();
          String name = generateConstraintName(table);
          ConstraintUnique pk = new ConstraintUnique(getSchema(), constraintId, name, table, true);
          pk.setColumns(indexColumns);
          pk.setIndex(index, true);
          constraint = pk;
          break;
        }
      case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_UNIQUE:
        {
          IndexColumn.mapColumns(indexColumns, table);
          boolean isOwner = false;
          if (index != null && canUseUniqueIndex(index, table, indexColumns)) {
            isOwner = true;
            index.getIndexType().setBelongsToConstraint(true);
          } else {
            index = getUniqueIndex(table, indexColumns);
            if (index == null) {
              index = createIndex(table, indexColumns, true);
              isOwner = true;
            }
          }
          int id = getObjectId();
          String name = generateConstraintName(table);
          ConstraintUnique unique = new ConstraintUnique(getSchema(), id, name, table, false);
          unique.setColumns(indexColumns);
          unique.setIndex(index, isOwner);
          constraint = unique;
          break;
        }
      case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_CHECK:
        {
          int id = getObjectId();
          String name = generateConstraintName(table);
          ConstraintCheck check = new ConstraintCheck(getSchema(), id, name, table);
          TableFilter filter = new TableFilter(session, table, null, false, null);
          checkExpression.mapColumns(filter, 0);
          checkExpression = checkExpression.optimize(session);
          check.setExpression(checkExpression);
          check.setTableFilter(filter);
          constraint = check;
          if (checkExisting) {
            check.checkExistingData(session);
          }
          break;
        }
      case CommandInterface.ALTER_TABLE_ADD_CONSTRAINT_REFERENTIAL:
        {
          Table refTable = refSchema.getTableOrView(session, refTableName);
          session.getUser().checkRight(refTable, Right.ALL);
          if (!refTable.canReference()) {
            throw DbException.getUnsupportedException("Reference " + refTable.getSQL());
          }
          boolean isOwner = false;
          IndexColumn.mapColumns(indexColumns, table);
          if (index != null && canUseIndex(index, table, indexColumns, false)) {
            isOwner = true;
            index.getIndexType().setBelongsToConstraint(true);
          } else {
            index = getIndex(table, indexColumns, true);
            if (index == null) {
              index = createIndex(table, indexColumns, false);
              isOwner = true;
            }
          }
          if (refIndexColumns == null) {
            Index refIdx = refTable.getPrimaryKey();
            refIndexColumns = refIdx.getIndexColumns();
          } else {
            IndexColumn.mapColumns(refIndexColumns, refTable);
          }
          if (refIndexColumns.length != indexColumns.length) {
            throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
          }
          boolean isRefOwner = false;
          if (refIndex != null
              && refIndex.getTable() == refTable
              && canUseIndex(refIndex, refTable, refIndexColumns, false)) {
            isRefOwner = true;
            refIndex.getIndexType().setBelongsToConstraint(true);
          } else {
            refIndex = null;
          }
          if (refIndex == null) {
            refIndex = getIndex(refTable, refIndexColumns, false);
            if (refIndex == null) {
              refIndex = createIndex(refTable, refIndexColumns, true);
              isRefOwner = true;
            }
          }
          int id = getObjectId();
          String name = generateConstraintName(table);
          ConstraintReferential ref = new ConstraintReferential(getSchema(), id, name, table);
          ref.setColumns(indexColumns);
          ref.setIndex(index, isOwner);
          ref.setRefTable(refTable);
          ref.setRefColumns(refIndexColumns);
          ref.setRefIndex(refIndex, isRefOwner);
          if (checkExisting) {
            ref.checkExistingData(session);
          }
          constraint = ref;
          refTable.addConstraint(constraint);
          ref.setDeleteAction(deleteAction);
          ref.setUpdateAction(updateAction);
          break;
        }
      default:
        throw DbException.throwInternalError("type=" + type);
    }
    // parent relationship is already set with addConstraint
    constraint.setComment(comment);
    if (table.isTemporary() && !table.isGlobalTemporary()) {
      session.addLocalTempTableConstraint(constraint);
    } else {
      db.addSchemaObject(session, constraint);
    }
    table.addConstraint(constraint);
    return 0;
  }

  private Index createIndex(Table t, IndexColumn[] cols, boolean unique) {
    int indexId = getObjectId();
    IndexType indexType;
    if (unique) {
      // for unique constraints
      indexType = IndexType.createUnique(t.isPersistIndexes(), false);
    } else {
      // constraints
      indexType = IndexType.createNonUnique(t.isPersistIndexes());
    }
    indexType.setBelongsToConstraint(true);
    String prefix = constraintName == null ? "CONSTRAINT" : constraintName;
    String indexName = t.getSchema().getUniqueIndexName(session, t, prefix + "_INDEX_");
    try {
      Index index = t.addIndex(session, indexName, indexId, cols, indexType, true, null);
      createdIndexes.add(index);
      return index;
    } finally {
      getSchema().freeUniqueName(indexName);
    }
  }

  public void setDeleteAction(int action) {
    this.deleteAction = action;
  }

  public void setUpdateAction(int action) {
    this.updateAction = action;
  }

  private static Index getUniqueIndex(Table t, IndexColumn[] cols) {
    for (Index idx : t.getIndexes()) {
      if (canUseUniqueIndex(idx, t, cols)) {
        return idx;
      }
    }
    return null;
  }

  private static Index getIndex(Table t, IndexColumn[] cols, boolean moreColumnOk) {
    for (Index idx : t.getIndexes()) {
      if (canUseIndex(idx, t, cols, moreColumnOk)) {
        return idx;
      }
    }
    return null;
  }

  private static boolean canUseUniqueIndex(Index idx, Table table, IndexColumn[] cols) {
    if (idx.getTable() != table || !idx.getIndexType().isUnique()) {
      return false;
    }
    Column[] indexCols = idx.getColumns();
    if (indexCols.length > cols.length) {
      return false;
    }
    HashSet<Column> set = New.hashSet();
    for (IndexColumn c : cols) {
      set.add(c.column);
    }
    for (Column c : indexCols) {
      // all columns of the index must be part of the list,
      // but not all columns of the list need to be part of the index
      if (!set.contains(c)) {
        return false;
      }
    }
    return true;
  }

  private static boolean canUseIndex(
      Index existingIndex, Table table, IndexColumn[] cols, boolean moreColumnsOk) {
    if (existingIndex.getTable() != table || existingIndex.getCreateSQL() == null) {
      // can't use the scan index or index of another table
      return false;
    }
    Column[] indexCols = existingIndex.getColumns();

    if (moreColumnsOk) {
      if (indexCols.length < cols.length) {
        return false;
      }
      for (IndexColumn col : cols) {
        // all columns of the list must be part of the index,
        // but not all columns of the index need to be part of the list
        // holes are not allowed (index=a,b,c & list=a,b is ok;
        // but list=a,c is not)
        int idx = existingIndex.getColumnIndex(col.column);
        if (idx < 0 || idx >= cols.length) {
          return false;
        }
      }
    } else {
      if (indexCols.length != cols.length) {
        return false;
      }
      for (IndexColumn col : cols) {
        // all columns of the list must be part of the index
        int idx = existingIndex.getColumnIndex(col.column);
        if (idx < 0) {
          return false;
        }
      }
    }
    return true;
  }

  public void setConstraintName(String constraintName) {
    this.constraintName = constraintName;
  }

  public void setType(int type) {
    this.type = type;
  }

  @Override
  public int getType() {
    return type;
  }

  public void setCheckExpression(Expression expression) {
    this.checkExpression = expression;
  }

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

  public void setIndexColumns(IndexColumn[] indexColumns) {
    this.indexColumns = indexColumns;
  }

  public IndexColumn[] getIndexColumns() {
    return indexColumns;
  }

  /**
   * Set the referenced table.
   *
   * @param refSchema the schema
   * @param ref the table name
   */
  public void setRefTableName(Schema refSchema, String ref) {
    this.refSchema = refSchema;
    this.refTableName = ref;
  }

  public void setRefIndexColumns(IndexColumn[] indexColumns) {
    this.refIndexColumns = indexColumns;
  }

  public void setIndex(Index index) {
    this.index = index;
  }

  public void setRefIndex(Index refIndex) {
    this.refIndex = refIndex;
  }

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

  public void setCheckExisting(boolean b) {
    this.checkExisting = b;
  }

  public void setPrimaryKeyHash(boolean b) {
    this.primaryKeyHash = b;
  }
}