private void optimize(Session s) {
   if (!optimized) {
     min = min.optimize(s);
     max = max.optimize(s);
     if (step != null) {
       step = step.optimize(s);
     }
     optimized = true;
   }
 }
Example #2
0
 private void setEvaluatableRecursive(TableFilter f) {
   for (; f != null; f = f.getJoin()) {
     f.setEvaluatable(f, true);
     if (condition != null) {
       condition.setEvaluatable(f, true);
     }
     TableFilter n = f.getNestedJoin();
     if (n != null) {
       setEvaluatableRecursive(n);
     }
     Expression on = f.getJoinCondition();
     if (on != null) {
       if (!on.isEverything(ExpressionVisitor.EVALUATABLE_VISITOR)) {
         if (session.getDatabase().getSettings().nestedJoins) {
           // need to check that all added are bound to a table
           on = on.optimize(session);
           if (!f.isJoinOuter() && !f.isJoinOuterIndirect()) {
             f.removeJoinCondition();
             addCondition(on);
           }
         } else {
           if (f.isJoinOuter()) {
             // this will check if all columns exist - it may or may not throw an exception
             on = on.optimize(session);
             // it is not supported even if the columns exist
             throw DbException.get(ErrorCode.UNSUPPORTED_OUTER_JOIN_CONDITION_1, on.getSQL());
           }
           f.removeJoinCondition();
           // need to check that all added are bound to a table
           on = on.optimize(session);
           addCondition(on);
         }
       }
     }
     on = f.getFilterCondition();
     if (on != null) {
       if (!on.isEverything(ExpressionVisitor.EVALUATABLE_VISITOR)) {
         f.removeFilterCondition();
         addCondition(on);
       }
     }
     // this is only important for subqueries, so they know
     // the result columns are evaluatable
     for (Expression e : expressions) {
       e.setEvaluatable(f, true);
     }
   }
 }
Example #3
0
 @Override
 public void prepare() {
   if (columns == null) {
     // 如INSERT INTO InsertTest DEFAULT VALUES
     if (list.size() > 0 && list.get(0).length == 0) {
       // special case where table is used as a sequence
       columns = new Column[0];
     } else { // 如INSERT INTO InsertTest(SELECT * FROM tmpSelectTest)
       columns = table.getColumns();
     }
   }
   if (list.size() > 0) {
     for (Expression[] expr : list) {
       if (expr.length != columns.length) {
         throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
       }
       for (int i = 0, len = expr.length; i < len; i++) {
         Expression e = expr[i];
         if (e != null) {
           e = e.optimize(session);
           if (e instanceof Parameter) {
             Parameter p = (Parameter) e;
             p.setColumn(columns[i]);
           }
           expr[i] = e;
         }
       }
     }
   } else {
     query.prepare();
     if (query.getColumnCount() != columns.length) {
       throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
     }
   }
 }
Example #4
0
 private int insertRows() {
   session.getUser().checkRight(table, Right.INSERT);
   setCurrentRowNumber(0);
   table.fire(session, Trigger.INSERT, true);
   rowNumber = 0;
   int listSize = list.size();
   if (listSize > 0) {
     int columnLen = columns.length;
     for (int x = 0; x < listSize; x++) {
       Row newRow = table.getTemplateRow(); // newRow的长度是全表字段的个数是,会>=columns的长度
       Expression[] expr = list.get(x);
       setCurrentRowNumber(x + 1);
       for (int i = 0; i < columnLen; i++) {
         Column c = columns[i];
         int index = c.getColumnId(); // 从0开始
         Expression e = expr[i];
         if (e != null) {
           // e can be null (DEFAULT)
           e = e.optimize(session);
           try {
             Value v = c.convert(e.getValue(session));
             newRow.setValue(index, v);
           } catch (DbException ex) {
             throw setRow(ex, x, getSQL(expr));
           }
         }
       }
       rowNumber++;
       table.validateConvertUpdateSequence(session, newRow);
       boolean done = table.fireBeforeRow(session, null, newRow); // INSTEAD OF触发器会返回true
       if (!done) {
         // 直到事务commit或rollback时才解琐,见org.h2.engine.Session.unlockAll()
         table.lock(session, true, false);
         table.addRow(session, newRow);
         // 在org.h2.index.PageDataIndex.addTry(Session, Row)中事先记了一次PageLog
         // 也就是org.h2.store.PageStore.logAddOrRemoveRow(Session, int, Row, boolean)
         // 这里又记了一次UndoLog
         // UndoLog在org.h2.engine.Session.commit(boolean)时就清除了
         session.log(table, UndoLogRecord.INSERT, newRow);
         table.fireAfterRow(session, null, newRow, false);
       }
     }
   } else {
     table.lock(session, true, false);
     // 这种方式主要是避免循环两次,因为query内部己循环一次了,得到记录后像else中的非insertFromSelect一样,还要循环一次
     if (insertFromSelect) {
       query.query(0, this); // 每遍历一行会回调下面的addRow方法
     } else {
       ResultInterface rows = query.query(0);
       while (rows.next()) {
         Value[] r = rows.currentRow();
         addRow(r);
       }
       rows.close();
     }
   }
   table.fire(session, Trigger.INSERT, false);
   return rowNumber;
 }
