Search in sources :

Example 1 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class OracleClobRDBMSMapping method updateClobColumn.

/**
 * Convenience method to update the contents of a CLOB column.
 * Oracle requires that a CLOB is initialised with EMPTY_CLOB() and then you retrieve
 * the column and update its CLOB value. Performs a statement
 * <pre>
 * SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE
 * </pre>
 * and then updates the Clob value returned.
 * @param op ObjectProvider of the object
 * @param table Table storing the CLOB column
 * @param mapping Datastore mapping for the CLOB column
 * @param value The value to store in the CLOB
 * @throws NucleusObjectNotFoundException Thrown if an object is not found
 * @throws NucleusDataStoreException Thrown if an error occurs in datastore communication
 */
@SuppressWarnings("deprecation")
public static void updateClobColumn(ObjectProvider op, Table table, DatastoreMapping mapping, String value) {
    ExecutionContext ec = op.getExecutionContext();
    RDBMSStoreManager storeMgr = table.getStoreManager();
    // Don't support join tables yet
    DatastoreClass classTable = (DatastoreClass) table;
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    // Generate "SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE" statement
    SelectStatement sqlStmt = new SelectStatement(storeMgr, table, null, null);
    sqlStmt.setClassLoaderResolver(ec.getClassLoaderResolver());
    sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
    SQLTable blobSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), mapping.getJavaTypeMapping());
    sqlStmt.select(blobSqlTbl, mapping.getColumn(), null);
    StatementClassMapping mappingDefinition = new StatementClassMapping();
    AbstractClassMetaData cmd = op.getClassMetaData();
    int inputParamNum = 1;
    if (cmd.getIdentityType() == IdentityType.DATASTORE) {
        // Datastore identity value for input
        JavaTypeMapping datastoreIdMapping = classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
        SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), datastoreIdMapping);
        SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, datastoreIdMapping, null, "ID");
        sqlStmt.whereAnd(expr.eq(val), true);
        StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
        if (datastoreIdx == null) {
            datastoreIdx = new StatementMappingIndex(datastoreIdMapping);
            mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdx);
        }
        datastoreIdx.addParameterOccurrence(new int[] { inputParamNum });
    } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
        // Application identity value(s) for input
        int[] pkNums = cmd.getPKMemberPositions();
        for (int i = 0; i < pkNums.length; i++) {
            AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkNums[i]);
            JavaTypeMapping pkMapping = classTable.getMemberMapping(mmd);
            SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), pkMapping);
            SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, pkMapping, null, "PK" + i);
            sqlStmt.whereAnd(expr.eq(val), true);
            StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNums[i]);
            if (pkIdx == null) {
                pkIdx = new StatementMappingIndex(pkMapping);
                mappingDefinition.addMappingForMember(pkNums[i], pkIdx);
            }
            int[] inputParams = new int[pkMapping.getNumberOfDatastoreMappings()];
            for (int j = 0; j < pkMapping.getNumberOfDatastoreMappings(); j++) {
                inputParams[j] = inputParamNum++;
            }
            pkIdx.addParameterOccurrence(inputParams);
        }
    }
    String textStmt = sqlStmt.getSQLText().toSQL();
    if (op.isEmbedded()) {
        // This mapping is embedded, so navigate back to the real owner since that is the "id" in the table
        ObjectProvider[] embeddedOwners = ec.getOwnersForEmbeddedObjectProvider(op);
        if (embeddedOwners != null) {
            // Just use the first owner
            // TODO Should check if the owner is stored in this table
            op = embeddedOwners[0];
        }
    }
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, textStmt);
            try {
                // Provide the primary key field(s) to the JDBC statement
                if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                    StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
                    for (int i = 0; i < datastoreIdx.getNumberOfParameterOccurrences(); i++) {
                        classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, datastoreIdx.getParameterPositionsForOccurrence(i), op.getInternalObjectId());
                    }
                } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                    op.provideFields(cmd.getPKMemberPositions(), new ParameterSetter(op, ps, mappingDefinition));
                }
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, textStmt, ps);
                try {
                    if (!rs.next()) {
                        throw new NucleusObjectNotFoundException("No such database row", op.getInternalObjectId());
                    }
                    DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
                    int jdbcMajorVersion = dba.getDriverMajorVersion();
                    if (dba.getDatastoreDriverName().equalsIgnoreCase(OracleAdapter.OJDBC_DRIVER_NAME) && jdbcMajorVersion < 10) {
                        // Oracle JDBC drivers version 9 and below use some sh*tty Oracle-specific CLOB type
                        // we have to cast to that, face west, pray whilst saying ommmmmmmmmmm
                        oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob(1);
                        if (clob != null) {
                            // Deprecated but what can you do
                            clob.putString(1, value);
                        }
                    } else {
                        // Oracle JDBC drivers 10 and above supposedly use the JDBC standard class for Clobs
                        java.sql.Clob clob = rs.getClob(1);
                        if (clob != null) {
                            clob.setString(1, value);
                        }
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        throw new NucleusDataStoreException("Update of CLOB value failed: " + textStmt, e);
    }
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SQLController(org.datanucleus.store.rdbms.SQLController) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) PreparedStatement(java.sql.PreparedStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) ExecutionContext(org.datanucleus.ExecutionContext) ObjectProvider(org.datanucleus.state.ObjectProvider) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 2 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class RDBMSQueryUtils method getPreparedStatementForQuery.

