Search in sources :

Example 1 with Top

use of net.sf.jsqlparser.statement.select.Top in project herddb by diennea.

the class SQLPlanner method buildSelectStatement.

private ExecutionPlan buildSelectStatement(String defaultTableSpace, Select s, boolean scan, int maxRows) throws StatementExecutionException {
    PlainSelect selectBody = (PlainSelect) s.getSelectBody();
    net.sf.jsqlparser.schema.Table fromTable = (net.sf.jsqlparser.schema.Table) selectBody.getFromItem();
    TableRef mainTable = TableRef.buildFrom(fromTable, defaultTableSpace);
    String mainTableAlias = mainTable.tableAlias;
    String tableSpace = mainTable.tableSpace;
    TableSpaceManager tableSpaceManager = manager.getTableSpaceManager(tableSpace);
    if (tableSpaceManager == null) {
        throw new TableSpaceDoesNotExistException("no such tablespace " + tableSpace + " here at " + manager.getNodeId());
    }
    AbstractTableManager tableManager = tableSpaceManager.getTableManager(mainTable.tableName);
    if (tableManager == null) {
        throw new TableDoesNotExistException("no such table " + mainTable.tableName + " in tablespace " + tableSpace);
    }
    // linked hash map retains the order of insertions
    LinkedHashMap<String, JoinSupport> joins = new LinkedHashMap<>();
    boolean joinPresent = false;
    joins.put(mainTable.tableAlias, new JoinSupport(mainTable, tableManager));
    if (selectBody.getJoins() != null) {
        for (Join join : selectBody.getJoins()) {
            joinPresent = true;
            if (join.isLeft() || join.isCross() || join.isRight() || join.isOuter() || join.isSimple()) {
                throw new StatementExecutionException("unsupported JOIN type: " + join);
            }
            net.sf.jsqlparser.schema.Table joinedTable = (net.sf.jsqlparser.schema.Table) join.getRightItem();
            TableRef joinedTableRef = TableRef.buildFrom(joinedTable, defaultTableSpace);
            if (!joinedTableRef.tableSpace.equalsIgnoreCase(mainTable.tableSpace)) {
                throw new TableDoesNotExistException("unsupported cross-tablespace JOIN " + "between" + mainTable.tableSpace + "." + mainTable.tableName + " and " + joinedTableRef.tableSpace + "." + joinedTableRef.tableName);
            }
            AbstractTableManager joinedTableManager = tableSpaceManager.getTableManager(joinedTableRef.tableName);
            if (joinedTableManager == null) {
                throw new TableDoesNotExistException("no such table " + joinedTableRef.tableName + " in tablespace " + tableSpace);
            }
            JoinSupport joinSupport = new JoinSupport(joinedTableRef, joinedTableManager);
            joins.put(joinedTableRef.tableAlias, joinSupport);
        }
    }
    Projection mainTableProjection;
    Table table = tableManager.getTable();
    boolean allColumns = false;
    boolean containsAggregateFunctions = false;
    for (SelectItem c : selectBody.getSelectItems()) {
        if (c instanceof AllColumns) {
            allColumns = true;
            break;
        } else if (c instanceof AllTableColumns) {
            AllTableColumns allTableColumns = (AllTableColumns) c;
            TableRef ref = TableRef.buildFrom(allTableColumns.getTable(), defaultTableSpace);
            if (!joinPresent && ref.tableAlias.equals(mainTable.tableAlias)) {
                // select a.*  FROM table a
                allColumns = true;
            } else {
                // select a.*, b.* FROM table a JOIN table b
                joins.get(ref.tableAlias).allColumns = true;
            }
        } else if (c instanceof SelectExpressionItem) {
            SelectExpressionItem se = (SelectExpressionItem) c;
            if (isAggregateFunction(se.getExpression())) {
                containsAggregateFunctions = true;
            }
            if (!joinPresent) {
                joins.get(mainTable.tableAlias).selectItems.add(c);
            } else {
                ColumnReferencesDiscovery discoverMainTableAlias = discoverMainTableAlias(se.getExpression());
                String mainTableAliasForItem = discoverMainTableAlias.getMainTableAlias();
                if (discoverMainTableAlias.isContainsMixedAliases()) {
                    throw new StatementExecutionException("unsupported single SELECT ITEM with mixed aliases: " + c);
                }
                if (mainTableAliasForItem == null) {
                    mainTableAliasForItem = mainTable.tableAlias;
                }
                joins.get(mainTableAliasForItem).selectItems.add(c);
            }
        } else {
            throw new StatementExecutionException("unsupported SELECT ITEM type: " + c);
        }
    }
    if (allColumns) {
        mainTableProjection = Projection.IDENTITY(table.columnNames, table.columns);
        for (Map.Entry<String, JoinSupport> join : joins.entrySet()) {
            JoinSupport support = join.getValue();
            support.projection = Projection.IDENTITY(support.table.columnNames, support.table.columns);
            support.allColumns = true;
        }
    } else {
        if (!joinPresent) {
            mainTableProjection = new SQLProjection(table, mainTableAlias, selectBody.getSelectItems());
        } else {
            for (JoinSupport support : joins.values()) {
                if (support.allColumns) {
                    support.projection = Projection.IDENTITY(support.table.columnNames, support.table.columns);
                } else {
                    support.projection = new SQLProjection(support.table, support.tableRef.tableAlias, support.selectItems);
                }
            }
            mainTableProjection = joins.get(mainTableAlias).projection;
        }
    }
    if (scan) {
        if (!joinPresent) {
            SQLRecordPredicate where = selectBody.getWhere() != null ? new SQLRecordPredicate(table, mainTableAlias, selectBody.getWhere()) : null;
            if (where != null) {
                discoverIndexOperations(selectBody.getWhere(), table, mainTableAlias, where, tableSpaceManager);
            }
            Aggregator aggregator = null;
            ScanLimitsImpl scanLimits = null;
            if (containsAggregateFunctions || (selectBody.getGroupByColumnReferences() != null && !selectBody.getGroupByColumnReferences().isEmpty())) {
                aggregator = new SQLAggregator(selectBody.getSelectItems(), selectBody.getGroupByColumnReferences(), manager.getRecordSetFactory());
            }
            TupleComparator comparatorOnScan = null;
            TupleComparator comparatorOnPlan = null;
            if (selectBody.getOrderByElements() != null && !selectBody.getOrderByElements().isEmpty()) {
                if (aggregator != null) {
                    comparatorOnPlan = SingleColumnSQLTupleComparator.make(mainTableAlias, selectBody.getOrderByElements(), null);
                } else {
                    comparatorOnScan = SingleColumnSQLTupleComparator.make(mainTableAlias, selectBody.getOrderByElements(), table.primaryKey);
                }
            }
            Limit limit = selectBody.getLimit();
            Top top = selectBody.getTop();
            if (limit != null && top != null) {
                throw new StatementExecutionException("LIMIT and TOP cannot be used on the same query");
            }
            if (limit != null) {
                if (limit.isLimitAll() || limit.isLimitNull() || limit.getOffset() instanceof JdbcParameter) {
                    throw new StatementExecutionException("Invalid LIMIT clause (limit=" + limit + ")");
                }
                if (maxRows > 0 && limit.getRowCount() instanceof JdbcParameter) {
                    throw new StatementExecutionException("Invalid LIMIT clause (limit=" + limit + ") and JDBC setMaxRows=" + maxRows);
                }
                int rowCount;
                int rowCountJdbcParameter = -1;
                if (limit.getRowCount() instanceof JdbcParameter) {
                    rowCount = -1;
                    rowCountJdbcParameter = ((JdbcParameter) limit.getRowCount()).getIndex() - 1;
                } else {
                    rowCount = ((Number) resolveValue(limit.getRowCount(), false)).intValue();
                }
                int offset = limit.getOffset() != null ? ((Number) resolveValue(limit.getOffset(), false)).intValue() : 0;
                scanLimits = new ScanLimitsImpl(rowCount, offset, rowCountJdbcParameter + 1);
            } else if (top != null) {
                if (top.isPercentage() || top.getExpression() == null) {
                    throw new StatementExecutionException("Invalid TOP clause (top=" + top + ")");
                }
                try {
                    int rowCount = Integer.parseInt(resolveValue(top.getExpression(), false) + "");
                    scanLimits = new ScanLimitsImpl(rowCount, 0);
                } catch (NumberFormatException error) {
                    throw new StatementExecutionException("Invalid TOP clause: " + error, error);
                }
            }
            if (maxRows > 0) {
                if (scanLimits == null) {
                    scanLimits = new ScanLimitsImpl(maxRows, 0);
                } else if (scanLimits.getMaxRows() <= 0 || scanLimits.getMaxRows() > maxRows) {
                    scanLimits = new ScanLimitsImpl(maxRows, scanLimits.getOffset());
                }
            }
            ScanLimitsImpl limitsOnScan = null;
            ScanLimitsImpl limitsOnPlan = null;
            if (aggregator != null) {
                limitsOnPlan = scanLimits;
            } else {
                limitsOnScan = scanLimits;
            }
            try {
                ScanStatement statement = new ScanStatement(tableSpace, mainTable.tableName, mainTableProjection, where, comparatorOnScan, limitsOnScan);
                return ExecutionPlan.make(statement, aggregator, limitsOnPlan, comparatorOnPlan);
            } catch (IllegalArgumentException err) {
                throw new StatementExecutionException(err);
            }
        } else {
            if (containsAggregateFunctions || (selectBody.getGroupByColumnReferences() != null && !selectBody.getGroupByColumnReferences().isEmpty())) {
                throw new StatementExecutionException("AGGREGATEs are not yet supported with JOIN");
            }
            Limit limit = selectBody.getLimit();
            Top top = selectBody.getTop();
            if (limit != null && top != null) {
                throw new StatementExecutionException("LIMIT and TOP cannot be used on the same query");
            }
            ScanLimitsImpl scanLimits = null;
            if (limit != null) {
                if (limit.isLimitAll() || limit.isLimitNull() || limit.getOffset() instanceof JdbcParameter) {
                    throw new StatementExecutionException("Invalid LIMIT clause (limit=" + limit + ")");
                }
                if (maxRows > 0 && limit.getRowCount() instanceof JdbcParameter) {
                    throw new StatementExecutionException("Invalid LIMIT clause (limit=" + limit + ") and JDBC setMaxRows=" + maxRows);
                }
                int rowCount;
                int rowCountJdbcParameter = -1;
                if (limit.getRowCount() instanceof JdbcParameter) {
                    rowCount = -1;
                    rowCountJdbcParameter = ((JdbcParameter) limit.getRowCount()).getIndex() - 1;
                } else {
                    rowCount = ((Number) resolveValue(limit.getRowCount(), false)).intValue();
                }
                int offset = limit.getOffset() != null ? ((Number) resolveValue(limit.getOffset(), false)).intValue() : 0;
                scanLimits = new ScanLimitsImpl(rowCount, offset, rowCountJdbcParameter + 1);
            } else if (top != null) {
                if (top.isPercentage() || top.getExpression() == null) {
                    throw new StatementExecutionException("Invalid TOP clause");
                }
                try {
                    int rowCount = Integer.parseInt(resolveValue(top.getExpression(), false) + "");
                    scanLimits = new ScanLimitsImpl(rowCount, 0);
                } catch (NumberFormatException error) {
                    throw new StatementExecutionException("Invalid TOP clause: " + error, error);
                }
            }
            if (maxRows > 0) {
                if (scanLimits == null) {
                    scanLimits = new ScanLimitsImpl(maxRows, 0);
                } else if (scanLimits.getMaxRows() <= 0 || scanLimits.getMaxRows() > maxRows) {
                    scanLimits = new ScanLimitsImpl(maxRows, scanLimits.getOffset());
                }
            }
            List<ColumnReferencesDiscovery> conditionsOnJoinedResult = new ArrayList<>();
            List<ScanStatement> scans = new ArrayList<>();
            for (Map.Entry<String, JoinSupport> join : joins.entrySet()) {
                String alias = join.getKey();
                JoinSupport joinSupport = join.getValue();
                Expression collectedConditionsForAlias = collectConditionsForAlias(alias, selectBody.getWhere(), conditionsOnJoinedResult, mainTableAlias);
                LOG.severe("Collected WHERE for alias " + alias + ": " + collectedConditionsForAlias);
                if (collectedConditionsForAlias == null) {
                    joinSupport.predicate = null;
                } else {
                    joinSupport.predicate = new SQLRecordPredicate(join.getValue().table, alias, collectedConditionsForAlias);
                }
            }
            for (Join join : selectBody.getJoins()) {
                if (join.getOnExpression() != null) {
                    ColumnReferencesDiscovery discoverMainTableAliasForJoinCondition = discoverMainTableAlias(join.getOnExpression());
                    conditionsOnJoinedResult.add(discoverMainTableAliasForJoinCondition);
                    LOG.severe("Collected ON-condition on final JOIN result: " + join.getOnExpression());
                }
            }
            for (ColumnReferencesDiscovery e : conditionsOnJoinedResult) {
                LOG.severe("Collected WHERE on final JOIN result: " + e.getExpression());
                for (Map.Entry<String, List<net.sf.jsqlparser.schema.Column>> entry : e.getColumnsByTable().entrySet()) {
                    String tableAlias = entry.getKey();
                    List<net.sf.jsqlparser.schema.Column> filteredColumnsOnJoin = entry.getValue();
                    LOG.severe("for  TABLE " + tableAlias + " we need to load " + filteredColumnsOnJoin);
                    JoinSupport support = joins.get(tableAlias);
                    if (support == null) {
                        throw new StatementExecutionException("invalid table alias " + tableAlias);
                    }
                    if (!support.allColumns) {
                        for (net.sf.jsqlparser.schema.Column c : filteredColumnsOnJoin) {
                            support.selectItems.add(new SelectExpressionItem(c));
                        }
                        support.projection = new SQLProjection(support.table, support.tableRef.tableAlias, support.selectItems);
                    }
                }
            }
            Map<String, Table> tables = new HashMap<>();
            for (Map.Entry<String, JoinSupport> join : joins.entrySet()) {
                JoinSupport joinSupport = join.getValue();
                tables.put(join.getKey(), joinSupport.table);
                ScanStatement statement = new ScanStatement(tableSpace, joinSupport.table.name, joinSupport.projection, joinSupport.predicate, null, null);
                scans.add(statement);
            }
            TuplePredicate joinFilter = null;
            if (!conditionsOnJoinedResult.isEmpty()) {
                joinFilter = new SQLRecordPredicate(null, null, composeAndExpression(conditionsOnJoinedResult));
            }
            Projection joinProjection = null;
            if (!allColumns) {
                joinProjection = new SQLProjection(tableSpace, tables, selectBody.getSelectItems());
            }
            TupleComparator comparatorOnPlan = null;
            if (selectBody.getOrderByElements() != null && !selectBody.getOrderByElements().isEmpty()) {
                comparatorOnPlan = SingleColumnSQLTupleComparator.make(mainTableAlias, selectBody.getOrderByElements(), null);
            }
            try {
                return ExecutionPlan.joinedScan(scans, joinFilter, joinProjection, scanLimits, comparatorOnPlan);
            } catch (IllegalArgumentException err) {
                throw new StatementExecutionException(err);
            }
        }
    } else {
        if (selectBody.getWhere() == null) {
            throw new StatementExecutionException("unsupported GET without WHERE");
        }
        if (joinPresent) {
            throw new StatementExecutionException("unsupported GET with JOIN");
        }
        // SELECT * FROM WHERE KEY=? AND ....
        SQLRecordKeyFunction keyFunction = findPrimaryKeyIndexSeek(selectBody.getWhere(), table, mainTableAlias);
        if (keyFunction == null || !keyFunction.isFullPrimaryKey()) {
            throw new StatementExecutionException("unsupported GET not on PK, bad where clause: " + selectBody.getWhere() + " (" + selectBody.getWhere().getClass() + ")");
        }
        Predicate where = buildSimplePredicate(selectBody.getWhere(), table, mainTableAlias);
        try {
            return ExecutionPlan.simple(new GetStatement(tableSpace, mainTable.tableName, keyFunction, where, false));
        } catch (IllegalArgumentException err) {
            throw new StatementExecutionException(err);
        }
    }
}
Also used : TuplePredicate(herddb.model.TuplePredicate) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Projection(herddb.model.Projection) StatementExecutionException(herddb.model.StatementExecutionException) LinkedHashMap(java.util.LinkedHashMap) TuplePredicate(herddb.model.TuplePredicate) Predicate(herddb.model.Predicate) TableSpaceManager(herddb.core.TableSpaceManager) ItemsList(net.sf.jsqlparser.expression.operators.relational.ItemsList) ArrayList(java.util.ArrayList) ExpressionList(net.sf.jsqlparser.expression.operators.relational.ExpressionList) ColumnsList(herddb.model.ColumnsList) MultiExpressionList(net.sf.jsqlparser.expression.operators.relational.MultiExpressionList) List(java.util.List) Top(net.sf.jsqlparser.statement.select.Top) AbstractTableManager(herddb.core.AbstractTableManager) GetStatement(herddb.model.commands.GetStatement) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) TableSpaceDoesNotExistException(herddb.model.TableSpaceDoesNotExistException) SelectExpressionItem(net.sf.jsqlparser.statement.select.SelectExpressionItem) PlainSelect(net.sf.jsqlparser.statement.select.PlainSelect) TupleComparator(herddb.model.TupleComparator) AllColumns(net.sf.jsqlparser.statement.select.AllColumns) Column(herddb.model.Column) SelectItem(net.sf.jsqlparser.statement.select.SelectItem) ScanStatement(herddb.model.commands.ScanStatement) Table(herddb.model.Table) CreateTable(net.sf.jsqlparser.statement.create.table.CreateTable) JdbcParameter(net.sf.jsqlparser.expression.JdbcParameter) Join(net.sf.jsqlparser.statement.select.Join) Aggregator(herddb.model.Aggregator) ScanLimitsImpl(herddb.model.ScanLimitsImpl) TableDoesNotExistException(herddb.model.TableDoesNotExistException) Expression(net.sf.jsqlparser.expression.Expression) AlterExpression(net.sf.jsqlparser.statement.alter.AlterExpression) BinaryExpression(net.sf.jsqlparser.expression.BinaryExpression) AndExpression(net.sf.jsqlparser.expression.operators.conditional.AndExpression) SignedExpression(net.sf.jsqlparser.expression.SignedExpression) CompiledSQLExpression(herddb.sql.expressions.CompiledSQLExpression) AllTableColumns(net.sf.jsqlparser.statement.select.AllTableColumns) Limit(net.sf.jsqlparser.statement.select.Limit)

