Search in sources :

Example 26 with DatastoreAdapter

use of org.datanucleus.store.rdbms.adapter.DatastoreAdapter in project datanucleus-rdbms by datanucleus.

the class ColumnImpl method getSQLDefinition.

/* (non-Javadoc)
     * @see org.datanucleus.store.rdbms.table.Column#getSQLDefinition()
     */
public String getSQLDefinition() {
    StringBuilder def = new StringBuilder(identifier.toString());
    if (!StringUtils.isWhitespace(columnMetaData.getColumnDdl())) {
        // User-defined DDL, so assume they set the type etc to something sensible
        // Note that the JPA spec doesn't explicitly specify if this has to include the type or not
        def.append(" ").append(columnMetaData.getColumnDdl());
        return def.toString();
    }
    DatastoreAdapter adapter = getStoreManager().getDatastoreAdapter();
    // Add any type specification.
    if (adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS) && isIdentity() && !adapter.supportsOption(DatastoreAdapter.AUTO_INCREMENT_COLUMN_TYPE_SPECIFICATION)) {
    // Don't add type
    } else if (typeName != null) {
        // Allow for manual override of "type" for things like MySQL ENUM where we want to define the type with its options
        def.append(" " + typeName);
    } else {
        StringBuilder typeSpec = new StringBuilder(typeInfo.getTypeName());
        // i.e. if it contains parentheses, and the type name itself doesn't. createParams is mighty ill-defined by the JDBC spec, but attempt to interpret it.
        if (typeInfo.getCreateParams() != null && typeInfo.getCreateParams().indexOf('(') >= 0 && typeInfo.getTypeName().indexOf('(') < 0) {
            StringTokenizer toks = new StringTokenizer(typeInfo.getCreateParams());
            while (toks.hasMoreTokens()) {
                String tok = toks.nextToken();
                if (tok.startsWith("[") && tok.endsWith("]")) {
                    // skip
                    continue;
                }
                typeSpec.append(" " + tok);
            }
        }
        // Add any precision. We use the "allowsPrecisionSpec" flag for this
        StringBuilder precSpec = new StringBuilder();
        int sqlPrecision = getSQLPrecision();
        if (sqlPrecision > 0 && typeInfo.isAllowsPrecisionSpec()) {
            precSpec.append(sqlPrecision);
            if (columnMetaData.getScale() != null) {
                precSpec.append("," + columnMetaData.getScale());
            }
        } else if (sqlPrecision > 0 && !typeInfo.isAllowsPrecisionSpec()) {
            NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("020183", this.toString()));
        }
        int lParenIdx = typeSpec.toString().indexOf('(');
        int rParenIdx = typeSpec.toString().indexOf(')', lParenIdx);
        if (lParenIdx > 0 && rParenIdx > 0) {
            // present ready for you to insert the values instead of appending them.
            if (precSpec.length() > 0) {
                typeSpec.replace(lParenIdx + 1, rParenIdx, precSpec.toString());
            } else if (rParenIdx == lParenIdx + 1) {
                throw new ColumnDefinitionException(Localiser.msg("020184", this.toString()));
            }
        } else if (precSpec.length() > 0) {
            typeSpec.append('(');
            typeSpec.append(precSpec.toString());
            typeSpec.append(')');
        }
        def.append(" " + typeSpec.toString());
    }
    // Add DEFAULT (if specifiable before NULL)
    if (adapter.supportsOption(DatastoreAdapter.DEFAULT_BEFORE_NULL_IN_COLUMN_OPTIONS) && adapter.supportsOption(DatastoreAdapter.DEFAULT_KEYWORD_IN_COLUMN_OPTIONS) && columnMetaData.getDefaultValue() != null) {
        def.append(" ").append(getDefaultDefinition());
    }
    if (isIdentity() && isPrimaryKey() && adapter.supportsOption(DatastoreAdapter.AUTO_INCREMENT_PK_IN_CREATE_TABLE_COLUMN_DEF)) {
        def.append(" PRIMARY KEY");
    }
    // Nullability
    if (adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS) && isIdentity() && !adapter.supportsOption(DatastoreAdapter.AUTO_INCREMENT_KEYS_NULL_SPECIFICATION)) {
    // Do nothing since the adapter doesn't allow NULL specifications with autoincrement/identity
    } else {
        if (!isNullable()) {
            if (columnMetaData.getDefaultValue() == null || adapter.supportsOption(DatastoreAdapter.DEFAULT_KEYWORD_WITH_NOT_NULL_IN_COLUMN_OPTIONS)) {
                def.append(" NOT NULL");
            }
        } else if (typeInfo.getNullable() == DatabaseMetaData.columnNullable) {
            if (adapter.supportsOption(DatastoreAdapter.NULLS_KEYWORD_IN_COLUMN_OPTIONS)) {
                def.append(" NULL");
            }
        }
    }
    // Add DEFAULT (if specifiable after NULL)
    if (!adapter.supportsOption(DatastoreAdapter.DEFAULT_BEFORE_NULL_IN_COLUMN_OPTIONS) && adapter.supportsOption(DatastoreAdapter.DEFAULT_KEYWORD_IN_COLUMN_OPTIONS) && columnMetaData.getDefaultValue() != null) {
        def.append(" ").append(getDefaultDefinition());
    }
    // CHECK Constraints
    if (adapter.supportsOption(DatastoreAdapter.CHECK_IN_CREATE_STATEMENTS) && checkConstraints != null) {
        def.append(" " + checkConstraints.toString());
    }
    // Auto Increment
    if (adapter.supportsOption(DatastoreAdapter.IDENTITY_COLUMNS) && isIdentity()) {
        def.append(" " + adapter.getAutoIncrementKeyword());
    }
    // Uniqueness
    if (isUnique() && !adapter.supportsOption(DatastoreAdapter.UNIQUE_IN_END_CREATE_STATEMENTS)) {
        def.append(" UNIQUE");
    }
    return def.toString();
}
Also used : StringTokenizer(java.util.StringTokenizer) ColumnDefinitionException(org.datanucleus.store.rdbms.exceptions.ColumnDefinitionException) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter)

