Beispiel #1
0
  private Session createSessionAndValidate(ConnectionInfo ci) {
    try {
      boolean ifExists = ci.getProperty("IFEXISTS", false);
      Session session;
      for (int i = 0; ; i++) {
        session = createSession(ci, ifExists);
        if (session != null) {
          break;
        }
        // we found a database that is currently closing
        // wait a bit to avoid a busy loop (the method is synchronized)
        if (i > 60 * 1000) {
          // retry at most 1 minute
          throw DbException.get(
              ErrorCode.DATABASE_ALREADY_OPEN_1,
              "Waited for database closing longer than 1 minute");
        }
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          // ignore
        }
      }

      initSession(session, ci);
      validateUserAndPassword(true);
      return session;
    } catch (DbException e) {
      if (e.getErrorCode() == ErrorCode.WRONG_USER_OR_PASSWORD) {
        validateUserAndPassword(false);
      }
      throw e;
    }
  }
 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);
     }
   }
 }
Beispiel #3
0
 /**
  * Create a CLOB value from a stream.
  *
  * @param in the reader
  * @param length the number of characters to read, or -1 for no limit
  * @param handler the data handler
  * @return the lob value
  */
 private static ValueLob createClob(Reader in, long length, DataHandler handler) {
   try {
     if (handler == null) {
       String s = IOUtils.readStringAndClose(in, (int) length);
       return createSmallLob(Value.CLOB, s.getBytes(Constants.UTF8));
     }
     boolean compress = handler.getLobCompressionAlgorithm(Value.CLOB) != null;
     long remaining = Long.MAX_VALUE;
     if (length >= 0 && length < remaining) {
       remaining = length;
     }
     int len = getBufferSize(handler, compress, remaining);
     char[] buff;
     if (len >= Integer.MAX_VALUE) {
       String data = IOUtils.readStringAndClose(in, -1);
       buff = data.toCharArray();
       len = buff.length;
     } else {
       buff = new char[len];
       len = IOUtils.readFully(in, buff, len);
     }
     if (len <= handler.getMaxLengthInplaceLob()) {
       byte[] small = new String(buff, 0, len).getBytes(Constants.UTF8);
       return ValueLob.createSmallLob(Value.CLOB, small);
     }
     ValueLob lob = new ValueLob(Value.CLOB, null);
     lob.createFromReader(buff, len, in, remaining, handler);
     return lob;
   } catch (IOException e) {
     throw DbException.convertIOException(e, null);
   }
 }
Beispiel #4
0
 /**
  * Create a BLOB value from a stream.
  *
  * @param in the input stream
  * @param length the number of characters to read, or -1 for no limit
  * @param handler the data handler
  * @return the lob value
  */
 private static ValueLob createBlob(InputStream in, long length, DataHandler handler) {
   try {
     if (handler == null) {
       byte[] data = IOUtils.readBytesAndClose(in, (int) length);
       return createSmallLob(Value.BLOB, data);
     }
     long remaining = Long.MAX_VALUE;
     boolean compress = handler.getLobCompressionAlgorithm(Value.BLOB) != null;
     if (length >= 0 && length < remaining) {
       remaining = length;
     }
     int len = getBufferSize(handler, compress, remaining);
     byte[] buff;
     if (len >= Integer.MAX_VALUE) {
       buff = IOUtils.readBytesAndClose(in, -1);
       len = buff.length;
     } else {
       buff = DataUtils.newBytes(len);
       len = IOUtils.readFully(in, buff, len);
     }
     if (len <= handler.getMaxLengthInplaceLob()) {
       byte[] small = DataUtils.newBytes(len);
       System.arraycopy(buff, 0, small, 0, len);
       return ValueLob.createSmallLob(Value.BLOB, small);
     }
     ValueLob lob = new ValueLob(Value.BLOB, null);
     lob.createFromStream(buff, len, in, remaining, handler);
     return lob;
   } catch (IOException e) {
     throw DbException.convertIOException(e, null);
   }
 }
 @Override
 protected void fetchRows(boolean sendFetch) {
   synchronized (session) {
     session.checkClosed();
     try {
       rowOffset += result.size();
       result.clear();
       int fetch = Math.min(fetchSize, rowCount - rowOffset);
       if (sendFetch) {
         sendFetch(fetch);
       }
       for (int r = 0; r < fetch; r++) {
         boolean row = transfer.readBoolean();
         if (!row) {
           if (transfer.available() > 0) {
             fetchRowsThrowException();
           }
           break;
         }
         int len = columns.length;
         Value[] values = new Value[len];
         for (int i = 0; i < len; i++) {
           Value v = transfer.readValue();
           values[i] = v;
         }
         result.add(values);
       }
       if (rowOffset + result.size() >= rowCount) {
         sendClose();
       }
     } catch (IOException e) {
       throw DbException.convertIOException(e, null);
     }
   }
 }
