Search in sources :

Example 1 with UpdateStatement

use of org.datanucleus.store.rdbms.sql.UpdateStatement in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method compileQueryUpdate.

/**
 * Method to compile the query for RDBMS for a bulk update.
 * @param parameterValues The parameter values (if any)
 * @param candidateCmd Meta-data for the candidate class
 */
protected void compileQueryUpdate(Map parameterValues, AbstractClassMetaData candidateCmd) {
    Expression[] updateExprs = compilation.getExprUpdate();
    if (updateExprs == null || updateExprs.length == 0) {
        // Nothing to update
        return;
    }
    // Generate statement for candidate
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreClass candidateTbl = storeMgr.getDatastoreClass(candidateCmd.getFullClassName(), clr);
    if (candidateTbl == null) {
        throw new NucleusDataStoreException("Bulk update of " + candidateCmd.getFullClassName() + " not supported since candidate has no table of its own");
    }
    List<BulkTable> tables = new ArrayList<>();
    tables.add(new BulkTable(candidateTbl, true));
    if (candidateTbl.getSuperDatastoreClass() != null) {
        DatastoreClass tbl = candidateTbl;
        while (tbl.getSuperDatastoreClass() != null) {
            tbl = tbl.getSuperDatastoreClass();
            tables.add(new BulkTable(tbl, false));
        }
    }
    List<SQLStatement> stmts = new ArrayList<>();
    List<Boolean> stmtCountFlags = new ArrayList<>();
    for (BulkTable bulkTable : tables) {
        // Generate statement for candidate
        DatastoreClass table = bulkTable.table;
        Map<String, Object> extensions = null;
        if (!storeMgr.getDatastoreAdapter().supportsOption(DatastoreAdapter.UPDATE_DELETE_STATEMENT_ALLOW_TABLE_ALIAS_IN_WHERE_CLAUSE)) {
            extensions = new HashMap<>();
            extensions.put(SQLStatement.EXTENSION_SQL_TABLE_NAMING_STRATEGY, "table-name");
        }
        UpdateStatement stmt = new UpdateStatement(storeMgr, table, null, null, extensions);
        stmt.setClassLoaderResolver(clr);
        stmt.setCandidateClassName(candidateCmd.getFullClassName());
        JavaTypeMapping multitenancyMapping = table.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false);
        if (multitenancyMapping != null) {
            // Multi-tenancy restriction
            SQLExpression tenantExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), multitenancyMapping);
            SQLExpression tenantVal = stmt.getSQLExpressionFactory().newLiteral(stmt, multitenancyMapping, ec.getNucleusContext().getMultiTenancyId(ec, candidateCmd));
            stmt.whereAnd(tenantExpr.eq(tenantVal), true);
        }
        // TODO Discriminator restriction?
        JavaTypeMapping softDeleteMapping = table.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false);
        if (softDeleteMapping != null) {
            // Soft-delete restriction
            SQLExpression softDeleteExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), softDeleteMapping);
            SQLExpression softDeleteVal = stmt.getSQLExpressionFactory().newLiteral(stmt, softDeleteMapping, Boolean.FALSE);
            stmt.whereAnd(softDeleteExpr.eq(softDeleteVal), true);
        }
        Set<String> options = new HashSet<>();
        if (getBooleanExtensionProperty(EXTENSION_USE_IS_NULL_WHEN_EQUALS_NULL_PARAM, true)) {
            options.add(QueryToSQLMapper.OPTION_NULL_PARAM_USE_IS_NULL);
        }
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(stmt, compilation, parameterValues, null, null, candidateCmd, subclasses, getFetchPlan(), ec, null, options, extensions);
        setMapperJoinTypes(sqlMapper);
        sqlMapper.compile();
        if (stmt.hasUpdates()) {
            stmts.add(stmt);
            stmtCountFlags.add(bulkTable.useInCount);
            datastoreCompilation.setStatementParameters(stmt.getSQLText().getParametersForStatement());
            datastoreCompilation.setPrecompilable(sqlMapper.isPrecompilable());
        }
    }
    datastoreCompilation.clearStatements();
    Iterator<SQLStatement> stmtIter = stmts.iterator();
    Iterator<Boolean> stmtCountFlagsIter = stmtCountFlags.iterator();
    while (stmtIter.hasNext()) {
        SQLStatement stmt = stmtIter.next();
        Boolean useInCount = stmtCountFlagsIter.next();
        if (stmts.size() == 1) {
            useInCount = true;
        }
        datastoreCompilation.addStatement(stmt, stmt.getSQLText().toSQL(), useInCount);
    }
}
Also used : UpdateStatement(org.datanucleus.store.rdbms.sql.UpdateStatement) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ArrayList(java.util.ArrayList) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) Expression(org.datanucleus.query.expression.Expression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) HashSet(java.util.HashSet)