/**
 * Method to create a PreparedStatement for use with the query.
 * @param conn the Connection
 * @param queryStmt The statement text for the query
 * @param query The query
 * @return the PreparedStatement
 * @throws SQLException Thrown if an error occurs creating the statement
 */
public static PreparedStatement getPreparedStatementForQuery(ManagedConnection conn, String queryStmt, Query query) throws SQLException {
    // Apply any non-standard result set definition if required (either from the PMF, or via query extensions)
    String rsTypeString = RDBMSQueryUtils.getResultSetTypeForQuery(query);
    if (rsTypeString != null && (!rsTypeString.equals(QUERY_RESULTSET_TYPE_SCROLL_SENSITIVE) && !rsTypeString.equals(QUERY_RESULTSET_TYPE_FORWARD_ONLY) && !rsTypeString.equals(QUERY_RESULTSET_TYPE_SCROLL_INSENSITIVE))) {
        throw new NucleusUserException(Localiser.msg("052510"));
    }
    if (rsTypeString != null) {
        DatastoreAdapter dba = ((RDBMSStoreManager) query.getStoreManager()).getDatastoreAdapter();
        // Add checks on what the DatastoreAdapter supports
        if (rsTypeString.equals(QUERY_RESULTSET_TYPE_SCROLL_SENSITIVE) && !dba.supportsOption(DatastoreAdapter.RESULTSET_TYPE_SCROLL_SENSITIVE)) {
            rsTypeString = QUERY_RESULTSET_TYPE_FORWARD_ONLY;
            NucleusLogger.DATASTORE_RETRIEVE.info("Query requested to run with result-set type of " + rsTypeString + " yet not supported by adapter. Using " + rsTypeString);
        } else if (rsTypeString.equals(QUERY_RESULTSET_TYPE_SCROLL_INSENSITIVE) && !dba.supportsOption(DatastoreAdapter.RESULTSET_TYPE_SCROLL_INSENSITIVE)) {
            rsTypeString = QUERY_RESULTSET_TYPE_FORWARD_ONLY;
            NucleusLogger.DATASTORE_RETRIEVE.info("Query requested to run with result-set type of " + rsTypeString + " yet not supported by adapter. Using " + rsTypeString);
        } else if (rsTypeString.equals(QUERY_RESULTSET_TYPE_FORWARD_ONLY) && !dba.supportsOption(DatastoreAdapter.RESULTSET_TYPE_FORWARD_ONLY)) {
            rsTypeString = QUERY_RESULTSET_TYPE_SCROLL_SENSITIVE;
            NucleusLogger.DATASTORE_RETRIEVE.info("Query requested to run with result-set type of " + rsTypeString + " yet not supported by adapter. Using " + rsTypeString);
        }
    }
    String rsConcurrencyString = RDBMSQueryUtils.getResultSetConcurrencyForQuery(query);
    if (rsConcurrencyString != null && (!rsConcurrencyString.equals(QUERY_RESULTSET_CONCURRENCY_READONLY) && !rsConcurrencyString.equals(QUERY_RESULTSET_CONCURRENCY_UPDATEABLE))) {
        throw new NucleusUserException(Localiser.msg("052511"));
    }
    SQLController sqlControl = ((RDBMSStoreManager) query.getStoreManager()).getSQLController();
    PreparedStatement ps = sqlControl.getStatementForQuery(conn, queryStmt, rsTypeString, rsConcurrencyString);
    return ps;
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) PreparedStatement(java.sql.PreparedStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SQLController(org.datanucleus.store.rdbms.SQLController)

Example 3 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class SQLQuery method performExecute.

/**
 * Execute the query and return the result.
 * For a SELECT query this will be the QueryResult.
 * For an UPDATE/DELETE it will be the row count for the update statement.
 * @param parameters the Map containing all of the parameters (positional parameters) (not null)
 * @return the result of the query
 */
protected Object performExecute(Map parameters) {
    if (parameters.size() != (parameterNames != null ? parameterNames.length : 0)) {
        throw new NucleusUserException(Localiser.msg("059019", (parameterNames != null) ? "" + parameterNames.length : 0, "" + parameters.size()));
    }
    if (type == QueryType.BULK_DELETE || type == QueryType.BULK_UPDATE) {
        // Update/Delete statement (INSERT/UPDATE/DELETE/MERGE)
        try {
            RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try {
                PreparedStatement ps = sqlControl.getStatementForUpdate(mconn, compiledSQL, false);
                try {
                    // Set the values of any parameters
                    for (int i = 0; i < parameters.size(); i++) {
                        ps.setObject((i + 1), parameters.get(Integer.valueOf(i + 1)));
                    }
                    // Execute the update statement
                    int[] rcs = sqlControl.executeStatementUpdate(ec, mconn, compiledSQL, ps, true);
                    // Return a single Long with the number of records updated
                    return Long.valueOf(rcs[0]);
                } finally {
                    sqlControl.closeStatement(mconn, ps);
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException e) {
            throw new NucleusDataStoreException(Localiser.msg("059025", compiledSQL), e);
        }
    } else if (type == QueryType.SELECT) {
        // Query statement (SELECT, stored-procedure)
        AbstractRDBMSQueryResult qr = null;
        try {
            RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try {
                PreparedStatement ps = RDBMSQueryUtils.getPreparedStatementForQuery(mconn, compiledSQL, this);
                try {
                    // Set the values of any parameters
                    for (int i = 0; i < parameters.size(); i++) {
                        ps.setObject((i + 1), parameters.get(Integer.valueOf(i + 1)));
                    }
                    // Apply any user-specified constraints over timeouts and ResultSet
                    RDBMSQueryUtils.prepareStatementForExecution(ps, this, true);
                    ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, compiledSQL, ps);
                    try {
                        // Generate a ResultObjectFactory
                        ResultObjectFactory rof = null;
                        if (resultMetaData != null) {
                            // Each row of the ResultSet is defined by MetaData
                            rof = new ResultMetaDataROF(ec, rs, ignoreCache, resultMetaData);
                        } else if (resultClass != null || candidateClass == null) {
                            // Each row of the ResultSet is either an instance of resultClass, or Object[]
                            rof = RDBMSQueryUtils.getResultObjectFactoryForNoCandidateClass(ec, rs, resultClass);
                        } else {
                            // Each row of the ResultSet is an instance of the candidate class
                            rof = getResultObjectFactoryForCandidateClass(rs);
                        }
                        // Return the associated type of results depending on whether scrollable or not
                        qr = RDBMSQueryUtils.getQueryResultForQuery(this, rof, rs, null);
                        qr.initialise();
                        final QueryResult qr1 = qr;
                        final ManagedConnection mconn1 = mconn;
                        mconn.addListener(new ManagedConnectionResourceListener() {

                            public void transactionFlushed() {
                            }

                            public void transactionPreClose() {
                                // Disconnect the query from this ManagedConnection (read in unread rows etc)
                                qr1.disconnect();
                            }

                            public void managedConnectionPreClose() {
                                if (!ec.getTransaction().isActive()) {
                                    // Disconnect the query from this ManagedConnection (read in unread rows etc)
                                    qr1.disconnect();
                                }
                            }

                            public void managedConnectionPostClose() {
                            }

                            public void resourcePostClose() {
                                mconn1.removeListener(this);
                            }
                        });
                    } finally {
                        if (qr == null) {
                            rs.close();
                        }
                    }
                } catch (QueryInterruptedException qie) {
                    // Execution was cancelled so cancel the PreparedStatement
                    ps.cancel();
                    throw qie;
                } finally {
                    if (qr == null) {
                        sqlControl.closeStatement(mconn, ps);
                    }
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException e) {
            throw new NucleusDataStoreException(Localiser.msg("059025", compiledSQL), e);
        }
        return qr;
    } else {
        // 'Other' statement (manually invoked stored-procedure?, CREATE?, DROP?, or similar)
        try {
            RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            try {
                PreparedStatement ps = RDBMSQueryUtils.getPreparedStatementForQuery(mconn, compiledSQL, this);
                try {
                    // Set the values of any parameters
                    for (int i = 0; i < parameters.size(); i++) {
                        ps.setObject((i + 1), parameters.get(Integer.valueOf(i + 1)));
                    }
                    // Apply any user-specified constraints over timeouts etc
                    RDBMSQueryUtils.prepareStatementForExecution(ps, this, false);
                    sqlControl.executeStatement(ec, mconn, compiledSQL, ps);
                } catch (QueryInterruptedException qie) {
                    // Execution was cancelled so cancel the PreparedStatement
                    ps.cancel();
                    throw qie;
                } finally {
                    sqlControl.closeStatement(mconn, ps);
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException e) {
            throw new NucleusDataStoreException(Localiser.msg("059025", compiledSQL), e);
        }
        return true;
    }
}
Also used : SQLException(java.sql.SQLException) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) PreparedStatement(java.sql.PreparedStatement) ManagedConnectionResourceListener(org.datanucleus.store.connection.ManagedConnectionResourceListener) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SQLController(org.datanucleus.store.rdbms.SQLController) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) QueryResult(org.datanucleus.store.query.QueryResult) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) QueryInterruptedException(org.datanucleus.store.query.QueryInterruptedException)

Example 4 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class SQLQuery method getResultObjectFactoryForCandidateClass.

/**
 * Method to generate a ResultObjectFactory for converting rows of the provided ResultSet into instances of the candidate class.
 * Populates "stmtMappings".
 * @param rs The ResultSet
 * @return The ResultObjectFactory
 * @throws SQLException Thrown if an error occurs processing the ResultSet
 */
protected ResultObjectFactory getResultObjectFactoryForCandidateClass(ResultSet rs) throws SQLException {
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
    // Create an index listing for ALL (fetchable) fields in the result class.
    final AbstractClassMetaData candidateCmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
    int fieldCount = candidateCmd.getNoOfManagedMembers() + candidateCmd.getNoOfInheritedManagedMembers();
    // Map of field numbers keyed by the column name
    Map columnFieldNumberMap = new HashMap();
    stmtMappings = new StatementMappingIndex[fieldCount];
    DatastoreClass tbl = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
    for (int fieldNumber = 0; fieldNumber < fieldCount; ++fieldNumber) {
        AbstractMemberMetaData mmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        String fieldName = mmd.getName();
        Class fieldType = mmd.getType();
        JavaTypeMapping m = null;
        if (mmd.getPersistenceModifier() != FieldPersistenceModifier.NONE) {
            if (tbl != null) {
                // Get the field mapping from the candidate table
                m = tbl.getMemberMapping(mmd);
            } else {
                // Fall back to generating a mapping for this type - does this ever happen?
                m = storeMgr.getMappingManager().getMappingWithDatastoreMapping(fieldType, false, false, clr);
            }
            if (m.includeInFetchStatement()) {
                // Set mapping for this field since it can potentially be returned from a fetch
                String columnName = null;
                if (mmd.getColumnMetaData() != null && mmd.getColumnMetaData().length > 0) {
                    for (int colNum = 0; colNum < mmd.getColumnMetaData().length; colNum++) {
                        columnName = mmd.getColumnMetaData()[colNum].getName();
                        columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
                    }
                } else {
                    columnName = storeMgr.getIdentifierFactory().newColumnIdentifier(fieldName, ec.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fieldType), FieldRole.ROLE_NONE, false).getName();
                    columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
                }
            } else {
            // Don't put anything in this position (field has no column in the result set)
            }
        } else {
        // Don't put anything in this position (field has no column in the result set)
        }
        stmtMappings[fieldNumber] = new StatementMappingIndex(m);
    }
    if (columnFieldNumberMap.size() == 0) {
        // None of the fields in the class have columns in the datastore table!
        throw new NucleusUserException(Localiser.msg("059030", candidateClass.getName())).setFatal();
    }
    // Generate id column field information for later checking the id is present
    DatastoreClass table = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
    if (table == null) {
        AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(candidateCmd, clr);
        if (cmds != null && cmds.length == 1) {
            table = storeMgr.getDatastoreClass(cmds[0].getFullClassName(), clr);
        } else {
            throw new NucleusUserException("SQL query specified with class " + candidateClass.getName() + " but this doesn't have its own table, or is mapped to multiple tables. Unsupported");
        }
    }
    PersistableMapping idMapping = (PersistableMapping) table.getIdMapping();
    String[] idColNames = new String[idMapping.getNumberOfDatastoreMappings()];
    for (int i = 0; i < idMapping.getNumberOfDatastoreMappings(); i++) {
        idColNames[i] = idMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString();
    }
    // Generate discriminator information for later checking it is present
    JavaTypeMapping discrimMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
    String discrimColName = discrimMapping != null ? discrimMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
    // Generate version information for later checking it is present
    JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
    String versionColName = versionMapping != null ? versionMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
    // Go through the fields of the ResultSet and map to the required fields in the candidate
    ResultSetMetaData rsmd = rs.getMetaData();
    // TODO We put nothing in this, so what is it for?!
    HashSet remainingColumnNames = new HashSet(columnFieldNumberMap.size());
    int colCount = rsmd.getColumnCount();
    int[] datastoreIndex = null;
    int[] versionIndex = null;
    int[] discrimIndex = null;
    int[] matchedFieldNumbers = new int[colCount];
    int fieldNumberPosition = 0;
    for (int colNum = 1; colNum <= colCount; ++colNum) {
        String colName = rsmd.getColumnName(colNum);
        // Find the field for this column
        int fieldNumber = -1;
        Integer fieldNum = (Integer) columnFieldNumberMap.get(colName);
        if (fieldNum == null) {
            // Try column name in lowercase
            fieldNum = (Integer) columnFieldNumberMap.get(colName.toLowerCase());
            if (fieldNum == null) {
                // Try column name in UPPERCASE
                fieldNum = (Integer) columnFieldNumberMap.get(colName.toUpperCase());
            }
        }
        if (fieldNum != null) {
            fieldNumber = fieldNum.intValue();
        }
        if (fieldNumber >= 0) {
            int[] exprIndices = null;
            if (stmtMappings[fieldNumber].getColumnPositions() != null) {
                exprIndices = new int[stmtMappings[fieldNumber].getColumnPositions().length + 1];
                for (int i = 0; i < stmtMappings[fieldNumber].getColumnPositions().length; i++) {
                    exprIndices[i] = stmtMappings[fieldNumber].getColumnPositions()[i];
                }
                exprIndices[exprIndices.length - 1] = colNum;
            } else {
                exprIndices = new int[] { colNum };
            }
            stmtMappings[fieldNumber].setColumnPositions(exprIndices);
            remainingColumnNames.remove(colName);
            matchedFieldNumbers[fieldNumberPosition++] = fieldNumber;
        }
        if (discrimColName != null && colName.equals(discrimColName)) {
            // Identify the location of the discriminator column
            discrimIndex = new int[1];
            discrimIndex[0] = colNum;
        }
        if (versionColName != null && colName.equals(versionColName)) {
            // Identify the location of the version column
            versionIndex = new int[1];
            versionIndex[0] = colNum;
        }
        if (candidateCmd.getIdentityType() == IdentityType.DATASTORE) {
            // Check for existence of id column, allowing for any RDBMS using quoted identifiers
            if (columnNamesAreTheSame(dba, idColNames[0], colName)) {
                datastoreIndex = new int[1];
                datastoreIndex[0] = colNum;
            }
        }
    }
    // Set the field numbers found to match what we really have
    int[] fieldNumbers = new int[fieldNumberPosition];
    for (int i = 0; i < fieldNumberPosition; i++) {
        fieldNumbers[i] = matchedFieldNumbers[i];
    }
    StatementClassMapping mappingDefinition = new StatementClassMapping();
    for (int i = 0; i < fieldNumbers.length; i++) {
        mappingDefinition.addMappingForMember(fieldNumbers[i], stmtMappings[fieldNumbers[i]]);
    }
    if (datastoreIndex != null) {
        StatementMappingIndex datastoreMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false));
        datastoreMappingIdx.setColumnPositions(datastoreIndex);
        mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreMappingIdx);
    }
    if (discrimIndex != null) {
        StatementMappingIndex discrimMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true));
        discrimMappingIdx.setColumnPositions(discrimIndex);
        mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimMappingIdx);
    }
    if (versionIndex != null) {
        StatementMappingIndex versionMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.VERSION, true));
        versionMappingIdx.setColumnPositions(versionIndex);
        mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionMappingIdx);
    }
    return new PersistentClassROF(ec, rs, ignoreCache, mappingDefinition, candidateCmd, getCandidateClass());
}
Also used : HashMap(java.util.HashMap) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) ResultSetMetaData(java.sql.ResultSetMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) HashMap(java.util.HashMap) Map(java.util.Map) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) HashSet(java.util.HashSet)