Beispiel #6
0
  @Override
  public Expression optimize(Session session) {
    if (columnResolver == null) {
      Schema schema =
          session
              .getDatabase()
              .findSchema(tableAlias == null ? session.getCurrentSchemaName() : tableAlias);
      if (schema != null) {
        Constant constant = schema.findConstant(columnName);
        if (constant != null) {
          return (Expression) constant.getValue();
        }
      }

      // 处理在where和having中出现别名的情况,如:
      // SELECT id AS A FROM mytable where A>=0
      // SELECT id/3 AS A, COUNT(*) FROM mytable GROUP BY A HAVING A>=0
      if (select != null) {
        for (Expression e : select.getExpressions()) {
          if (database.equalsIdentifiers(columnName, e.getAlias()))
            return e.getNonAliasExpression().optimize(session);
        }
      }

      String name = columnName;
      if (tableAlias != null) {
        name = tableAlias + "." + name;
        if (schemaName != null) {
          name = schemaName + "." + name;
        }
      }
      throw DbException.get(ErrorCode.COLUMN_NOT_FOUND_1, name);
    }
    return (Expression) columnResolver.optimize(this, column);
  }
 @Override
 Value getMergedValue(Database database, int dataType, boolean distinct) {
   if (distinct) {
     count = 0;
     groupDistinct(database, dataType);
   }
   Value v = null;
   switch (aggregateType) {
     case Aggregate.SUM:
     case Aggregate.MIN:
     case Aggregate.MAX:
     case Aggregate.BOOL_AND:
     case Aggregate.BOOL_OR:
     case Aggregate.BIT_AND:
     case Aggregate.BIT_OR:
       v = value;
       break;
     case Aggregate.AVG:
     case Aggregate.STDDEV_POP:
     case Aggregate.STDDEV_SAMP:
     case Aggregate.VAR_POP:
     case Aggregate.VAR_SAMP:
     default:
       DbException.throwInternalError("type=" + aggregateType);
   }
   return v == null ? ValueNull.INSTANCE : v.convertTo(dataType);
 }