Example 27 with DatastoreAdapter

use of org.datanucleus.store.rdbms.adapter.DatastoreAdapter in project datanucleus-rdbms by datanucleus.

the class DatastoreUUIDHexGenerator method reserveBlock.

/**
 * Reserve a block of ids.
 * @param size Block size
 * @return The reserved block
 */
protected synchronized ValueGenerationBlock<String> reserveBlock(long size) {
    if (size < 1) {
        return null;
    }
    List<String> oids = new ArrayList<>();
    try {
        ManagedConnection mconn = connectionProvider.retrieveConnection();
        PreparedStatement ps = null;
        ResultSet rs = null;
        RDBMSStoreManager rdbmsMgr = (RDBMSStoreManager) storeMgr;
        SQLController sqlControl = rdbmsMgr.getSQLController();
        try {
            // Find the next ID from the database
            DatastoreAdapter dba = rdbmsMgr.getDatastoreAdapter();
            String stmt = dba.getSelectNewUUIDStmt();
            ps = sqlControl.getStatementForQuery(mconn, stmt);
            for (int i = 1; i < size; i++) {
                rs = sqlControl.executeStatementQuery(null, mconn, stmt, ps);
                if (rs.next()) {
                    oids.add(rs.getString(1));
                }
            }
        } catch (SQLException e) {
            throw new ValueGenerationException(Localiser.msg("040008", e.getMessage()));
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
                if (ps != null) {
                    sqlControl.closeStatement(mconn, ps);
                }
            } catch (SQLException e) {
            // non-recoverable error
            }
        }
    } finally {
        connectionProvider.releaseConnection();
    }
    return new ValueGenerationBlock(oids);
}
Also used : SQLException(java.sql.SQLException) ArrayList(java.util.ArrayList) ValueGenerationBlock(org.datanucleus.store.valuegenerator.ValueGenerationBlock) PreparedStatement(java.sql.PreparedStatement) ValueGenerationException(org.datanucleus.store.valuegenerator.ValueGenerationException) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SQLController(org.datanucleus.store.rdbms.SQLController) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter)

Example 28 with DatastoreAdapter

use of org.datanucleus.store.rdbms.adapter.DatastoreAdapter in project datanucleus-rdbms by datanucleus.

the class TableGenerator method initialiseSequenceTable.

/**
 * Method to initialise the sequence table used for storing the sequence values.
 */
