Search in sources :

Example 1 with GridSqlAlias

use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.

the class DmlAstUtils method selectForUpdate.

/**
     * Generate SQL SELECT based on UPDATE's WHERE, LIMIT, etc.
     *
     * @param update Update statement.
     * @param keysParamIdx Index of new param for the array of keys.
     * @return SELECT statement.
     */
public static GridSqlSelect selectForUpdate(GridSqlUpdate update, @Nullable Integer keysParamIdx) {
    GridSqlSelect mapQry = new GridSqlSelect();
    mapQry.from(update.target());
    Set<GridSqlTable> tbls = new HashSet<>();
    collectAllGridTablesInTarget(update.target(), tbls);
    assert tbls.size() == 1 : "Failed to determine target table for UPDATE";
    GridSqlTable tbl = tbls.iterator().next();
    GridH2Table gridTbl = tbl.dataTable();
    assert gridTbl != null : "Failed to determine target grid table for UPDATE";
    Column h2KeyCol = gridTbl.getColumn(GridH2AbstractKeyValueRow.KEY_COL);
    Column h2ValCol = gridTbl.getColumn(GridH2AbstractKeyValueRow.VAL_COL);
    GridSqlColumn keyCol = new GridSqlColumn(h2KeyCol, tbl, h2KeyCol.getName());
    keyCol.resultType(GridSqlType.fromColumn(h2KeyCol));
    GridSqlColumn valCol = new GridSqlColumn(h2ValCol, tbl, h2ValCol.getName());
    valCol.resultType(GridSqlType.fromColumn(h2ValCol));
    mapQry.addColumn(keyCol, true);
    mapQry.addColumn(valCol, true);
    for (GridSqlColumn c : update.cols()) {
        String newColName = Parser.quoteIdentifier("_upd_" + c.columnName());
        // We have to use aliases to cover cases when the user
        // wants to update _val field directly (if it's a literal)
        GridSqlAlias alias = new GridSqlAlias(newColName, elementOrDefault(update.set().get(c.columnName()), c), true);
        alias.resultType(c.resultType());
        mapQry.addColumn(alias, true);
    }
    GridSqlElement where = update.where();
    if (keysParamIdx != null)
        where = injectKeysFilterParam(where, keyCol, keysParamIdx);
    mapQry.where(where);
    mapQry.limit(update.limit());
    return mapQry;
}
Also used : Column(org.h2.table.Column) GridH2Table(org.apache.ignite.internal.processors.query.h2.opt.GridH2Table) ValueString(org.h2.value.ValueString) HashSet(java.util.HashSet)

Example 2 with GridSqlAlias

use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.

the class DmlAstUtils method injectKeysFilterParam.

/**
 * Append additional condition to WHERE for it to select only specific keys.
 *
 * @param where Initial condition.
 * @param keyCol Column to base the new condition on.
 * @return New condition.
 */
private static GridSqlElement injectKeysFilterParam(GridSqlElement where, GridSqlColumn keyCol, int paramIdx) {
    // Yes, we need a subquery for "WHERE _key IN ?" to work with param being an array without dirty query rewriting.
    GridSqlSelect sel = new GridSqlSelect();
    GridSqlFunction from = new GridSqlFunction(GridSqlFunctionType.TABLE);
    sel.from(from);
    GridSqlColumn col = new GridSqlColumn(null, from, null, "TABLE", "_IGNITE_ERR_KEYS");
    sel.addColumn(col, true);
    GridSqlAlias alias = new GridSqlAlias("_IGNITE_ERR_KEYS", new GridSqlParameter(paramIdx));
    alias.resultType(keyCol.resultType());
    from.addChild(alias);
    GridSqlElement e = new GridSqlOperation(GridSqlOperationType.IN, keyCol, new GridSqlSubquery(sel));
    if (where == null)
        return e;
    else
        return new GridSqlOperation(GridSqlOperationType.AND, where, e);
}
Also used : GridSqlAlias(org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias) GridSqlSubquery(org.apache.ignite.internal.processors.query.h2.sql.GridSqlSubquery) GridSqlColumn(org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn) GridSqlParameter(org.apache.ignite.internal.processors.query.h2.sql.GridSqlParameter) GridSqlElement(org.apache.ignite.internal.processors.query.h2.sql.GridSqlElement) GridSqlFunction(org.apache.ignite.internal.processors.query.h2.sql.GridSqlFunction) GridSqlOperation(org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation) GridSqlSelect(org.apache.ignite.internal.processors.query.h2.sql.GridSqlSelect)