Beispiel #8
0
 /**
  * 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;
 }
 @Override
 Value getValue(Database database, int dataType, boolean distinct) {
   if (distinct) {
     count = 0;
     groupDistinct(database, dataType);
   }
   Value v = null;
   switch (aggregateType) {
     case Aggregate.SUM:
     case Aggregate.MIN:
     case Aggregate.MAX:
     case Aggregate.BIT_OR:
     case Aggregate.BIT_AND:
     case Aggregate.BOOL_OR:
     case Aggregate.BOOL_AND:
       v = value;
       break;
     case Aggregate.AVG:
       if (value != null) {
         v = Aggregate.divide(value, count);
       }
       break;
     case Aggregate.STDDEV_POP:
       {
         if (count < 1) {
           return ValueNull.INSTANCE;
         }
         v = ValueDouble.get(Math.sqrt(m2 / count));
         break;
       }
     case Aggregate.STDDEV_SAMP:
       {
         if (count < 2) {
           return ValueNull.INSTANCE;
         }
         v = ValueDouble.get(Math.sqrt(m2 / (count - 1)));
         break;
       }
     case Aggregate.VAR_POP:
       {
         if (count < 1) {
           return ValueNull.INSTANCE;
         }
         v = ValueDouble.get(m2 / count);
         break;
       }
     case Aggregate.VAR_SAMP:
       {
         if (count < 2) {
           return ValueNull.INSTANCE;
         }
         v = ValueDouble.get(m2 / (count - 1));
         break;
       }
     default:
       DbException.throwInternalError("type=" + aggregateType);
   }
   return v == null ? ValueNull.INSTANCE : v.convertTo(dataType);
 }
Beispiel #10
0
 private void mapColumn(ColumnResolver resolver, Column col, int level) {
   if (this.columnResolver == null) {
     queryLevel = level;
     column = col;
     this.columnResolver = resolver;
   } else if (queryLevel == level && this.columnResolver != resolver) {
     throw DbException.get(ErrorCode.AMBIGUOUS_COLUMN_NAME_1, columnName);
   }
 }
Beispiel #11
0
 private static void copyFileTo(DataHandler h, String sourceFileName, String targetFileName) {
   synchronized (h.getLobSyncObject()) {
     try {
       IOUtils.copyFiles(sourceFileName, targetFileName);
     } catch (IOException e) {
       throw DbException.convertIOException(e, null);
     }
   }
 }
Beispiel #12
0
 private static String getFileName(DataHandler handler, int tableId, int objectId) {
   if (SysProperties.CHECK && tableId == 0 && objectId == 0) {
     DbException.throwInternalError("0 LOB");
   }
   String table = tableId < 0 ? ".temp" : ".t" + tableId;
   return getFileNamePrefix(handler.getDatabasePath(), objectId)
       + table
       + Constants.SUFFIX_LOB_FILE;
 }
 private void checkNoNullValues() {
   String sql =
       "SELECT COUNT(*) FROM " + table.getSQL() + " WHERE " + oldColumn.getSQL() + " IS NULL";
   Prepared command = (Prepared) session.prepare(sql);
   ResultInterface result = command.query(0);
   result.next();
   if (result.currentRow()[0].getInt() > 0) {
     throw DbException.get(ErrorCode.COLUMN_CONTAINS_NULL_VALUES_1, oldColumn.getSQL());
   }
 }
Beispiel #14
0
 /**
  * Get an object from the map if it is stored.
  *
  * @param id the id of the object
  * @param ifAvailable only return it if available, otherwise return null
  * @return the object or null
  * @throws DbException if isAvailable is false and the object has not been found
  */
 public Object getObject(int id, boolean ifAvailable) {
   if (id == cacheId) {
     return cache;
   }
   Object obj = map.get(id);
   if (obj == null && !ifAvailable) {
     throw DbException.get(ErrorCode.OBJECT_CLOSED);
   }
   return obj;
 }
Beispiel #15
0
 /**
  * Store the lob data to a file if the size of the buffer is larger than the maximum size for an
  * in-place lob.
  *
  * @param h the data handler
  */
 public void convertToFileIfRequired(DataHandler h) {
   try {
     if (small != null && small.length > h.getMaxLengthInplaceLob()) {
       boolean compress = h.getLobCompressionAlgorithm(type) != null;
       int len = getBufferSize(h, compress, Long.MAX_VALUE);
       int tabId = tableId;
       if (type == Value.BLOB) {
         createFromStream(DataUtils.newBytes(len), 0, getInputStream(), Long.MAX_VALUE, h);
       } else {
         createFromReader(new char[len], 0, getReader(), Long.MAX_VALUE, h);
       }
       Value v2 = link(h, tabId);
       if (SysProperties.CHECK && v2 != this) {
         DbException.throwInternalError();
       }
     }
   } catch (IOException e) {
     throw DbException.convertIOException(e, null);
   }
 }
 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());
   }
 }
 private void checkNullable() {
   for (Index index : table.getIndexes()) {
     if (index.getColumnIndex(oldColumn) < 0) {
       continue;
     }
     IndexType indexType = index.getIndexType();
     if (indexType.isPrimaryKey() || indexType.isHash()) {
       throw DbException.get(ErrorCode.COLUMN_IS_PART_OF_INDEX_1, index.getSQL());
     }
   }
 }
