private void removeSequence(Sequence sequence) { if (sequence != null) { table.removeSequence(sequence); sequence.setBelongsToTable(false); Database db = session.getDatabase(); db.removeSchemaObject(session, sequence); } }
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); } } }
@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 public int update() { session.commit(true); session.getUser().checkAdmin(); Database db = session.getDatabase(); if (db.findAggregate(name) != null || schema.findFunction(name) != null) { if (!ifNotExists) { throw DbException.get(ErrorCode.FUNCTION_ALIAS_ALREADY_EXISTS_1, name); } } else { int id = getObjectId(); UserAggregate aggregate = new UserAggregate(db, id, name, javaClassName, force); db.addDatabaseObject(session, aggregate); } return 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; }
/** * Create a new schema object. * * @param database the database * @param id the object id * @param schemaName the schema name * @param owner the owner of the schema * @param system if this is a system schema (such a schema can not be dropped) */ public Schema(Database database, int id, String schemaName, User owner, boolean system) { super(database, id, schemaName, Trace.SCHEMA); tablesAndViews = database.newStringMap(); indexes = database.newStringMap(); sequences = database.newStringMap(); triggers = database.newStringMap(); constraints = database.newStringMap(); constants = database.newStringMap(); functions = database.newStringMap(); this.owner = owner; this.system = system; }
@Override public String getSQL(boolean isDistributed) { String sql; boolean quote = database.getSettings().databaseToUpper; if (column != null) { sql = column.getSQL(); } else { sql = quote ? Parser.quoteIdentifier(columnName) : columnName; } if (tableAlias != null) { String a = quote ? Parser.quoteIdentifier(tableAlias) : tableAlias; sql = a + "." + sql; } if (schemaName != null) { String s = quote ? Parser.quoteIdentifier(schemaName) : schemaName; sql = s + "." + sql; } return sql; }
@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()); } }
/** Check that all views and other dependent objects. */ private void checkViews(SchemaObject sourceTable, SchemaObject newTable) { String sourceTableName = sourceTable.getName(); String newTableName = newTable.getName(); Database db = sourceTable.getDatabase(); // save the real table under a temporary name String temp = db.getTempTableName(sourceTableName, session); db.renameSchemaObject(session, sourceTable, temp); try { // have our new table impersonate the target table db.renameSchemaObject(session, newTable, sourceTableName); checkViewsAreValid(sourceTable); } finally { // always put the source tables back with their proper names try { db.renameSchemaObject(session, newTable, newTableName); } finally { db.renameSchemaObject(session, sourceTable, sourceTableName); } } }
@Override public void mapColumns(ColumnResolver resolver, int level) { if (select == null) select = (Select) resolver.getSelect(); if (resolver instanceof TableFilter && resolver.getTableFilter().getTable().supportsColumnFamily()) { Table t = resolver.getTableFilter().getTable(); // if (!t.isStatic() && t.getRowKeyName().equalsIgnoreCase(columnName)) { // if (columnFamilyName != null) { // schemaName = tableAlias; // tableAlias = columnFamilyName; // columnFamilyName = null; // } // if (tableAlias != null && !database.equalsIdentifiers(tableAlias, // resolver.getTableAlias())) { // return; // } // if (schemaName != null && !database.equalsIdentifiers(schemaName, // resolver.getSchemaName())) { // return; // } // mapColumn(resolver, t.getRowKeyColumn(), level); // return; // } if (database.equalsIdentifiers(Column.ROWKEY, columnName)) { Column col = t.getRowKeyColumn(); if (col != null) { mapColumn(resolver, col, level); return; } } if (resolver.getSelect() == null) { Column c = t.getColumn(columnName); mapColumn(resolver, c, level); return; } String tableAlias = this.tableAlias; boolean useAlias = false; // 当columnFamilyName不存在时,有可能是想使用简化的tableAlias.columnName语法 if (columnFamilyName != null && !t.doesColumnFamilyExist(columnFamilyName)) { // 不替换原有的tableAlias,因为有可能在另一个table中存在这样的columnFamilyName tableAlias = columnFamilyName; if (!t.doesColumnExist(columnName)) return; useAlias = true; } if (tableAlias != null && !database.equalsIdentifiers(tableAlias, resolver.getTableAlias())) { return; } if (schemaName != null && !database.equalsIdentifiers(schemaName, resolver.getSchemaName())) { return; } String fullColumnName; if (useAlias || columnFamilyName == null) fullColumnName = columnName; else fullColumnName = t.getFullColumnName(columnFamilyName, columnName); if (t.doesColumnExist(fullColumnName)) { Column c = t.getColumn(fullColumnName); mapColumn(resolver, c, level); return; } } else { if (columnFamilyName != null) { schemaName = tableAlias; tableAlias = columnFamilyName; columnFamilyName = null; } } if (tableAlias != null && !database.equalsIdentifiers(tableAlias, resolver.getTableAlias())) { return; } if (schemaName != null && !database.equalsIdentifiers(schemaName, resolver.getSchemaName())) { return; } for (Column col : resolver.getColumns()) { String n = col.getName(); if (database.equalsIdentifiers(columnName, n)) { mapColumn(resolver, col, level); return; } } if (database.equalsIdentifiers(Column.ROWID, columnName)) { Column col = resolver.getRowIdColumn(); if (col != null) { mapColumn(resolver, col, level); return; } } Column[] columns = resolver.getSystemColumns(); for (int i = 0; columns != null && i < columns.length; i++) { Column col = columns[i]; if (database.equalsIdentifiers(columnName, col.getName())) { mapColumn(resolver, col, level); return; } } }
@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); } }
@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); } }
@Override public int update() { session.commit(true); Database db = session.getDatabase(); session.getUser().checkRight(table, Right.ALL); table.checkSupportAlter(); table.lock(session, true, true); Sequence sequence = oldColumn == null ? null : oldColumn.getSequence(); if (newColumn != null) { checkDefaultReferencesTable((Expression) newColumn.getDefaultExpression()); } if (columnsToAdd != null) { for (Column column : columnsToAdd) { checkDefaultReferencesTable((Expression) column.getDefaultExpression()); } } switch (type) { case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL: { if (!oldColumn.isNullable()) { // no change break; } checkNoNullValues(); oldColumn.setNullable(false); db.updateMeta(session, table); break; } case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL: { if (oldColumn.isNullable()) { // no change break; } checkNullable(); oldColumn.setNullable(true); db.updateMeta(session, table); break; } case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT: { checkDefaultReferencesTable(defaultExpression); oldColumn.setSequence(null); oldColumn.setDefaultExpression(session, defaultExpression); removeSequence(sequence); db.updateMeta(session, table); break; } case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE: { // if the change is only increasing the precision, then we don't // need to copy the table because the length is only a constraint, // and does not affect the storage structure. if (oldColumn.isWideningConversion(newColumn)) { convertAutoIncrementColumn(newColumn); oldColumn.copy(newColumn); db.updateMeta(session, table); } else { oldColumn.setSequence(null); oldColumn.setDefaultExpression(session, null); oldColumn.setConvertNullToDefault(false); if (oldColumn.isNullable() && !newColumn.isNullable()) { checkNoNullValues(); } else if (!oldColumn.isNullable() && newColumn.isNullable()) { checkNullable(); } convertAutoIncrementColumn(newColumn); copyData(); } break; } case CommandInterface.ALTER_TABLE_ADD_COLUMN: { // ifNotExists only supported for single column add if (ifNotExists && columnsToAdd.size() == 1 && table.doesColumnExist(columnsToAdd.get(0).getName())) { break; } for (Column column : columnsToAdd) { if (column.isAutoIncrement()) { int objId = getObjectId(); column.convertAutoIncrementToSequence( session, getSchema(), objId, table.isTemporary()); } } copyData(); break; } case CommandInterface.ALTER_TABLE_DROP_COLUMN: { if (table.getColumns().length == 1) { throw DbException.get(ErrorCode.CANNOT_DROP_LAST_COLUMN, oldColumn.getSQL()); } table.dropSingleColumnConstraintsAndIndexes(session, oldColumn); copyData(); break; } case CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY: { int value = newSelectivity.optimize(session).getValue(session).getInt(); oldColumn.setSelectivity(value); db.updateMeta(session, table); break; } default: DbException.throwInternalError("type=" + type); } return 0; }
private Table cloneTableStructure( Column[] columns, Database db, String tempName, ArrayList<Column> newColumns) { for (Column col : columns) { newColumns.add(col.getClone()); } if (type == CommandInterface.ALTER_TABLE_DROP_COLUMN) { int position = oldColumn.getColumnId(); newColumns.remove(position); } else if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN) { int position; if (addBefore != null) { position = table.getColumn(addBefore).getColumnId(); } else if (addAfter != null) { position = table.getColumn(addAfter).getColumnId() + 1; } else { position = columns.length; } for (Column column : columnsToAdd) { newColumns.add(position++, column); } } else if (type == CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE) { int position = oldColumn.getColumnId(); newColumns.remove(position); newColumns.add(position, newColumn); } // create a table object in order to get the SQL statement // can't just use this table, because most column objects are 'shared' // with the old table // still need a new id because using 0 would mean: the new table tries // to use the rows of the table 0 (the meta table) int id = db.allocateObjectId(); CreateTableData data = new CreateTableData(); data.tableName = tempName; data.id = id; data.columns = newColumns; data.temporary = table.isTemporary(); data.persistData = table.isPersistData(); data.persistIndexes = table.isPersistIndexes(); data.isHidden = table.isHidden(); data.create = true; data.session = session; data.storageEngineName = table.getStorageEngineName(); Table newTable = getSchema().createTable(data); newTable.setComment(table.getComment()); StringBuilder buff = new StringBuilder(); buff.append(newTable.getCreateSQL()); if (table.supportsAlterColumnWithCopyData()) { StringBuilder columnList = new StringBuilder(); for (Column nc : newColumns) { if (columnList.length() > 0) { columnList.append(", "); } if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN && columnsToAdd.contains(nc)) { Expression def = (Expression) nc.getDefaultExpression(); columnList.append(def == null ? "NULL" : def.getSQL()); } else { columnList.append(nc.getSQL()); } } buff.append(" AS SELECT "); if (columnList.length() == 0) { // special case: insert into test select * from buff.append('*'); } else { buff.append(columnList); } buff.append(" FROM ").append(table.getSQL()); } String newTableSQL = buff.toString(); String newTableName = newTable.getName(); Schema newTableSchema = newTable.getSchema(); newTable.removeChildrenAndResources(session); execute(newTableSQL, true); newTable = newTableSchema.getTableOrView(session, newTableName); ArrayList<String> triggers = New.arrayList(); for (DbObject child : table.getChildren()) { if (child instanceof Sequence) { continue; } else if (child instanceof Index) { Index idx = (Index) child; if (idx.getIndexType().getBelongsToConstraint()) { continue; } } String createSQL = child.getCreateSQL(); if (createSQL == null) { continue; } if (child instanceof TableView) { continue; } else if (child.getType() == DbObject.TABLE_OR_VIEW) { DbException.throwInternalError(); } String quotedName = Parser.quoteIdentifier(tempName + "_" + child.getName()); String sql = null; if (child instanceof ConstraintReferential) { ConstraintReferential r = (ConstraintReferential) child; if (r.getTable() != table) { sql = r.getCreateSQLForCopy(r.getTable(), newTable, quotedName, false); } } if (sql == null) { sql = child.getCreateSQLForCopy(newTable, quotedName); } if (sql != null) { if (child instanceof TriggerObject) { triggers.add(sql); } else { execute(sql, true); } } } table.setModified(); // remove the sequences from the columns (except dropped columns) // otherwise the sequence is dropped if the table is dropped for (Column col : newColumns) { Sequence seq = col.getSequence(); if (seq != null) { table.removeSequence(seq); col.setSequence(null); } } for (String sql : triggers) { execute(sql, true); } return newTable; }
@Override public int update() { if (!transactional) { session.commit(true); } Database db = session.getDatabase(); if (!db.isPersistent()) { data.persistIndexes = false; } if (getSchema().findTableOrView(session, data.tableName) != null) { if (ifNotExists) { return 0; } throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, data.tableName); } if (asQuery != null) { asQuery.prepare(); if (data.columns.isEmpty()) { generateColumnsFromQuery(); } else if (data.columns.size() != asQuery.getColumnCount()) { throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); } } if (pkColumns != null) { for (Column c : data.columns) { for (IndexColumn idxCol : pkColumns) { if (c.getName().equals(idxCol.columnName)) { c.setNullable(false); } } } } data.id = getObjectId(); data.create = create; data.session = session; boolean isSessionTemporary = data.temporary && !data.globalTemporary; if (!isSessionTemporary) { db.lockMeta(session); } Table table = createTable(data); ArrayList<Sequence> sequences = New.arrayList(); for (Column c : data.columns) { if (c.isAutoIncrement()) { int objId = getObjectId(); c.convertAutoIncrementToSequence(session, getSchema(), objId, data.temporary); } Sequence seq = c.getSequence(); if (seq != null) { sequences.add(seq); } } table.setComment(comment); if (isSessionTemporary) { if (onCommitDrop) { table.setOnCommitDrop(true); } if (onCommitTruncate) { table.setOnCommitTruncate(true); } session.addLocalTempTable(table); } else { db.lockMeta(session); db.addSchemaObject(session, table); } try { for (Column c : data.columns) { c.prepareExpression(session); } for (Sequence sequence : sequences) { table.addSequence(sequence); } for (DefineCommand command : constraintCommands) { command.setTransactional(transactional); command.update(); } if (asQuery != null) { Insert insert = null; insert = new Insert(session); insert.setSortedInsertMode(sortedInsertMode); insert.setQuery(asQuery); insert.setTable(table); insert.setInsertFromSelect(true); insert.prepare(); insert.update(); } } catch (DbException e) { db.checkPowerOff(); db.removeSchemaObject(session, table); if (!transactional) { session.commit(true); } throw e; } return 0; }