protected synchronized void initialiseSequenceTable() {
    // Set catalog/schema name (using properties, and if not specified using the values for the table)
    String catalogName = properties.getProperty(ValueGenerator.PROPERTY_SEQUENCETABLE_CATALOG);
    if (catalogName == null) {
        catalogName = properties.getProperty(ValueGenerator.PROPERTY_CATALOG_NAME);
    }
    String schemaName = properties.getProperty(ValueGenerator.PROPERTY_SEQUENCETABLE_SCHEMA);
    if (schemaName == null) {
        schemaName = properties.getProperty(ValueGenerator.PROPERTY_SCHEMA_NAME);
    }
    String tableName = (properties.getProperty(ValueGenerator.PROPERTY_SEQUENCETABLE_TABLE) == null ? DEFAULT_TABLE_NAME : properties.getProperty(ValueGenerator.PROPERTY_SEQUENCETABLE_TABLE));
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) this.storeMgr;
    DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
    DatastoreIdentifier identifier = storeMgr.getIdentifierFactory().newTableIdentifier(tableName);
    if (dba.supportsOption(DatastoreAdapter.CATALOGS_IN_TABLE_DEFINITIONS) && catalogName != null) {
        identifier.setCatalogName(catalogName);
    }
    if (dba.supportsOption(DatastoreAdapter.SCHEMAS_IN_TABLE_DEFINITIONS) && schemaName != null) {
        identifier.setSchemaName(schemaName);
    }
    DatastoreClass table = storeMgr.getDatastoreClass(identifier);
    if (table != null) {
        sequenceTable = (SequenceTable) table;
    } else {
        String sequenceNameColumnName = DEFAULT_SEQUENCE_COLUMN_NAME;
        if (properties.containsKey(ValueGenerator.PROPERTY_SEQUENCETABLE_NAME_COLUMN)) {
            sequenceNameColumnName = properties.getProperty(ValueGenerator.PROPERTY_SEQUENCETABLE_NAME_COLUMN);
        }
        String nextValColumnName = DEFAULT_NEXTVALUE_COLUMN_NAME;
        if (properties.containsKey(ValueGenerator.PROPERTY_SEQUENCETABLE_NEXTVAL_COLUMN)) {
            nextValColumnName = properties.getProperty(ValueGenerator.PROPERTY_SEQUENCETABLE_NEXTVAL_COLUMN);
        }
        sequenceTable = new SequenceTable(identifier, storeMgr, sequenceNameColumnName, nextValColumnName);
        sequenceTable.initialize(storeMgr.getNucleusContext().getClassLoaderResolver(null));
    }
}
Also used : DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager)

Example 29 with DatastoreAdapter

use of org.datanucleus.store.rdbms.adapter.DatastoreAdapter in project datanucleus-rdbms by datanucleus.

the class SQLStatementHelper method selectMemberOfSourceInStatement.

/**
 * Method to select the specified member (field/property) of the source table in the passed SQL
 * statement. This populates the mappingDefinition with the column details for this member.
 * @param stmt The SQL statement
 * @param mappingDefinition Mapping definition for the results (will be populated by any
 *                          selected mappings if provided as input)
 * @param fetchPlan FetchPlan
 * @param sourceSqlTbl Table that has the member (or a super-table/secondary-table of this table)
 * @param mmd Meta-data for the field/property in the source that we are selecting
 * @param clr ClassLoader resolver
 * @param maxFetchPlanLimit Max fetch depth from this point to select (0 implies no other objects)
 * @param inputJoinType Optional join type to use for subobjects (otherwise decide join type internally)
 */