Beispiel #18
0
 @SuppressWarnings("unchecked")
 private static Comparator<String> getIcu4jCollator(String name, int strength) {
   try {
     Comparator<String> result = null;
     Class<?> collatorClass = Utils.loadUserClass("com.ibm.icu.text.Collator");
     Method getInstanceMethod = collatorClass.getMethod("getInstance", Locale.class);
     if (name.length() == 2) {
       Locale locale = new Locale(StringUtils.toLowerEnglish(name), "");
       if (compareLocaleNames(locale, name)) {
         result = (Comparator<String>) getInstanceMethod.invoke(null, locale);
       }
     } else if (name.length() == 5) {
       // LL_CC (language_country)
       int idx = name.indexOf('_');
       if (idx >= 0) {
         String language = StringUtils.toLowerEnglish(name.substring(0, idx));
         String country = name.substring(idx + 1);
         Locale locale = new Locale(language, country);
         if (compareLocaleNames(locale, name)) {
           result = (Comparator<String>) getInstanceMethod.invoke(null, locale);
         }
       }
     }
     if (result == null) {
       for (Locale locale :
           (Locale[]) collatorClass.getMethod("getAvailableLocales").invoke(null)) {
         if (compareLocaleNames(locale, name)) {
           result = (Comparator<String>) getInstanceMethod.invoke(null, locale);
           break;
         }
       }
     }
     if (result == null) {
       throw DbException.getInvalidValueException("collator", name);
     }
     collatorClass.getMethod("setStrength", int.class).invoke(result, strength);
     return result;
   } catch (Exception e) {
     throw DbException.convert(e);
   }
 }
Beispiel #19
0
 @Override
 public byte[] getBytesNoCopy() {
   if (type == CLOB) {
     // convert hex to string
     return super.getBytesNoCopy();
   }
   if (small != null) {
     return small;
   }
   try {
     return IOUtils.readBytesAndClose(getInputStream(), Integer.MAX_VALUE);
   } catch (IOException e) {
     throw DbException.convertIOException(e, fileName);
   }
 }
Beispiel #20
0
 @Override
 public void updateAggregate(Session session) {
   Value now = columnResolver.getValue(column);
   Select select = (Select) columnResolver.getSelect();
   if (select == null) {
     throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
   }
   HashMap<Expression, Object> values = select.getCurrentGroup();
   if (values == null) {
     // this is a different level (the enclosing query)
     return;
   }
   Value v = (Value) values.get(this);
   if (v == null) {
     values.put(this, now);
   }
 }