Example #5
0
 /**
  * Get the sample size, if set.
  *
  * @param session the session
  * @return the sample size
  */
 int getSampleSizeValue(Session session) {
   if (sampleSizeExpr == null) {
     return 0;
   }
   Value v = sampleSizeExpr.optimize(session).getValue(session);
   if (v == ValueNull.INSTANCE) {
     return 0;
   }
   return v.getInt();
 }
Example #6
0
 // limitExpr在org.h2.command.Parser.parseDelete()中调用过optimize了,所以在这里不用再调用
 // 因为limitExpr不会涉及到列,所以也不需要调用mapColumns
 @Override
 public void prepare() {
   if (condition != null) {
     condition.mapColumns(tableFilter, 0);
     condition = condition.optimize(session);
     condition.createIndexConditions(session, tableFilter);
   }
   // 为什么不能像mapColumns把level设为0,因为getBestPlanItem内部会把level当被除数,所以不行。
   PlanItem item = tableFilter.getBestPlanItem(session, 1);
   tableFilter.setPlanItem(item);
   tableFilter.prepare();
 }
Example #7
0
 public int update() throws SQLException {
   session.commit(true);
   session.getUser().checkAdmin();
   Database db = session.getDatabase();
   if (getSchema().findConstant(constantName) != null) {
     if (ifNotExists) {
       return 0;
     }
     throw Message.getSQLException(ErrorCode.CONSTANT_ALREADY_EXISTS_1, constantName);
   }
   int id = getObjectId(false, true);
   Constant constant = new Constant(getSchema(), id, constantName);
   expression = expression.optimize(session);
   Value value = expression.getValue(session);
   constant.setValue(value);
   db.addSchemaObject(session, constant);
   return 0;
 }
Example #8
0
 public void addGlobalCondition(Parameter param, int columnId, int comparisonType) {
   addParameter(param);
   Expression comp;
   Expression col = expressions.get(columnId);
   col = col.getNonAliasExpression();
   if (col.isEverything(ExpressionVisitor.QUERY_COMPARABLE_VISITOR)) {
     comp = new Comparison(session, comparisonType, col, param);
   } else {
     // this condition will always evaluate to true, but need to
     // add the parameter, so it can be set later
     comp = new Comparison(session, Comparison.EQUAL_NULL_SAFE, param, param);
   }
   comp = comp.optimize(session);
   boolean addToCondition = true;
   if (isGroupQuery) {
     addToCondition = false;
     for (int i = 0; groupIndex != null && i < groupIndex.length; i++) {
       if (groupIndex[i] == columnId) {
         addToCondition = true;
         break;
       }
     }
     if (!addToCondition) {
       if (havingIndex >= 0) {
         having = expressions.get(havingIndex);
       }
       if (having == null) {
         having = comp;
       } else {
         having = new ConditionAndOr(ConditionAndOr.AND, having, comp);
       }
     }
   }
   if (addToCondition) {
     if (condition == null) {
       condition = comp;
     } else {
       condition = new ConditionAndOr(ConditionAndOr.AND, condition, comp);
     }
   }
 }
Example #9
0
 private byte[] getByteArray(Expression e) {
   return StringUtils.convertHexToBytes(e.optimize(session).getValue(session).getString());
 }
Example #10
0
 private char[] getCharArray(Expression e) {
   return e.optimize(session).getValue(session).getString().toCharArray();
 }