Example 2 with Top

use of net.sf.jsqlparser.statement.select.Top in project dbeaver by dbeaver.

the class QueryTransformerTop method transformQueryString.

@Override
public String transformQueryString(SQLQuery query) throws DBCException {
    limitSet = false;
    if (query.isPlainSelect()) {
        try {
            Statement statement = query.getStatement();
            if (statement instanceof Select) {
                Select select = (Select) statement;
                if (select.getSelectBody() instanceof PlainSelect) {
                    PlainSelect selectBody = (PlainSelect) select.getSelectBody();
                    if (selectBody.getTop() == null && CommonUtils.isEmpty(selectBody.getIntoTables())) {
                        Top top = new Top();
                        top.setPercentage(false);
                        top.setExpression(new LongValue(offset.longValue() + length.longValue()));
                        selectBody.setTop(top);
                        limitSet = true;
                        return statement.toString();
                    }
                }
            }
        } catch (Throwable e) {
            // ignore
            log.debug(e);
        }
    }
    return query.getText();
}
Also used : Top(net.sf.jsqlparser.statement.select.Top) DBCStatement(org.jkiss.dbeaver.model.exec.DBCStatement) Statement(net.sf.jsqlparser.statement.Statement) Select(net.sf.jsqlparser.statement.select.Select) PlainSelect(net.sf.jsqlparser.statement.select.PlainSelect) PlainSelect(net.sf.jsqlparser.statement.select.PlainSelect) LongValue(net.sf.jsqlparser.expression.LongValue)