Beispiel #21
0
 /**
  * This method is called after validating user name and password. If user name and password were
  * correct, the sleep time is reset, otherwise this method waits some time (to make brute force /
  * rainbow table attacks harder) and then throws a 'wrong user or password' exception. The delay
  * is a bit randomized to protect against timing attacks. Also the delay doubles after each
  * unsuccessful logins, to make brute force attacks harder.
  *
  * <p>There is only one exception message both for wrong user and for wrong password, to make it
  * harder to get the list of user names. This method must only be called from one place, so it is
  * not possible from the stack trace to see if the user name was wrong or the password.
  *
  * @param correct if the user name or the password was correct
  * @throws DbException the exception 'wrong user or password'
  */
 private void validateUserAndPassword(boolean correct) {
   int min = SysProperties.DELAY_WRONG_PASSWORD_MIN;
   if (correct) {
     long delay = wrongPasswordDelay;
     if (delay > min && delay > 0) {
       // the first correct password must be blocked,
       // otherwise parallel attacks are possible
       synchronized (this) {
         // delay up to the last delay
         // an attacker can't know how long it will be
         delay = MathUtils.secureRandomInt((int) delay);
         try {
           Thread.sleep(delay);
         } catch (InterruptedException e) {
           // ignore
         }
         wrongPasswordDelay = min;
       }
     }
   } else {
     // this method is not synchronized on the Engine, so that
     // regular successful attempts are not blocked
     synchronized (this) {
       long delay = wrongPasswordDelay;
       int max = SysProperties.DELAY_WRONG_PASSWORD_MAX;
       if (max <= 0) {
         max = Integer.MAX_VALUE;
       }
       wrongPasswordDelay += wrongPasswordDelay;
       if (wrongPasswordDelay > max || wrongPasswordDelay < 0) {
         wrongPasswordDelay = max;
       }
       if (min > 0) {
         // a bit more to protect against timing attacks
         delay += Math.abs(MathUtils.secureRandomLong() % 100);
         try {
           Thread.sleep(delay);
         } catch (InterruptedException e) {
           // ignore
         }
       }
       throw DbException.get(ErrorCode.WRONG_USER_OR_PASSWORD);
     }
   }
 }