Example #11
0
 public void prepare() {
   if (isPrepared) {
     // sometimes a subquery is prepared twice (CREATE TABLE AS SELECT)
     return;
   }
   if (SysProperties.CHECK && !checkInit) {
     DbException.throwInternalError("not initialized");
   }
   if (orderList != null) {
     sort = prepareOrder(orderList, expressions.size());
     orderList = null;
   }
   for (int i = 0; i < expressions.size(); i++) {
     Expression e = expressions.get(i);
     expressions.set(i, e.optimize(session));
   }
   if (condition != null) {
     condition = condition.optimize(session);
     for (TableFilter f : filters) {
       // outer joins: must not add index conditions such as
       // "c is null" - example:
       // create table parent(p int primary key) as select 1;
       // create table child(c int primary key, pc int);
       // insert into child values(2, 1);
       // select p, c from parent
       // left outer join child on p = pc where c is null;
       if (!f.isJoinOuter() && !f.isJoinOuterIndirect()) {
         condition.createIndexConditions(session, f);
       }
     }
   }
   if (isGroupQuery && groupIndex == null && havingIndex < 0 && filters.size() == 1) {
     if (condition == null) {
       Table t = filters.get(0).getTable();
       ExpressionVisitor optimizable = ExpressionVisitor.getOptimizableVisitor(t);
       isQuickAggregateQuery = isEverything(optimizable);
     }
   }
   cost = preparePlan();
   if (distinct
       && session.getDatabase().getSettings().optimizeDistinct
       && !isGroupQuery
       && filters.size() == 1
       && expressions.size() == 1
       && condition == null) {
     Expression expr = expressions.get(0);
     expr = expr.getNonAliasExpression();
     if (expr instanceof ExpressionColumn) {
       Column column = ((ExpressionColumn) expr).getColumn();
       int selectivity = column.getSelectivity();
       Index columnIndex = topTableFilter.getTable().getIndexForColumn(column);
       if (columnIndex != null
           && selectivity != Constants.SELECTIVITY_DEFAULT
           && selectivity < 20) {
         // the first column must be ascending
         boolean ascending = columnIndex.getIndexColumns()[0].sortType == SortOrder.ASCENDING;
         Index current = topTableFilter.getIndex();
         // if another index is faster
         if (columnIndex.canFindNext()
             && ascending
             && (current == null || current.getIndexType().isScan() || columnIndex == current)) {
           IndexType type = columnIndex.getIndexType();
           // hash indexes don't work, and unique single column indexes don't work
           if (!type.isHash() && (!type.isUnique() || columnIndex.getColumns().length > 1)) {
             topTableFilter.setIndex(columnIndex);
             isDistinctQuery = true;
           }
         }
       }
     }
   }
   if (sort != null && !isQuickAggregateQuery && !isGroupQuery) {
     Index index = getSortIndex();
     if (index != null) {
       Index current = topTableFilter.getIndex();
       if (current.getIndexType().isScan() || current == index) {
         topTableFilter.setIndex(index);
         if (!topTableFilter.hasInComparisons()) {
           // in(select ...) and in(1,2,3) my return the key in another order
           sortUsingIndex = true;
         }
       } else if (index.getIndexColumns().length >= current.getIndexColumns().length) {
         IndexColumn[] sortColumns = index.getIndexColumns();
         IndexColumn[] currentColumns = current.getIndexColumns();
         boolean swapIndex = false;
         for (int i = 0; i < currentColumns.length; i++) {
           if (sortColumns[i].column != currentColumns[i].column) {
             swapIndex = false;
             break;
           }
           if (sortColumns[i].sortType != currentColumns[i].sortType) {
             swapIndex = true;
           }
         }
         if (swapIndex) {
           topTableFilter.setIndex(index);
           sortUsingIndex = true;
         }
       }
     }
   }
   if (!isQuickAggregateQuery && isGroupQuery && getGroupByExpressionCount() > 0) {
     Index index = getGroupSortedIndex();
     Index current = topTableFilter.getIndex();
     if (index != null && (current.getIndexType().isScan() || current == index)) {
       topTableFilter.setIndex(index);
       isGroupSortedQuery = true;
     }
   }
   expressionArray = new Expression[expressions.size()];
   expressions.toArray(expressionArray);
   isPrepared = true;
 }
 @Override
 public int update() {
   session.commit(true);
   Database db = session.getDatabase();
   session.getUser().checkRight(table, Right.ALL);
   table.checkSupportAlter();
   table.lock(session, true, true);
   if (newColumn != null) {
     checkDefaultReferencesTable(newColumn.getDefaultExpression());
   }
   if (columnsToAdd != null) {
     for (Column column : columnsToAdd) {
       checkDefaultReferencesTable(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:
       {
         Sequence sequence = oldColumn == null ? null : oldColumn.getSequence();
         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 - columnsToRemove.size() < 1) {
           throw DbException.get(
               ErrorCode.CANNOT_DROP_LAST_COLUMN, columnsToRemove.get(0).getSQL());
         }
         table.dropMultipleColumnsConstraintsAndIndexes(session, columnsToRemove);
         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;
 }