Example 3 with GridSqlAlias

use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.

the class QueryParser method mvccCacheIdForSelect.

/**
 * Get ID of the first MVCC cache for SELECT.
 *
 * @param objMap Object map.
 * @return ID of the first MVCC cache or {@code null} if no MVCC caches involved.
 */
private Integer mvccCacheIdForSelect(Map<Object, Object> objMap) {
    Boolean mvccEnabled = null;
    Integer mvccCacheId = null;
    GridCacheContextInfo cctx = null;
    for (Object o : objMap.values()) {
        if (o instanceof GridSqlAlias)
            o = GridSqlAlias.unwrap((GridSqlAst) o);
        if (o instanceof GridSqlTable && ((GridSqlTable) o).dataTable() != null) {
            GridSqlTable tbl = (GridSqlTable) o;
            if (tbl.dataTable() != null) {
                GridCacheContextInfo curCctx = tbl.dataTable().cacheInfo();
                assert curCctx != null;
                boolean curMvccEnabled = curCctx.config().getAtomicityMode() == CacheAtomicityMode.TRANSACTIONAL_SNAPSHOT;
                if (mvccEnabled == null) {
                    mvccEnabled = curMvccEnabled;
                    if (mvccEnabled)
                        mvccCacheId = curCctx.cacheId();
                    cctx = curCctx;
                } else if (mvccEnabled != curMvccEnabled)
                    MvccUtils.throwAtomicityModesMismatchException(cctx.config(), curCctx.config());
            }
        }
    }
    return mvccCacheId;
}
Also used : GridSqlAlias(org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias) GridSqlTable(org.apache.ignite.internal.processors.query.h2.sql.GridSqlTable) GridCacheContextInfo(org.apache.ignite.internal.processors.cache.GridCacheContextInfo)

Example 4 with GridSqlAlias

use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.

the class QueryParser method parseH2.

/**
 * Parse and split query if needed, cache either two-step query or statement.
 *
 * @param schemaName Schema name.
 * @param qry Query.
 * @param batched Batched flag.
 * @param remainingAllowed Whether multiple statements are allowed.
 * @return Parsing result.
 */