Beispiel #22
0
 @Override
 public Value getValue(Session session) {
   Select select = (Select) columnResolver.getSelect();
   if (select != null) {
     HashMap<Expression, Object> values = select.getCurrentGroup();
     if (values != null) {
       Value v = (Value) values.get(this);
       if (v != null) {
         return v;
       }
     }
   }
   Value value = columnResolver.getValue(column);
   if (value == null) {
     columnResolver.getValue(column);
     throw DbException.get(ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
   }
   return value;
 }
Beispiel #23
0
 @Override
 public boolean isEverything(ExpressionVisitor visitor) {
   switch (visitor.getType()) {
     case ExpressionVisitor.OPTIMIZABLE_MIN_MAX_COUNT_ALL:
       return false;
     case ExpressionVisitor.READONLY:
     case ExpressionVisitor.DETERMINISTIC:
     case ExpressionVisitor.QUERY_COMPARABLE:
       return true;
     case ExpressionVisitor.INDEPENDENT:
       return this.queryLevel < visitor.getQueryLevel();
     case ExpressionVisitor.EVALUATABLE:
       // if the current value is known (evaluatable set)
       // or if this columns belongs to a 'higher level' query and is
       // therefore just a parameter
       if (database.getSettings().nestedJoins) {
         if (visitor.getQueryLevel() < this.queryLevel) {
           return true;
         }
         if (getTableFilter() == null) {
           return false;
         }
         return getTableFilter().isEvaluatable();
       }
       return evaluatable || visitor.getQueryLevel() < this.queryLevel;
     case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
       visitor.addDataModificationId(column.getTable().getMaxDataModificationId());
       return true;
     case ExpressionVisitor.NOT_FROM_RESOLVER:
       return columnResolver != visitor.getResolver();
     case ExpressionVisitor.GET_DEPENDENCIES:
       if (column != null) {
         visitor.addDependency(column.getTable());
       }
       return true;
     case ExpressionVisitor.GET_COLUMNS:
       visitor.addColumn(column);
       return true;
     default:
       throw DbException.throwInternalError("type=" + visitor.getType());
   }
 }
Beispiel #24
0
 @Override
 public String getString() {
   int len = precision > Integer.MAX_VALUE || precision == 0 ? Integer.MAX_VALUE : (int) precision;
   try {
     if (type == Value.CLOB) {
       if (small != null) {
         return new String(small, Constants.UTF8);
       }
       return IOUtils.readStringAndClose(getReader(), len);
     }
     byte[] buff;
     if (small != null) {
       buff = small;
     } else {
       buff = IOUtils.readBytesAndClose(getInputStream(), len);
     }
     return StringUtils.convertBytesToHex(buff);
   } catch (IOException e) {
     throw DbException.convertIOException(e, fileName);
   }
 }
Beispiel #25
0
 @Override
 public int update() {
   session.commit(true);
   Database db = session.getDatabase();
   if (getSchema().findSequence(sequenceName) != null) {
     if (ifNotExists) {
       return 0;
     }
     throw DbException.get(ErrorCode.SEQUENCE_ALREADY_EXISTS_1, sequenceName);
   }
   int id = getObjectId();
   Long startValue = getLong(start);
   Long inc = getLong(increment);
   Long cache = getLong(cacheSize);
   Long min = getLong(minValue);
   Long max = getLong(maxValue);
   Sequence sequence =
       new Sequence(
           getSchema(), id, sequenceName, startValue, inc, cache, min, max, cycle, belongsToTable);
   db.addSchemaObject(session, sequence);
   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;
  }
 @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;
 }
 @Override
 void add(Database database, int dataType, boolean distinct, Value v) {
   if (v == ValueNull.INSTANCE) {
     return;
   }
   count++;
   if (distinct) {
     if (distinctValues == null) {
       distinctValues = ValueHashMap.newInstance();
     }
     distinctValues.put(v, this);
     return;
   }
   switch (aggregateType) {
     case Aggregate.SUM:
       if (value == null) {
         value = v.convertTo(dataType);
       } else {
         v = v.convertTo(value.getType());
         value = value.add(v);
       }
       break;
     case Aggregate.AVG:
       if (value == null) {
         value = v.convertTo(DataType.getAddProofType(dataType));
       } else {
         v = v.convertTo(value.getType());
         value = value.add(v);
       }
       break;
     case Aggregate.MIN:
       if (value == null || database.compare(v, value) < 0) {
         value = v;
       }
       break;
     case Aggregate.MAX:
       if (value == null || database.compare(v, value) > 0) {
         value = v;
       }
       break;
     case Aggregate.STDDEV_POP:
     case Aggregate.STDDEV_SAMP:
     case Aggregate.VAR_POP:
     case Aggregate.VAR_SAMP:
       {
         // Using Welford's method, see also
         // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
         // http://www.johndcook.com/standard_deviation.html
         double x = v.getDouble();
         if (count == 1) {
           mean = x;
           m2 = 0;
         } else {
           double delta = x - mean;
           mean += delta / count;
           m2 += delta * (x - mean);
         }
         break;
       }
     case Aggregate.BOOL_AND:
       v = v.convertTo(Value.BOOLEAN);
       if (value == null) {
         value = v;
       } else {
         value =
             ValueBoolean.get(value.getBoolean().booleanValue() && v.getBoolean().booleanValue());
       }
       break;
     case Aggregate.BOOL_OR:
       v = v.convertTo(Value.BOOLEAN);
       if (value == null) {
         value = v;
       } else {
         value =
             ValueBoolean.get(value.getBoolean().booleanValue() || v.getBoolean().booleanValue());
       }
       break;
     case Aggregate.BIT_AND:
       if (value == null) {
         value = v.convertTo(dataType);
       } else {
         value = ValueLong.get(value.getLong() & v.getLong()).convertTo(dataType);
       }
       break;
     case Aggregate.BIT_OR:
       if (value == null) {
         value = v.convertTo(dataType);
       } else {
         value = ValueLong.get(value.getLong() | v.getLong()).convertTo(dataType);
       }
       break;
     default:
       DbException.throwInternalError("type=" + aggregateType);
   }
 }
