Search in sources :

Example 1 with ColumnNamer

use of org.h2.util.ColumnNamer in project h2database by h2database.

the class Select method prepare.

@Override
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;
    }
    ColumnNamer columnNamer = new ColumnNamer(session);
    for (int i = 0; i < expressions.size(); i++) {
        Expression e = expressions.get(i);
        String proposedColumnName = e.getAlias();
        String columnName = columnNamer.getColumnName(e, i, proposedColumnName);
        // if the name changed, create an alias
        if (!columnName.equals(proposedColumnName)) {
            e = new Alias(e, columnName, true);
        }
        expressions.set(i, e.optimize(session));
    }
    if (condition != null) {
        condition = condition.optimize(session);
        for (TableFilter f : filters) {
            // 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(session.isParsingCreateView());
    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, false, true);
            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();
                    // 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();
        Index current = topTableFilter.getIndex();
        if (index != null && current != null) {
            if (current.getIndexType().isScan() || current == index) {
                topTableFilter.setIndex(index);
                if (!topTableFilter.hasInComparisons()) {
                    // in(select ...) and in(1,2,3) may return the key in
                    // another order
                    sortUsingIndex = true;
                }
            } else if (index.getIndexColumns() != null && 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 != null && (current.getIndexType().isScan() || current == index)) {
            topTableFilter.setIndex(index);
            isGroupSortedQuery = true;
        }
    }
    expressionArray = expressions.toArray(new Expression[0]);
    isPrepared = true;
}
Also used : Index(org.h2.index.Index) IndexType(org.h2.index.IndexType)

Example 2 with ColumnNamer

use of org.h2.util.ColumnNamer in project h2database by h2database.

the class TableView method createQueryColumnTemplateList.

/**
 * Creates a list of column templates from a query (usually from WITH query,
 * but could be any query)
 *
 * @param cols - an optional list of column names (can be specified by WITH
 *            clause overriding usual select names)
 * @param theQuery - the query object we want the column list for
 * @param querySQLOutput - array of length 1 to receive extra 'output' field
 *            in addition to return value - containing the SQL query of the
 *            Query object
 * @return a list of column object returned by withQuery
 */
public static List<Column> createQueryColumnTemplateList(String[] cols, Query theQuery, String[] querySQLOutput) {
    List<Column> columnTemplateList = new ArrayList<>();
    theQuery.prepare();
    // String array of length 1 is to receive extra 'output' field in addition to
    // return value
    querySQLOutput[0] = StringUtils.cache(theQuery.getPlanSQL());
    ColumnNamer columnNamer = new ColumnNamer(theQuery.getSession());
    ArrayList<Expression> withExpressions = theQuery.getExpressions();
    for (int i = 0; i < withExpressions.size(); ++i) {
        Expression columnExp = withExpressions.get(i);
        // use the passed in column name if supplied, otherwise use alias
        // (if found) otherwise use column name derived from column
        // expression
        String columnName = columnNamer.getColumnName(columnExp, i, cols);
        columnTemplateList.add(new Column(columnName, columnExp.getType()));
    }
    return columnTemplateList;
}
Also used : ColumnNamer(org.h2.util.ColumnNamer) ExpressionColumn(org.h2.expression.ExpressionColumn) Expression(org.h2.expression.Expression) ArrayList(java.util.ArrayList)

Example 3 with ColumnNamer

use of org.h2.util.ColumnNamer in project h2database by h2database.

the class TableView method initColumnsAndTables.

private void initColumnsAndTables(Session session, boolean literalsChecked) {
    Column[] cols;
    removeCurrentViewFromOtherTables();
    setTableExpression(isTableExpression);
    try {
        Query compiledQuery = compileViewQuery(session, querySQL, literalsChecked, getName());
        this.querySQL = compiledQuery.getPlanSQL();
        tables = new ArrayList<>(compiledQuery.getTables());
        ArrayList<Expression> expressions = compiledQuery.getExpressions();
        ArrayList<Column> list = New.arrayList();
        ColumnNamer columnNamer = new ColumnNamer(session);
        for (int i = 0, count = compiledQuery.getColumnCount(); i < count; i++) {
            Expression expr = expressions.get(i);
            String name = null;
            int type = Value.UNKNOWN;
            if (columnTemplates != null && columnTemplates.length > i) {
                name = columnTemplates[i].getName();
                type = columnTemplates[i].getType();
            }
            if (name == null) {
                name = expr.getAlias();
            }
            name = columnNamer.getColumnName(expr, i, name);
            if (type == Value.UNKNOWN) {
                type = expr.getType();
            }
            long precision = expr.getPrecision();
            int scale = expr.getScale();
            int displaySize = expr.getDisplaySize();
            String[] enumerators = null;
            if (type == Value.ENUM) {
                if (expr instanceof ExpressionColumn) {
                    enumerators = ((ExpressionColumn) expr).getColumn().getEnumerators();
                }
            }
            Column col = new Column(name, type, precision, scale, displaySize, enumerators);
            col.setTable(this, i);
            // Fetch check constraint from view column source
            ExpressionColumn fromColumn = null;
            if (expr instanceof ExpressionColumn) {
                fromColumn = (ExpressionColumn) expr;
            } else if (expr instanceof Alias) {
                Expression aliasExpr = expr.getNonAliasExpression();
                if (aliasExpr instanceof ExpressionColumn) {
                    fromColumn = (ExpressionColumn) aliasExpr;
                }
            }
            if (fromColumn != null) {
                Expression checkExpression = fromColumn.getColumn().getCheckConstraint(session, name);
                if (checkExpression != null) {
                    col.addCheckConstraint(session, checkExpression);
                }
            }
            list.add(col);
        }
        cols = list.toArray(new Column[0]);
        createException = null;
        viewQuery = compiledQuery;
    } catch (DbException e) {
        e.addSQL(getCreateSQL());
        createException = e;
        // table expression query.
        if (isRecursiveQueryExceptionDetected(createException)) {
            this.isRecursiveQueryDetected = true;
        }
        tables = New.arrayList();
        cols = new Column[0];
        if (allowRecursive && columnTemplates != null) {
            cols = new Column[columnTemplates.length];
            for (int i = 0; i < columnTemplates.length; i++) {
                cols[i] = columnTemplates[i].getClone();
            }
            index.setRecursive(true);
            createException = null;
        }
    }
    setColumns(cols);
    if (getId() != 0) {
        addDependentViewToTables();
    }
}
Also used : ColumnNamer(org.h2.util.ColumnNamer) Query(org.h2.command.dml.Query) ExpressionColumn(org.h2.expression.ExpressionColumn) DbException(org.h2.message.DbException) ExpressionColumn(org.h2.expression.ExpressionColumn) Expression(org.h2.expression.Expression) Alias(org.h2.expression.Alias)