@SuppressWarnings("IfMayBeConditional")
private QueryParserResult parseH2(String schemaName, SqlFieldsQuery qry, boolean batched, boolean remainingAllowed) {
    try (H2PooledConnection c = connMgr.connection(schemaName)) {
        // For queries that are explicitly local, we rely on the flag specified in the query
        // because this parsing result will be cached and used for queries directly.
        // For other queries, we enforce join order at this stage to avoid premature optimizations
        // (and therefore longer parsing) as long as there'll be more parsing at split stage.
        boolean enforceJoinOrderOnParsing = (!qry.isLocal() || qry.isEnforceJoinOrder());
        QueryContext qctx = QueryContext.parseContext(idx.backupFilter(null, null), qry.isLocal());
        H2Utils.setupConnection(c, qctx, false, enforceJoinOrderOnParsing, false);
        PreparedStatement stmt = null;
        try {
            stmt = c.prepareStatementNoCache(qry.getSql());
            if (qry.isLocal() && GridSqlQueryParser.checkMultipleStatements(stmt))
                throw new IgniteSQLException("Multiple statements queries are not supported for local queries.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
            GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt);
            Prepared prepared = prep.prepared();
            if (GridSqlQueryParser.isExplainUpdate(prepared))
                throw new IgniteSQLException("Explains of update queries are not supported.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
            // Get remaining query and check if it is allowed.
            SqlFieldsQuery remainingQry = null;
            if (!F.isEmpty(prep.remainingSql())) {
                checkRemainingAllowed(remainingAllowed);
                remainingQry = cloneFieldsQuery(qry).setSql(prep.remainingSql());
            }
            // Prepare new query.
            SqlFieldsQuery newQry = cloneFieldsQuery(qry).setSql(prepared.getSQL());
            final int paramsCnt = prepared.getParameters().size();
            Object[] argsOrig = qry.getArgs();
            Object[] args = null;
            Object[] remainingArgs = null;
            if (!batched && paramsCnt > 0) {
                if (argsOrig == null || argsOrig.length < paramsCnt)
                    // Not enough parameters, but we will handle this later on execution phase.
                    args = argsOrig;
                else {
                    args = Arrays.copyOfRange(argsOrig, 0, paramsCnt);
                    if (paramsCnt != argsOrig.length)
                        remainingArgs = Arrays.copyOfRange(argsOrig, paramsCnt, argsOrig.length);
                }
            } else
                remainingArgs = argsOrig;
            newQry.setArgs(args);
            QueryDescriptor newQryDesc = queryDescriptor(schemaName, newQry);
            if (remainingQry != null)
                remainingQry.setArgs(remainingArgs);
            final List<JdbcParameterMeta> paramsMeta;
            try {
                paramsMeta = H2Utils.parametersMeta(stmt.getParameterMetaData());
                assert prepared.getParameters().size() == paramsMeta.size();
            } catch (IgniteCheckedException | SQLException e) {
                throw new IgniteSQLException("Failed to get parameters metadata", IgniteQueryErrorCode.UNKNOWN, e);
            }
            // Do actual parsing.
            if (CommandProcessor.isCommand(prepared)) {
                GridSqlStatement cmdH2 = new GridSqlQueryParser(false, log).parse(prepared);
                QueryParserResultCommand cmd = new QueryParserResultCommand(null, cmdH2, false);
                return new QueryParserResult(newQryDesc, queryParameters(newQry), remainingQry, paramsMeta, null, null, cmd);
            } else if (CommandProcessor.isCommandNoOp(prepared)) {
                QueryParserResultCommand cmd = new QueryParserResultCommand(null, null, true);
                return new QueryParserResult(newQryDesc, queryParameters(newQry), remainingQry, paramsMeta, null, null, cmd);
            } else if (GridSqlQueryParser.isDml(prepared)) {
                QueryParserResultDml dml = prepareDmlStatement(newQryDesc, prepared);
                return new QueryParserResult(newQryDesc, queryParameters(newQry), remainingQry, paramsMeta, null, dml, null);
            } else if (!prepared.isQuery()) {
                throw new IgniteSQLException("Unsupported statement: " + newQry.getSql(), IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
            }
            // Parse SELECT.
            GridSqlQueryParser parser = new GridSqlQueryParser(false, log);
            GridSqlQuery selectStmt = (GridSqlQuery) parser.parse(prepared);
            List<Integer> cacheIds = parser.cacheIds();
            Integer mvccCacheId = mvccCacheIdForSelect(parser.objectsMap());
            // Calculate if query is in fact can be executed locally.
            boolean loc = qry.isLocal();
            if (!loc) {
                if (parser.isLocalQuery())
                    loc = true;
            }
            // If this is a local query, check if it must be split.
            boolean locSplit = false;
            if (loc) {
                GridCacheContext cctx = parser.getFirstPartitionedCache();
                if (cctx != null && cctx.config().getQueryParallelism() > 1)
                    locSplit = true;
            }
            // Split is required either if query is distributed, or when it is local, but executed
            // over segmented PARTITIONED case. In this case multiple map queries will be executed against local
            // node stripes in parallel and then merged through reduce process.
            boolean splitNeeded = !loc || locSplit;
            String forUpdateQryOutTx = null;
            String forUpdateQryTx = null;
            GridCacheTwoStepQuery forUpdateTwoStepQry = null;
            boolean forUpdate = GridSqlQueryParser.isForUpdateQuery(prepared);
            // column to be able to lock selected rows further.
            if (forUpdate) {
                // We have checked above that it's not an UNION query, so it's got to be SELECT.
                assert selectStmt instanceof GridSqlSelect;
                // Check FOR UPDATE invariants: only one table, MVCC is there.
                if (cacheIds.size() != 1)
                    throw new IgniteSQLException("SELECT FOR UPDATE is supported only for queries " + "that involve single transactional cache.");
                if (mvccCacheId == null)
                    throw new IgniteSQLException("SELECT FOR UPDATE query requires transactional cache " + "with MVCC enabled.", IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
                // We need a copy because we are going to modify AST a bit. We do not want to modify original select.
                GridSqlSelect selForUpdate = ((GridSqlSelect) selectStmt).copySelectForUpdate();
                // Clear forUpdate flag to run it as a plain query.
                selForUpdate.forUpdate(false);
                ((GridSqlSelect) selectStmt).forUpdate(false);
                // Remember sql string without FOR UPDATE clause.
                forUpdateQryOutTx = selForUpdate.getSQL();
                GridSqlAlias keyCol = keyColumn(selForUpdate);
                selForUpdate.addColumn(keyCol, true);
                // Remember sql string without FOR UPDATE clause and with _key column.
                forUpdateQryTx = selForUpdate.getSQL();
                // Prepare additional two-step query for FOR UPDATE case.
                if (splitNeeded) {
                    c.schema(newQry.getSchema());
                    forUpdateTwoStepQry = GridSqlQuerySplitter.split(c, selForUpdate, forUpdateQryTx, newQry.isCollocated(), newQry.isDistributedJoins(), newQry.isEnforceJoinOrder(), locSplit, idx, paramsCnt, log);
                }
            }
            GridCacheTwoStepQuery twoStepQry = null;
            if (splitNeeded) {
                GridSubqueryJoinOptimizer.pullOutSubQueries(selectStmt);
                c.schema(newQry.getSchema());
                twoStepQry = GridSqlQuerySplitter.split(c, selectStmt, newQry.getSql(), newQry.isCollocated(), newQry.isDistributedJoins(), newQry.isEnforceJoinOrder(), locSplit, idx, paramsCnt, log);
            }
            List<GridQueryFieldMetadata> meta = H2Utils.meta(stmt.getMetaData());
            QueryParserResultSelect select = new QueryParserResultSelect(selectStmt, twoStepQry, forUpdateTwoStepQry, meta, cacheIds, mvccCacheId, forUpdateQryOutTx, forUpdateQryTx);
            return new QueryParserResult(newQryDesc, queryParameters(newQry), remainingQry, paramsMeta, select, null, null);
        } catch (IgniteCheckedException | SQLException e) {
            throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
        } finally {
            U.close(stmt, log);
        }
    }
}
Also used : GridSqlAlias(org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias) SQLException(java.sql.SQLException) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException) GridSqlStatement(org.apache.ignite.internal.processors.query.h2.sql.GridSqlStatement) Prepared(org.h2.command.Prepared) GridCacheTwoStepQuery(org.apache.ignite.internal.processors.cache.query.GridCacheTwoStepQuery) GridQueryFieldMetadata(org.apache.ignite.internal.processors.query.GridQueryFieldMetadata) IgniteCheckedException(org.apache.ignite.IgniteCheckedException) GridCacheContext(org.apache.ignite.internal.processors.cache.GridCacheContext) JdbcParameterMeta(org.apache.ignite.internal.processors.odbc.jdbc.JdbcParameterMeta) PreparedStatement(java.sql.PreparedStatement) QueryContext(org.apache.ignite.internal.processors.query.h2.opt.QueryContext) GridSqlSelect(org.apache.ignite.internal.processors.query.h2.sql.GridSqlSelect) SqlFieldsQuery(org.apache.ignite.cache.query.SqlFieldsQuery) GridSqlQuery(org.apache.ignite.internal.processors.query.h2.sql.GridSqlQuery) GridSqlQueryParser(org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser) IgniteSQLException(org.apache.ignite.internal.processors.query.IgniteSQLException)

Example 5 with GridSqlAlias

use of org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias in project ignite by apache.

the class PartitionExtractor method prepareTable.

/**
 * Prepare single table.
 *
 * @param from Expression.
 * @param tblModel Table model.
 * @return Added table or {@code null} if table is exlcuded from the model.
 */
private static PartitionTable prepareTable(GridSqlAst from, PartitionTableModel tblModel) {
    // Unwrap alias. We assume that every table must be aliased.
    assert from instanceof GridSqlAlias;
    String alias = ((GridSqlAlias) from).alias();
    from = from.child();
    if (from instanceof GridSqlTable) {
        // Normal table.
        GridSqlTable from0 = (GridSqlTable) from;
        GridH2Table tbl0 = from0.dataTable();
        // Unknown table type, e.g. temp table.
        if (tbl0 == null) {
            tblModel.addExcludedTable(alias);
            return null;
        }
        String cacheName = tbl0.cacheName();
        String affColName = null;
        String secondAffColName = null;
        for (Column col : tbl0.getColumns()) {
            if (tbl0.isColumnForPartitionPruningStrict(col)) {
                if (affColName == null)
                    affColName = col.getName();
                else {
                    secondAffColName = col.getName();
                    // Break as we cannot have more than two affinity key columns.
                    break;
                }
            }
        }
        PartitionTable tbl = new PartitionTable(alias, cacheName, affColName, secondAffColName);
        PartitionTableAffinityDescriptor aff = affinityForCache(tbl0.cacheInfo().config());
        if (aff == null) {
            // Non-standard affinity, exclude table.
            tblModel.addExcludedTable(alias);
            return null;
        }
        tblModel.addTable(tbl, aff);
        return tbl;
    } else {
        // Subquery/union/view, etc.
        assert alias != null;
        tblModel.addExcludedTable(alias);
        return null;
    }
}
Also used : PartitionTable(org.apache.ignite.internal.sql.optimizer.affinity.PartitionTable) GridSqlAlias(org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias) Column(org.h2.table.Column) GridSqlColumn(org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn) GridSqlTable(org.apache.ignite.internal.processors.query.h2.sql.GridSqlTable) GridH2Table(org.apache.ignite.internal.processors.query.h2.opt.GridH2Table) PartitionTableAffinityDescriptor(org.apache.ignite.internal.sql.optimizer.affinity.PartitionTableAffinityDescriptor)

Aggregations

GridSqlAlias (org.apache.ignite.internal.processors.query.h2.sql.GridSqlAlias)9 GridH2Table (org.apache.ignite.internal.processors.query.h2.opt.GridH2Table)8 GridSqlSelect (org.apache.ignite.internal.processors.query.h2.sql.GridSqlSelect)7 Column (org.h2.table.Column)7 GridSqlColumn (org.apache.ignite.internal.processors.query.h2.sql.GridSqlColumn)6 GridSqlTable (org.apache.ignite.internal.processors.query.h2.sql.GridSqlTable)6 GridSqlElement (org.apache.ignite.internal.processors.query.h2.sql.GridSqlElement)5 ArrayList (java.util.ArrayList)3 HashSet (java.util.HashSet)3 IgniteSQLException (org.apache.ignite.internal.processors.query.IgniteSQLException)3 GridSqlFunction (org.apache.ignite.internal.processors.query.h2.sql.GridSqlFunction)3 GridSqlOperation (org.apache.ignite.internal.processors.query.h2.sql.GridSqlOperation)3 GridSqlSubquery (org.apache.ignite.internal.processors.query.h2.sql.GridSqlSubquery)3 ValueString (org.h2.value.ValueString)3 GridCacheContext (org.apache.ignite.internal.processors.cache.GridCacheContext)2 GridSqlArray (org.apache.ignite.internal.processors.query.h2.sql.GridSqlArray)2 GridSqlAst (org.apache.ignite.internal.processors.query.h2.sql.GridSqlAst)2 GridSqlJoin (org.apache.ignite.internal.processors.query.h2.sql.GridSqlJoin)2 GridSqlQuery (org.apache.ignite.internal.processors.query.h2.sql.GridSqlQuery)2 GridSqlType.fromExpression (org.apache.ignite.internal.processors.query.h2.sql.GridSqlType.fromExpression)2