Example 2 with UpdateStatement

use of org.datanucleus.store.rdbms.sql.UpdateStatement in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method compile.

/**
 * Method to update the supplied SQLStatement with the components of the specified query.
 * During the compilation process this updates the SQLStatement "compileComponent" to the
 * component of the query being compiled.
 */
public void compile() {
    if (NucleusLogger.QUERY.isDebugEnabled() && parentMapper == null) {
        // Give debug output of compilation
        StringBuilder str = new StringBuilder("JoinType : navigation(default=");
        str.append(defaultJoinType != null ? defaultJoinType : "(using nullability)");
        str.append(", filter=");
        str.append(defaultJoinTypeFilter != null ? defaultJoinTypeFilter : "(using nullability)");
        str.append(")");
        if (extensionsByName != null) {
            Iterator<Map.Entry<String, Object>> extensionsIter = extensionsByName.entrySet().iterator();
            while (extensionsIter.hasNext()) {
                Map.Entry<String, Object> entry = extensionsIter.next();
                String key = entry.getKey();
                if (key.startsWith("datanucleus.query.jdoql.") && key.endsWith(".join")) {
                    // Alias join definition
                    String alias = key.substring("datanucleus.query.jdoql.".length(), key.lastIndexOf(".join"));
                    str.append(", ").append(alias).append("=").append(entry.getValue());
                }
            }
        }
        NucleusLogger.QUERY.debug("Compile of " + compilation.getQueryLanguage() + " into SQL - " + str);
    }
    compileFrom();
    compileFilter();
    if (stmt instanceof UpdateStatement) {
        compileUpdate((UpdateStatement) stmt);
    } else if (stmt instanceof SelectStatement) {
        SelectStatement selectStmt = (SelectStatement) stmt;
        // the datastore doesn't allow select of some field types when used with DISTINCT
        if (compilation.getResultDistinct()) {
            selectStmt.setDistinct(true);
        } else if (!options.contains(OPTION_EXPLICIT_JOINS) && compilation.getExprResult() == null) {
            // Joins are made implicitly and no result so set distinct based on whether joining to other table groups
            if (selectStmt.getNumberOfTableGroups() > 1) {
                // Queries against an extent always consider only distinct candidate instances, regardless of whether distinct is specified (JDO spec)
                if (!options.contains(OPTION_NON_DISTINCT_IMPLICIT_JOINS)) {
                    // If user can guarantee distinct w/ query no reason to take performance hit of distinct clause
                    selectStmt.setDistinct(true);
                }
            }
        }
        compileResult(selectStmt);
        compileGrouping(selectStmt);
        compileHaving(selectStmt);
        compileOrdering(selectStmt);
    }
    // Check for variables that haven't been bound to the query (declared but not used)
    for (String symbol : compilation.getSymbolTable().getSymbolNames()) {
        Symbol sym = compilation.getSymbolTable().getSymbol(symbol);
        if (sym.getType() == Symbol.VARIABLE) {
            if (compilation.getCompilationForSubquery(sym.getQualifiedName()) == null && !hasSQLTableMappingForAlias(sym.getQualifiedName())) {
                // Variable not a subquery, nor had its table allocated
                throw new QueryCompilerSyntaxException("Query has variable \"" + sym.getQualifiedName() + "\" which is not bound to the query");
            }
        }
    }
}
Also used : SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) UpdateStatement(org.datanucleus.store.rdbms.sql.UpdateStatement) Symbol(org.datanucleus.query.compiler.Symbol) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 3 with UpdateStatement

use of org.datanucleus.store.rdbms.sql.UpdateStatement in project datanucleus-rdbms by datanucleus.

the class JPQLQuery method compileQueryUpdate.

/**
 * Method to compile the query for RDBMS for a bulk update.
 * @param parameterValues The parameter values (if any)
 * @param candidateCmd Meta-data for the candidate class
 */