Example 4 with ColumnNamer

use of org.h2.util.ColumnNamer in project h2database by h2database.

the class SelectUnion method prepare.

@Override
public void prepare() {
    if (isPrepared) {
        // sometimes a subquery is prepared twice (CREATE TABLE AS SELECT)
        return;
    }
    if (SysProperties.CHECK && !checkInit) {
        DbException.throwInternalError("not initialized");
    }
    isPrepared = true;
    left.prepare();
    right.prepare();
    int len = left.getColumnCount();
    // set the correct expressions now
    expressions = New.arrayList();
    ArrayList<Expression> le = left.getExpressions();
    ArrayList<Expression> re = right.getExpressions();
    ColumnNamer columnNamer = new ColumnNamer(session);
    for (int i = 0; i < len; i++) {
        Expression l = le.get(i);
        Expression r = re.get(i);
        int type = Value.getHigherOrder(l.getType(), r.getType());
        long prec = Math.max(l.getPrecision(), r.getPrecision());
        int scale = Math.max(l.getScale(), r.getScale());
        int displaySize = Math.max(l.getDisplaySize(), r.getDisplaySize());
        String columnName = columnNamer.getColumnName(l, i, l.getAlias());
        Column col = new Column(columnName, type, prec, scale, displaySize);
        Expression e = new ExpressionColumn(session.getDatabase(), col);
        expressions.add(e);
    }
    if (orderList != null) {
        initOrder(session, expressions, null, orderList, getColumnCount(), true, null);
        sort = prepareOrder(orderList, expressions.size());
        orderList = null;
    }
    expressionArray = expressions.toArray(new Expression[0]);
}
Also used : ColumnNamer(org.h2.util.ColumnNamer) ValueExpression(org.h2.expression.ValueExpression) Expression(org.h2.expression.Expression) Column(org.h2.table.Column) ExpressionColumn(org.h2.expression.ExpressionColumn) ExpressionColumn(org.h2.expression.ExpressionColumn)

Example 5 with ColumnNamer

use of org.h2.util.ColumnNamer in project h2database by h2database.

the class CreateTable method generateColumnsFromQuery.

private void generateColumnsFromQuery() {
    int columnCount = asQuery.getColumnCount();
    ArrayList<Expression> expressions = asQuery.getExpressions();
    ColumnNamer columnNamer = new ColumnNamer(session);
    for (int i = 0; i < columnCount; i++) {
        Expression expr = expressions.get(i);
        int type = expr.getType();
        String name = columnNamer.getColumnName(expr, i, expr.getAlias());
        long precision = expr.getPrecision();
        int displaySize = expr.getDisplaySize();
        DataType dt = DataType.getDataType(type);
        if (precision > 0 && (dt.defaultPrecision == 0 || (dt.defaultPrecision > precision && dt.defaultPrecision < Byte.MAX_VALUE))) {
            // dont' set precision to MAX_VALUE if this is the default
            precision = dt.defaultPrecision;
        }
        int scale = expr.getScale();
        if (scale > 0 && (dt.defaultScale == 0 || (dt.defaultScale > scale && dt.defaultScale < precision))) {
            scale = dt.defaultScale;
        }
        if (scale > precision) {
            precision = scale;
        }
        String[] enumerators = null;
        if (dt.type == Value.ENUM) {
            /**
             * Only columns of tables may be enumerated.
             */
            if (!(expr instanceof ExpressionColumn)) {
                throw DbException.get(ErrorCode.GENERAL_ERROR_1, "Unable to resolve enumerators of expression");
            }
            enumerators = ((ExpressionColumn) expr).getColumn().getEnumerators();
        }
        Column col = new Column(name, type, precision, scale, displaySize, enumerators);
        addColumn(col);
    }
}
Also used : ColumnNamer(org.h2.util.ColumnNamer) Expression(org.h2.expression.Expression) ExpressionColumn(org.h2.expression.ExpressionColumn) Column(org.h2.table.Column) DataType(org.h2.value.DataType) ExpressionColumn(org.h2.expression.ExpressionColumn)

Aggregations

Expression (org.h2.expression.Expression)5 ColumnNamer (org.h2.util.ColumnNamer)5 ExpressionColumn (org.h2.expression.ExpressionColumn)4 ValueExpression (org.h2.expression.ValueExpression)2 Column (org.h2.table.Column)2 ArrayList (java.util.ArrayList)1 Query (org.h2.command.dml.Query)1 Alias (org.h2.expression.Alias)1 Index (org.h2.index.Index)1 IndexType (org.h2.index.IndexType)1 DbException (org.h2.message.DbException)1 DataType (org.h2.value.DataType)1