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); } } }
/** * 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); } }
/** * 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); } } }
@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); }
/** * 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); }
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); } }
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); } } }
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()); } }
/** * 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; }
/** * 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()); } } }
@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); } }
@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); } }
@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); } }
/** * 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); } } }
@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; }
@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()); } }
@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); } }
@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); } }
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); } }