Example 3 with Top

use of net.sf.jsqlparser.statement.select.Top in project dbeaver by serge-rider.

the class QueryTransformerTop method transformQueryString.

@Override
public String transformQueryString(SQLQuery query) throws DBCException {
    limitSet = false;
    if (query.isPlainSelect()) {
        try {
            Statement statement = query.getStatement();
            if (statement instanceof Select) {
                Select select = (Select) statement;
                if (select.getSelectBody() instanceof PlainSelect) {
                    PlainSelect selectBody = (PlainSelect) select.getSelectBody();
                    if (selectBody.getTop() == null && CommonUtils.isEmpty(selectBody.getIntoTables())) {
                        Top top = new Top();
                        top.setPercentage(false);
                        top.setExpression(new LongValue(offset.longValue() + length.longValue()));
                        selectBody.setTop(top);
                        limitSet = true;
                        return statement.toString();
                    }
                }
            }
        } catch (Throwable e) {
            // ignore
            log.debug(e);
        }
    }
    return query.getText();
}
Also used : Top(net.sf.jsqlparser.statement.select.Top) DBCStatement(org.jkiss.dbeaver.model.exec.DBCStatement) Statement(net.sf.jsqlparser.statement.Statement) Select(net.sf.jsqlparser.statement.select.Select) PlainSelect(net.sf.jsqlparser.statement.select.PlainSelect) PlainSelect(net.sf.jsqlparser.statement.select.PlainSelect) LongValue(net.sf.jsqlparser.expression.LongValue)

Aggregations

PlainSelect (net.sf.jsqlparser.statement.select.PlainSelect)3 Top (net.sf.jsqlparser.statement.select.Top)3 LongValue (net.sf.jsqlparser.expression.LongValue)2 Statement (net.sf.jsqlparser.statement.Statement)2 AbstractTableManager (herddb.core.AbstractTableManager)1 TableSpaceManager (herddb.core.TableSpaceManager)1 Aggregator (herddb.model.Aggregator)1 Column (herddb.model.Column)1 ColumnsList (herddb.model.ColumnsList)1 Predicate (herddb.model.Predicate)1 Projection (herddb.model.Projection)1 ScanLimitsImpl (herddb.model.ScanLimitsImpl)1 StatementExecutionException (herddb.model.StatementExecutionException)1 Table (herddb.model.Table)1 TableDoesNotExistException (herddb.model.TableDoesNotExistException)1 TableSpaceDoesNotExistException (herddb.model.TableSpaceDoesNotExistException)1 TupleComparator (herddb.model.TupleComparator)1 TuplePredicate (herddb.model.TuplePredicate)1 GetStatement (herddb.model.commands.GetStatement)1 ScanStatement (herddb.model.commands.ScanStatement)1