protected void compileQueryUpdate(Map parameterValues, AbstractClassMetaData candidateCmd) {
    Expression[] updateExprs = compilation.getExprUpdate();
    if (updateExprs == null || updateExprs.length == 0) {
        // Nothing to update
        return;
    }
    // Generate statement for candidate and related classes in this inheritance tree
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreClass candidateTbl = storeMgr.getDatastoreClass(candidateCmd.getFullClassName(), clr);
    if (candidateTbl == null) {
        // TODO Using subclass-table, so find the table(s) it can be persisted into
        throw new NucleusDataStoreException("Bulk update of " + candidateCmd.getFullClassName() + " not supported since candidate has no table of its own");
    }
    // Find tables potentially affected by this UPDATE statement
    List<BulkTable> tables = new ArrayList<>();
    tables.add(new BulkTable(candidateTbl, true));
    if (candidateTbl.getSuperDatastoreClass() != null) {
        DatastoreClass tbl = candidateTbl;
        while (tbl.getSuperDatastoreClass() != null) {
            tbl = tbl.getSuperDatastoreClass();
            tables.add(new BulkTable(tbl, false));
        }
    }
    List<SQLStatement> stmts = new ArrayList<>();
    List<Boolean> stmtCountFlags = new ArrayList<>();
    for (BulkTable bulkTable : tables) {
        // Generate statement for candidate
        DatastoreClass table = bulkTable.table;
        Map<String, Object> extensions = null;
        if (!storeMgr.getDatastoreAdapter().supportsOption(DatastoreAdapter.UPDATE_DELETE_STATEMENT_ALLOW_TABLE_ALIAS_IN_WHERE_CLAUSE)) {
            extensions = new HashMap<>();
            extensions.put(SQLStatement.EXTENSION_SQL_TABLE_NAMING_STRATEGY, "table-name");
        }
        UpdateStatement stmt = new UpdateStatement(storeMgr, table, null, null, extensions);
        stmt.setClassLoaderResolver(clr);
        stmt.setCandidateClassName(candidateCmd.getFullClassName());
        JavaTypeMapping multitenancyMapping = table.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false);
        if (multitenancyMapping != null) {
            // Multi-tenancy restriction
            SQLExpression tenantExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), multitenancyMapping);
            SQLExpression tenantVal = stmt.getSQLExpressionFactory().newLiteral(stmt, multitenancyMapping, ec.getNucleusContext().getMultiTenancyId(ec, candidateCmd));
            stmt.whereAnd(tenantExpr.eq(tenantVal), true);
        }
        // TODO Discriminator restriction?
        JavaTypeMapping softDeleteMapping = table.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false);
        if (softDeleteMapping != null) {
            // Soft-delete restriction
            SQLExpression softDeleteExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), softDeleteMapping);
            SQLExpression softDeleteVal = stmt.getSQLExpressionFactory().newLiteral(stmt, softDeleteMapping, Boolean.FALSE);
            stmt.whereAnd(softDeleteExpr.eq(softDeleteVal), true);
        }
        Set<String> options = new HashSet<>();
        options.add(QueryToSQLMapper.OPTION_CASE_INSENSITIVE);
        options.add(QueryToSQLMapper.OPTION_EXPLICIT_JOINS);
        if (// Default to false for "IS NULL" with null param
        getBooleanExtensionProperty(EXTENSION_USE_IS_NULL_WHEN_EQUALS_NULL_PARAM, false)) {
            options.add(QueryToSQLMapper.OPTION_NULL_PARAM_USE_IS_NULL);
        }
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(stmt, compilation, parameterValues, null, null, candidateCmd, subclasses, getFetchPlan(), ec, null, options, extensions);
        setMapperJoinTypes(sqlMapper);
        sqlMapper.compile();
        if (stmt.hasUpdates()) {
            stmts.add(stmt);
            stmtCountFlags.add(bulkTable.useInCount);
            datastoreCompilation.setStatementParameters(stmt.getSQLText().getParametersForStatement());
            datastoreCompilation.setPrecompilable(sqlMapper.isPrecompilable());
        }
    }
    datastoreCompilation.clearStatements();
    Iterator<SQLStatement> stmtIter = stmts.iterator();
    Iterator<Boolean> stmtCountFlagsIter = stmtCountFlags.iterator();
    while (stmtIter.hasNext()) {
        SQLStatement stmt = stmtIter.next();
        Boolean useInCount = stmtCountFlagsIter.next();
        if (stmts.size() == 1) {
            useInCount = true;
        }
        datastoreCompilation.addStatement(stmt, stmt.getSQLText().toSQL(), useInCount);
    }
}
Also used : UpdateStatement(org.datanucleus.store.rdbms.sql.UpdateStatement) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ArrayList(java.util.ArrayList) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) Expression(org.datanucleus.query.expression.Expression) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) HashSet(java.util.HashSet)

Aggregations

UpdateStatement (org.datanucleus.store.rdbms.sql.UpdateStatement)3 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)2 Expression (org.datanucleus.query.expression.Expression)2 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)2 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)2 SQLStatement (org.datanucleus.store.rdbms.sql.SQLStatement)2 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)2 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)2 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Symbol (org.datanucleus.query.compiler.Symbol)1 QueryCompilerSyntaxException (org.datanucleus.store.query.QueryCompilerSyntaxException)1 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)1 BooleanExpression (org.datanucleus.store.rdbms.sql.expression.BooleanExpression)1 ColumnExpression (org.datanucleus.store.rdbms.sql.expression.ColumnExpression)1