Example 5 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class SQLQuery method compileInternal.

/**
 * Verify the elements of the query and provide a hint to the query to prepare and optimize an execution plan.
 */
public void compileInternal(Map parameterValues) {
    if (isCompiled) {
        return;
    }
    // Default to using the users SQL direct with no substitution of params etc
    compiledSQL = inputSQL;
    if (candidateClass != null && getType() == QueryType.SELECT) {
        // Perform any sanity checking of input for SELECT queries
        RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
        if (cmd == null) {
            throw new ClassNotPersistableException(candidateClass.getName());
        }
        if (cmd.getPersistableSuperclass() != null) {
        // throw new PersistentSuperclassNotAllowedException(candidateClass.getName());
        }
        if (getResultClass() == null) {
            // Check the presence of the required columns (id, version, discriminator) in the candidate class
            // Skip "SELECT "
            String selections = stripComments(compiledSQL.trim()).substring(7);
            int fromStart = selections.indexOf("FROM");
            if (fromStart == -1) {
                fromStart = selections.indexOf("from");
            }
            selections = selections.substring(0, fromStart).trim();
            String[] selectedColumns = StringUtils.split(selections, ",");
            if (selectedColumns == null || selectedColumns.length == 0) {
                throw new NucleusUserException(Localiser.msg("059003", compiledSQL));
            }
            if (selectedColumns.length == 1 && selectedColumns[0].trim().equals("*")) {
            // SQL Query using * so just end the checking since all possible columns will be selected
            } else {
                // Generate id column field information for later checking the id is present
                DatastoreClass table = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
                PersistableMapping idMapping = (PersistableMapping) table.getIdMapping();
                String[] idColNames = new String[idMapping.getNumberOfDatastoreMappings()];
                boolean[] idColMissing = new boolean[idMapping.getNumberOfDatastoreMappings()];
                for (int i = 0; i < idMapping.getNumberOfDatastoreMappings(); i++) {
                    idColNames[i] = idMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString();
                    idColMissing[i] = true;
                }
                // Generate discriminator/version information for later checking they are present
                JavaTypeMapping discrimMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
                String discriminatorColName = (discrimMapping != null) ? discrimMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
                JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
                String versionColName = (versionMapping != null) ? versionMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
                boolean discrimMissing = (discriminatorColName != null);
                boolean versionMissing = (versionColName != null);
                // Go through the selected fields and check the existence of id, version, discriminator cols
                DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
                final AbstractClassMetaData candidateCmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
                for (int i = 0; i < selectedColumns.length; i++) {
                    String colName = selectedColumns[i].trim();
                    if (colName.indexOf(" AS ") > 0) {
                        // Allow for user specification of "XX.YY AS ZZ"
                        colName = colName.substring(colName.indexOf(" AS ") + 4).trim();
                    } else if (colName.indexOf(" as ") > 0) {
                        // Allow for user specification of "XX.YY as ZZ"
                        colName = colName.substring(colName.indexOf(" as ") + 4).trim();
                    }
                    if (candidateCmd.getIdentityType() == IdentityType.DATASTORE) {
                        // Check for existence of id column, allowing for any RDBMS using quoted identifiers
                        if (SQLQuery.columnNamesAreTheSame(dba, idColNames[0], colName)) {
                            idColMissing[0] = false;
                        }
                    } else if (candidateCmd.getIdentityType() == IdentityType.APPLICATION) {
                        for (int j = 0; j < idColNames.length; j++) {
                            // Check for existence of id column, allowing for any RDBMS using quoted identifiers
                            if (SQLQuery.columnNamesAreTheSame(dba, idColNames[j], colName)) {
                                idColMissing[j] = false;
                            }
                        }
                    }
                    if (discrimMissing && SQLQuery.columnNamesAreTheSame(dba, discriminatorColName, colName)) {
                        discrimMissing = false;
                    } else if (versionMissing && SQLQuery.columnNamesAreTheSame(dba, versionColName, colName)) {
                        versionMissing = false;
                    }
                }
                if (discrimMissing) {
                    throw new NucleusUserException(Localiser.msg("059014", compiledSQL, candidateClass.getName(), discriminatorColName));
                }
                if (versionMissing) {
                    throw new NucleusUserException(Localiser.msg("059015", compiledSQL, candidateClass.getName(), versionColName));
                }
                for (int i = 0; i < idColMissing.length; i++) {
                    if (idColMissing[i]) {
                        throw new NucleusUserException(Localiser.msg("059013", compiledSQL, candidateClass.getName(), idColNames[i]));
                    }
                }
            }
        }
    }
    if (NucleusLogger.QUERY.isDebugEnabled()) {
        NucleusLogger.QUERY.debug(Localiser.msg("059012", compiledSQL));
    }
    isCompiled = true;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) ClassNotPersistableException(org.datanucleus.exceptions.ClassNotPersistableException)

Aggregations

RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)197 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)84 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)82 SQLException (java.sql.SQLException)78 Connection (java.sql.Connection)76 HashSet (java.util.HashSet)72 DatabaseMetaData (java.sql.DatabaseMetaData)62 PersistenceManager (javax.jdo.PersistenceManager)61 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)56 JDOPersistenceManager (org.datanucleus.api.jdo.JDOPersistenceManager)55 Transaction (javax.jdo.Transaction)52 ArrayList (java.util.ArrayList)49 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)49 JDOFatalUserException (javax.jdo.JDOFatalUserException)48 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)44 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)42 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)41 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)38 NumericExpression (org.datanucleus.store.rdbms.sql.expression.NumericExpression)28 JDOFatalInternalException (javax.jdo.JDOFatalInternalException)25