public static void selectMemberOfSourceInStatement(SelectStatement stmt, StatementClassMapping mappingDefinition, FetchPlan fetchPlan, SQLTable sourceSqlTbl, AbstractMemberMetaData mmd, ClassLoaderResolver clr, int maxFetchPlanLimit, JoinType inputJoinType) {
    boolean selectSubobjects = false;
    if (maxFetchPlanLimit > 0) {
        selectSubobjects = true;
    }
    // Set table-group name for any related object we join to (naming based on member name)
    String tableGroupName = sourceSqlTbl.getGroupName() + "." + mmd.getName();
    JavaTypeMapping m = sourceSqlTbl.getTable().getMemberMapping(mmd);
    if (m != null && m.includeInFetchStatement()) {
        RelationType relationType = mmd.getRelationType(clr);
        RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
        DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
        if (!dba.validToSelectMappingInStatement(stmt, m)) {
            // Not valid to select this mapping for this statement so return
            return;
        }
        MetaDataManager mmgr = storeMgr.getMetaDataManager();
        StatementMappingIndex stmtMapping = new StatementMappingIndex(m);
        if (m.getNumberOfDatastoreMappings() > 0) {
            // Select of fields with columns in source table(s)
            // Adds inner/outer join to any required superclass/secondary tables
            SQLTable sqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, sourceSqlTbl, m);
            boolean selectFK = true;
            if (selectSubobjects && (relationType == RelationType.ONE_TO_ONE_UNI || (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() == null)) && !mmd.isSerialized() && !mmd.isEmbedded()) {
                // Related object with FK at this side
                selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
            } else if (selectSubobjects && (!mmd.isEmbedded() && !mmd.isSerialized()) && relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
                    // N-1 bidirectional join table relation
                    // TODO Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
                    Table joinTable = storeMgr.getTable(relatedMmds[0]);
                    DatastoreElementContainer collTable = (DatastoreElementContainer) joinTable;
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();
                    SQLTable joinSqlTbl = null;
                    if (stmt.getPrimaryTable().getTable() != joinTable) {
                        // Join to the join table
                        JavaTypeMapping referenceMapping = collTable.getElementMapping();
                        joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName, true);
                    } else {
                        // Main table of the statement is the join table so no need to join
                        joinSqlTbl = stmt.getPrimaryTable();
                    }
                    // Select the owner mapping of the join table
                    int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
                    stmtMapping.setColumnPositions(colNumbers);
                // TODO Join to 1 side from join table?
                } else {
                    // N-1 bidirectional FK relation
                    // Related object with FK at this side, so join/select related object as required
                    selectFK = selectFetchPlanFieldsOfFKRelatedObject(stmt, mappingDefinition, fetchPlan, sourceSqlTbl, mmd, clr, maxFetchPlanLimit, m, tableGroupName, stmtMapping, sqlTbl, inputJoinType);
                }
            }
            if (selectFK) {
                int[] colNumbers = stmt.select(sqlTbl, m, null);
                stmtMapping.setColumnPositions(colNumbers);
            }
        } else {
            // Select of related objects with FK in other table
            if (relationType == RelationType.ONE_TO_ONE_BI && mmd.getMappedBy() != null) {
                // 1-1 bidirectional relation with FK in related table
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                AbstractMemberMetaData relatedMmd = relatedMmds[0];
                String[] clsNames = null;
                if (mmd.getType().isInterface()) {
                    if (mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1) {
                        // Use field-type since only one class specified
                        Class fldTypeCls = clr.classForName(mmd.getFieldTypes()[0]);
                        if (fldTypeCls.isInterface()) {
                            // User has specified an interface, so find its implementations
                            clsNames = mmgr.getClassesImplementingInterface(mmd.getFieldTypes()[0], clr);
                        } else {
                            // Use user-provided field-type
                            clsNames = new String[] { mmd.getFieldTypes()[0] };
                        }
                    }
                    if (clsNames == null) {
                        clsNames = mmgr.getClassesImplementingInterface(mmd.getTypeName(), clr);
                    }
                } else {
                    String typeName = mmd.isSingleCollection() ? mmd.getCollection().getElementType() : mmd.getTypeName();
                    clsNames = new String[] { typeName };
                }
                DatastoreClass relatedTbl = storeMgr.getDatastoreClass(clsNames[0], clr);
                JavaTypeMapping relatedMapping = relatedTbl.getMemberMapping(relatedMmd);
                JavaTypeMapping relatedDiscrimMapping = relatedTbl.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
                Object[] discrimValues = null;
                JavaTypeMapping relatedTypeMapping = null;
                AbstractClassMetaData relatedCmd = relatedMmd.getAbstractClassMetaData();
                if (relatedDiscrimMapping != null && (relatedCmd.getSuperAbstractClassMetaData() != null || !relatedCmd.getFullClassName().equals(mmd.getTypeName()))) {
                    // Related table has a discriminator and the field can store other types
                    List discValueList = null;
                    for (String clsName : clsNames) {
                        List values = getDiscriminatorValuesForMember(clsName, relatedDiscrimMapping, storeMgr, clr);
                        if (discValueList == null) {
                            discValueList = values;
                        } else {
                            discValueList.addAll(values);
                        }
                    }
                    if (discValueList != null) {
                        discrimValues = discValueList.toArray(new Object[discValueList.size()]);
                    }
                } else if (relatedTbl != relatedMapping.getTable()) {
                    // The relation is to a base class table, and the type stored is a sub-class
                    relatedTypeMapping = relatedTbl.getIdMapping();
                }
                SQLTable relatedSqlTbl = null;
                if (relatedTypeMapping == null) {
                    // Join the 1-1 relation
                    JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
                    if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                        inputJoinType = joinType;
                    }
                    relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relatedTbl, null, discrimValues, tableGroupName, joinType);
                    // Select the id mapping in the related table
                    int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
                    stmtMapping.setColumnPositions(colNumbers);
                } else {
                    DatastoreClass relationTbl = (DatastoreClass) relatedMapping.getTable();
                    if (relatedTbl != relatedMapping.getTable()) {
                        if (relatedMapping.isNullable()) {
                            // Nullable - left outer join from {sourceTable}.ID to {relatedBaseTable}.FK
                            // and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
                            // (joins the relation and restricts to the right type)
                            relatedSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
                        } else {
                            // Not nullable - inner join from {sourceTable}.ID to {relatedBaseTable}.FK
                            // and inner join from {relatedBaseTable}.ID to {relatedTable}.ID
                            // (joins the relation and restricts to the right type)
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), relatedMapping.getTable(), null, relatedMapping, null, tableGroupName, true);
                            relatedSqlTbl = stmt.join(JoinType.INNER_JOIN, relatedSqlTbl, relatedMapping.getTable().getIdMapping(), relatedTbl, null, relatedTbl.getIdMapping(), null, tableGroupName, true);
                        }
                    } else {
                        // Join the 1-1 relation
                        JoinType joinType = getJoinTypeForOneToOneRelationJoin(sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, inputJoinType);
                        if (joinType == JoinType.LEFT_OUTER_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN) {
                            inputJoinType = joinType;
                        }
                        relatedSqlTbl = addJoinForOneToOneRelation(stmt, sourceSqlTbl.getTable().getIdMapping(), sourceSqlTbl, relatedMapping, relationTbl, null, null, tableGroupName, joinType);
                    }
                    // Select the id mapping in the subclass of the related table
                    // Note this adds an inner join from relatedTable to its subclass
                    relatedSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(stmt, relatedSqlTbl, relatedTbl.getIdMapping());
                    int[] colNumbers = stmt.select(relatedSqlTbl, relatedTbl.getIdMapping(), null);
                    stmtMapping.setColumnPositions(colNumbers);
                }
                if (selectSubobjects && !mmd.isSerialized() && !mmd.isEmbedded()) {
                    // Select the fetch-plan fields of the related object
                    StatementClassMapping subMappingDefinition = new StatementClassMapping(null, mmd.getName());
                    selectFetchPlanOfSourceClassInStatement(stmt, subMappingDefinition, fetchPlan, relatedSqlTbl, relatedMmd.getAbstractClassMetaData(), maxFetchPlanLimit - 1, inputJoinType);
                    if (mappingDefinition != null) {
                        mappingDefinition.addMappingDefinitionForMember(mmd.getAbsoluteFieldNumber(), subMappingDefinition);
                    }
                }
            } else if (relationType == RelationType.MANY_TO_ONE_BI) {
                AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
                if (mmd.getJoinMetaData() != null || relatedMmds[0].getJoinMetaData() != null) {
                    // N-1 bidirectional join table relation
                    // Add left outer join from {sourceTable}.ID to {joinTable}.ELEM_FK
                    Table joinTable = storeMgr.getTable(relatedMmds[0]);
                    DatastoreElementContainer collTable = (DatastoreElementContainer) joinTable;
                    JavaTypeMapping selectMapping = collTable.getOwnerMapping();
                    SQLTable joinSqlTbl = null;
                    if (stmt.getPrimaryTable().getTable() != joinTable) {
                        // Join to the join table
                        JavaTypeMapping referenceMapping = collTable.getElementMapping();
                        if (referenceMapping instanceof ReferenceMapping) {
                            // Join table has a reference mapping pointing to our table, so get the submapping for the implementation
                            ReferenceMapping refMap = (ReferenceMapping) referenceMapping;
                            Class implType = clr.classForName(mmd.getClassName(true));
                            referenceMapping = refMap.getJavaTypeMappingForType(implType);
                        }
                        joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), collTable, null, referenceMapping, null, tableGroupName + "_JOIN", true);
                    } else {
                        // Main table of the statement is the join table so no need to join
                        joinSqlTbl = stmt.getPrimaryTable();
                    }
                    // Select the owner mapping of the join table
                    int[] colNumbers = stmt.select(joinSqlTbl, selectMapping, null);
                    stmtMapping.setColumnPositions(colNumbers);
                }
            // TODO Select fetch plan fields of this related object
            } else if (relationType == RelationType.MANY_TO_ONE_UNI) {
                // Add left outer join from {sourceTable}.ID to {joinTable}.OWNER_FK
                PersistableJoinTable joinTable = (PersistableJoinTable) storeMgr.getTable(mmd);
                SQLTable joinSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, sourceSqlTbl, sourceSqlTbl.getTable().getIdMapping(), joinTable, null, joinTable.getOwnerMapping(), null, tableGroupName + "_JOIN", true);
                int[] colNumbers = stmt.select(joinSqlTbl, joinTable.getRelatedMapping(), null);
                stmtMapping.setColumnPositions(colNumbers);
            // TODO Select fetch plan fields of this related object
            }
        }
        if (mappingDefinition != null) {
            mappingDefinition.addMappingForMember(mmd.getAbsoluteFieldNumber(), stmtMapping);
        }
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) RelationType(org.datanucleus.metadata.RelationType) List(java.util.List) ArrayList(java.util.ArrayList) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) Table(org.datanucleus.store.rdbms.table.Table) JoinTable(org.datanucleus.store.rdbms.table.JoinTable) DatastoreElementContainer(org.datanucleus.store.rdbms.table.DatastoreElementContainer) MetaDataManager(org.datanucleus.metadata.MetaDataManager) JoinType(org.datanucleus.store.rdbms.sql.SQLJoin.JoinType) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) PersistableJoinTable(org.datanucleus.store.rdbms.table.PersistableJoinTable) SecondaryDatastoreClass(org.datanucleus.store.rdbms.table.SecondaryDatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 30 with DatastoreAdapter

use of org.datanucleus.store.rdbms.adapter.DatastoreAdapter in project datanucleus-rdbms by datanucleus.

the class SelectStatement method getSQLText.

public synchronized SQLText getSQLText() {
    if (sql != null) {
        return sql;
    }
    DatastoreAdapter dba = getDatastoreAdapter();
    boolean lock = false;
    Boolean val = (Boolean) getValueForExtension(EXTENSION_LOCK_FOR_UPDATE);
    if (val != null) {
        lock = val.booleanValue();
    }
    boolean addAliasToAllSelects = false;
    if (rangeOffset > 0 || rangeCount > -1) {
        if (dba.getRangeByRowNumberColumn2().length() > 0) {
            // Doing "SELECT * FROM (...)" so to be safe we need alias on all selects
            addAliasToAllSelects = true;
        }
    }
    // SELECT ..., ..., ...
    sql = new SQLText("SELECT ");
    if (distinct) {
        sql.append("DISTINCT ");
    }
    addOrderingColumnsToSelect();
    if (selectedItems.isEmpty()) {
        // Nothing selected so select all
        sql.append("*");
    } else {
        int autoAliasNum = 0;
        Iterator<SelectedItem> selectItemIter = selectedItems.iterator();
        while (selectItemIter.hasNext()) {
            SelectedItem selectedItem = selectItemIter.next();
            SQLText selectedST = selectedItem.getSQLText();
            sql.append(selectedST);
            if (selectedItem.getAlias() != null) {
                sql.append(" AS " + rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase(selectedItem.getAlias()));
            } else {
                if (addAliasToAllSelects) {
                    // This query needs an alias on all selects, so add "DN_{X}"
                    sql.append(" AS ").append(rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase("DN_" + autoAliasNum));
                    autoAliasNum++;
                }
            }
            if (selectItemIter.hasNext()) {
                sql.append(',');
            }
        }
        if ((rangeOffset > -1 || rangeCount > -1) && dba.getRangeByRowNumberColumn().length() > 0) {
            // Add a ROW NUMBER column if supported as the means of handling ranges by the RDBMS
            sql.append(',').append(dba.getRangeByRowNumberColumn()).append(" rn");
        }
    }
    // FROM ...
    sql.append(" FROM ");
    sql.append(primaryTable.toString());
    if (lock && dba.supportsOption(DatastoreAdapter.LOCK_OPTION_PLACED_AFTER_FROM)) {
        sql.append(" WITH ").append(dba.getSelectWithLockOption());
    }
    if (joins != null) {
        sql.append(getSqlForJoins(lock));
    }
    // WHERE ...
    if (where != null) {
        sql.append(" WHERE ").append(where.toSQLText());
    }
    // GROUP BY ...
    if (groupingExpressions != null) {
        List<SQLText> groupBy = new ArrayList();
        Iterator<SQLExpression> groupIter = groupingExpressions.iterator();
        while (groupIter.hasNext()) {
            SQLExpression expr = groupIter.next();
            boolean exists = false;
            String exprSQL = expr.toSQLText().toSQL();
            for (SQLText st : groupBy) {
                String sql = st.toSQL();
                if (sql.equals(exprSQL)) {
                    exists = true;
                    break;
                }
            }
            if (!exists) {
                groupBy.add(expr.toSQLText());
            }
        }
        if (dba.supportsOption(DatastoreAdapter.GROUP_BY_REQUIRES_ALL_SELECT_PRIMARIES)) {
            // Check that all select items are represented in the grouping for those RDBMS that need that
            for (SelectedItem selItem : selectedItems) {
                if (selItem.isPrimary()) {
                    boolean exists = false;
                    String selItemSQL = selItem.getSQLText().toSQL();
                    for (SQLText st : groupBy) {
                        String sql = st.toSQL();
                        if (sql.equals(selItemSQL)) {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists) {
                        groupBy.add(selItem.getSQLText());
                    }
                }
            }
        }
        if (groupBy.size() > 0 && aggregated) {
            sql.append(" GROUP BY ");
            for (int i = 0; i < groupBy.size(); i++) {
                if (i > 0) {
                    sql.append(',');
                }
                sql.append(groupBy.get(i));
            }
        }
    }
    // HAVING ...
    if (having != null) {
        sql.append(" HAVING ").append(having.toSQLText());
    }
    if (unions != null && allowUnions) {
        // Add on any UNIONed statements
        if (!dba.supportsOption(DatastoreAdapter.UNION_SYNTAX)) {
            throw new NucleusException(Localiser.msg("052504", "UNION")).setFatal();
        }
        Iterator<SelectStatement> unionIter = unions.iterator();
        while (unionIter.hasNext()) {
            if (dba.supportsOption(DatastoreAdapter.USE_UNION_ALL)) {
                sql.append(" UNION ALL ");
            } else {
                sql.append(" UNION ");
            }
            SelectStatement stmt = unionIter.next();
            SQLText unionSql = stmt.getSQLText();
            sql.append(unionSql);
        }
    }
    // ORDER BY ...
    SQLText orderStmt = generateOrderingStatement();
    if (orderStmt != null) {
        sql.append(" ORDER BY ").append(orderStmt);
    }
    // RANGE
    if (rangeOffset > -1 || rangeCount > -1) {
        // Add a LIMIT clause to end of statement if supported by the adapter
        String limitClause = dba.getRangeByLimitEndOfStatementClause(rangeOffset, rangeCount, orderStmt != null);
        if (limitClause.length() > 0) {
            sql.append(" ").append(limitClause);
        }
    }
    if (lock && dba.supportsOption(DatastoreAdapter.LOCK_WITH_SELECT_FOR_UPDATE)) {
        // Add any required locking based on the RDBMS capability
        if (distinct && !dba.supportsOption(DatastoreAdapter.DISTINCT_WITH_SELECT_FOR_UPDATE)) {
            NucleusLogger.QUERY.warn(Localiser.msg("052502"));
        } else if (groupingExpressions != null && !dba.supportsOption(DatastoreAdapter.GROUPING_WITH_SELECT_FOR_UPDATE)) {
            NucleusLogger.QUERY.warn(Localiser.msg("052506"));
        } else if (having != null && !dba.supportsOption(DatastoreAdapter.HAVING_WITH_SELECT_FOR_UPDATE)) {
            NucleusLogger.QUERY.warn(Localiser.msg("052507"));
        } else if (orderingExpressions != null && !dba.supportsOption(DatastoreAdapter.ORDERING_WITH_SELECT_FOR_UPDATE)) {
            NucleusLogger.QUERY.warn(Localiser.msg("052508"));
        } else if (joins != null && !joins.isEmpty() && !dba.supportsOption(DatastoreAdapter.MULTITABLES_WITH_SELECT_FOR_UPDATE)) {
            NucleusLogger.QUERY.warn(Localiser.msg("052509"));
        } else {
            sql.append(" " + dba.getSelectForUpdateText());
            if (dba.supportsOption(DatastoreAdapter.SELECT_FOR_UPDATE_NOWAIT)) {
                Boolean nowait = (Boolean) getValueForExtension(EXTENSION_LOCK_FOR_UPDATE_NOWAIT);
                if (nowait != null) {
                    sql.append(" NOWAIT");
                }
            }
        }
    }
    if (lock && !dba.supportsOption(DatastoreAdapter.LOCK_WITH_SELECT_FOR_UPDATE) && !dba.supportsOption(DatastoreAdapter.LOCK_OPTION_PLACED_AFTER_FROM) && !dba.supportsOption(DatastoreAdapter.LOCK_OPTION_PLACED_WITHIN_JOIN)) {
        NucleusLogger.QUERY.warn("Requested locking of query statement, but this RDBMS doesn't support a convenient mechanism");
    }
    if (rangeOffset > 0 || rangeCount > -1) {
        if (dba.getRangeByRowNumberColumn2().length() > 0) {
            // Oracle-specific using ROWNUM. Creates a query of the form
            // SELECT * FROM (
            // SELECT subq.*, ROWNUM rn FROM (
            // SELECT x1, x2, ... FROM ... WHERE ... ORDER BY ...
            // ) subq
            // ) WHERE rn > {offset} AND rn <= {count}
            SQLText userSql = sql;
            // SELECT all columns of userSql, plus ROWNUM, with the FROM being the users query
            SQLText innerSql = new SQLText("SELECT subq.*");
            innerSql.append(',').append(dba.getRangeByRowNumberColumn2()).append(" rn");
            innerSql.append(" FROM (").append(userSql).append(") subq ");
            // Put that query as the FROM of the outer query, and apply the ROWNUM restrictions
            SQLText outerSql = new SQLText("SELECT * FROM (").append(innerSql).append(") ");
            outerSql.append("WHERE ");
            if (rangeOffset > 0) {
                outerSql.append("rn > " + rangeOffset);
                if (rangeCount > -1) {
                    outerSql.append(" AND rn <= " + (rangeCount + rangeOffset));
                }
            } else {
                outerSql.append(" rn <= " + rangeCount);
            }
            sql = outerSql;
        } else if (dba.getRangeByRowNumberColumn().length() > 0) {
            // DB2-specific ROW_NUMBER weirdness. Creates a query of the form
            // SELECT subq.x1, subq.x2, ... FROM (
            // SELECT x1, x2, ..., {keyword} rn FROM ... WHERE ... ORDER BY ...) subq
            // WHERE subq.rn >= {offset} AND subq.rn < {count}
            // This apparently works for DB2 (unverified, but claimed by IBM employee)
            SQLText userSql = sql;
            sql = new SQLText("SELECT ");
            Iterator<SelectedItem> selectedItemIter = selectedItems.iterator();
            while (selectedItemIter.hasNext()) {
                SelectedItem selectedItemExpr = selectedItemIter.next();
                sql.append("subq.");
                String selectedCol = selectedItemExpr.getSQLText().toSQL();
                if (selectedItemExpr.getAlias() != null) {
                    selectedCol = rdbmsMgr.getIdentifierFactory().getIdentifierInAdapterCase(selectedItemExpr.getAlias());
                } else {
                    // strip out qualifier when encountered from column name since we are adding a new qualifier above.
                    // NOTE THAT THIS WILL FAIL IF THE ORIGINAL QUERY HAD "A0.COL1, B0.COL1" IN THE SELECT
                    int dotIndex = selectedCol.indexOf(".");
                    if (dotIndex > 0) {
                        // Remove qualifier name and the dot
                        selectedCol = selectedCol.substring(dotIndex + 1);
                    }
                }
                sql.append(selectedCol);
                if (selectedItemIter.hasNext()) {
                    sql.append(',');
                }
            }
            sql.append(" FROM (").append(userSql).append(") subq WHERE ");
            if (rangeOffset > 0) {
                sql.append("subq.rn").append(">").append("" + rangeOffset);
            }
            if (rangeCount > 0) {
                if (rangeOffset > 0) {
                    sql.append(" AND ");
                }
                sql.append("subq.rn").append("<=").append("" + (rangeCount + rangeOffset));
            }
        }
    }
    return sql;
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) ArrayList(java.util.ArrayList) Iterator(java.util.Iterator) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) NucleusException(org.datanucleus.exceptions.NucleusException)

Aggregations

DatastoreAdapter (org.datanucleus.store.rdbms.adapter.DatastoreAdapter)46 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)24 SQLException (java.sql.SQLException)17 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)10 ResultSet (java.sql.ResultSet)8 List (java.util.List)8 Connection (java.sql.Connection)7 Statement (java.sql.Statement)7 EntityTransaction (javax.persistence.EntityTransaction)7 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)7 Person (org.datanucleus.samples.annotations.models.company.Person)7 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)7 PreparedStatement (java.sql.PreparedStatement)6 ArrayList (java.util.ArrayList)6 SQLController (org.datanucleus.store.rdbms.SQLController)6 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)6 StoredProcedureQuery (javax.persistence.StoredProcedureQuery)5 JPAEntityManager (org.datanucleus.api.jpa.JPAEntityManager)5 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)5 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)5