Beispiel #29
0
  private Session createSession(ConnectionInfo ci, boolean ifExists) {
    String name = ci.getDatabaseName();
    name = Database.parseDatabaseShortName(ci.getDbSettings(), name);
    Database database;
    boolean openNew = ci.getProperty("OPEN_NEW", false);
    if (openNew) {
      database = null;
    } else {
      database = DATABASES.get(name);
    }
    User user = null;
    boolean opened = false;
    if (database == null) {
      if (ifExists && !SystemDatabase.exists(name)) {
        throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1, name);
      }
      database = createDatabase(ci.isPersistent());
      database.init(ci, name);
      opened = true;
      if (database.getAllUsers().isEmpty()) {
        // users is the last thing we add, so if no user is around,
        // the database is new (or not initialized correctly)
        user = new User(database, database.allocateObjectId(), ci.getUserName(), false);
        user.setAdmin(true);
        user.setUserPasswordHash(ci.getUserPasswordHash());
        database.setMasterUser(user);
      }
      DATABASES.put(name, database);

      if (database.isPersistent())
        SystemDatabase.addDatabase(database.getShortName(), database.getStorageEngineName());
    } else {
      if (!database.isInitialized()) database.init(ci, name);
    }

    synchronized (database) {
      if (opened) {
        // start the thread when already synchronizing on the database
        // otherwise a deadlock can occur when the writer thread
        // opens a new database (as in recovery testing)
        database.opened();
      }
      if (database.isClosing()) {
        return null;
      }
      if (user == null) {
        if (database.validateFilePasswordHash(
            ci.getProperty("CIPHER", null), ci.getFilePasswordHash())) {
          user = database.findUser(ci.getUserName());
          if (user != null) {
            if (!user.validateUserPasswordHash(ci.getUserPasswordHash())) {
              user = null;
            }
          }
        }
        if (opened && (user == null || !user.isAdmin())) {
          // reset - because the user is not an admin, and has no
          // right to listen to exceptions
          database.setEventListener(null);
        }
      }
      if (user == null) {
        database.removeSession(null);
        throw DbException.get(ErrorCode.WRONG_USER_OR_PASSWORD);
      }
      Session session = database.createSession(user);
      session.setConnectionInfo(ci);
      return session;
    }
  }
 @Override
 void merge(Database database, int dataType, boolean distinct, Value v) {
   if (v == ValueNull.INSTANCE) {
     return;
   }
   count++;
   if (distinct) {
     if (distinctValues == null) {
       distinctValues = ValueHashMap.newInstance();
     }
     distinctValues.put(v, this);
     return;
   }
   switch (aggregateType) {
     case Aggregate.SUM:
       if (value == null) {
         value = v.convertTo(dataType);
       } else {
         v = v.convertTo(value.getType());
         value = value.add(v);
       }
       break;
     case Aggregate.MIN:
       if (value == null || database.compare(v, value) < 0) {
         value = v;
       }
       break;
     case Aggregate.MAX:
       if (value == null || database.compare(v, value) > 0) {
         value = v;
       }
       break;
     case Aggregate.BOOL_AND:
       v = v.convertTo(Value.BOOLEAN);
       if (value == null) {
         value = v;
       } else {
         value =
             ValueBoolean.get(value.getBoolean().booleanValue() && v.getBoolean().booleanValue());
       }
       break;
     case Aggregate.BOOL_OR:
       v = v.convertTo(Value.BOOLEAN);
       if (value == null) {
         value = v;
       } else {
         value =
             ValueBoolean.get(value.getBoolean().booleanValue() || v.getBoolean().booleanValue());
       }
       break;
     case Aggregate.BIT_AND:
       if (value == null) {
         value = v.convertTo(dataType);
       } else {
         value = ValueLong.get(value.getLong() & v.getLong()).convertTo(dataType);
       }
       break;
     case Aggregate.BIT_OR:
       if (value == null) {
         value = v.convertTo(dataType);
       } else {
         value = ValueLong.get(value.getLong() | v.getLong()).convertTo(dataType);
       }
       break;
       // 这5个在分布式环境下会进行重写,所以合并时是不会出现的
     case Aggregate.AVG:
     case Aggregate.STDDEV_POP:
     case Aggregate.STDDEV_SAMP:
     case Aggregate.VAR_POP:
     case Aggregate.VAR_SAMP:
     default:
       DbException.throwInternalError("type=" + aggregateType);
   }
 }