Search in sources :

Example 6 with PrimaryKey

use of org.datanucleus.store.rdbms.key.PrimaryKey in project datanucleus-rdbms by datanucleus.

the class SQLAnywhereAdapter method getCreateTableStatement.

/**
 * Returns the appropriate SQL to create the given table having the given columns. No column constraints
 * or key definitions should be included. It should return something like:
 *
 * <pre>
 * CREATE TABLE FOO ( BAR VARCHAR(30), BAZ INTEGER )
 * </pre>
 * @param table The table to create.
 * @param columns The columns of the table.
 * @param props Properties for controlling the table creation
 * @param factory Factory for identifiers
 * @return The text of the SQL statement.
 */
public String getCreateTableStatement(TableImpl table, Column[] columns, Properties props, IdentifierFactory factory) {
    StringBuilder createStmt = new StringBuilder();
    String indent = "    ";
    if (getContinuationString().length() == 0) {
        indent = "";
    }
    // CREATE TABLE with column specifiers
    createStmt.append("CREATE TABLE ").append(table.toString()).append(getContinuationString()).append("(").append(getContinuationString());
    for (int i = 0; i < columns.length; ++i) {
        if (i > 0) {
            createStmt.append(",").append(getContinuationString());
        }
        createStmt.append(indent).append(columns[i].getSQLDefinition());
    }
    // PRIMARY KEY(col[,col])
    if (supportsOption(PRIMARYKEY_IN_CREATE_STATEMENTS)) {
        PrimaryKey pk = table.getPrimaryKey();
        if (pk != null && pk.size() > 0) {
            boolean includePk = true;
            if (supportsOption(AUTO_INCREMENT_PK_IN_CREATE_TABLE_COLUMN_DEF)) {
                for (Column pkCol : pk.getColumns()) {
                    if (pkCol.isIdentity()) {
                        // This column is auto-increment and is specified in the column def so ignore here
                        includePk = false;
                        break;
                    }
                }
            }
            if (includePk) {
                createStmt.append(",").append(getContinuationString());
                if (pk.getName() != null) {
                    String identifier = factory.getIdentifierInAdapterCase(pk.getName());
                    createStmt.append(indent).append("CONSTRAINT ").append(identifier).append(" ").append(pk.toString());
                } else {
                    createStmt.append(indent).append(pk.toString());
                }
            }
        }
    }
    // UNIQUE( col [,col] )
    if (supportsOption(UNIQUE_IN_END_CREATE_STATEMENTS)) {
        StringBuilder uniqueConstraintStmt = new StringBuilder();
        for (int i = 0; i < columns.length; ++i) {
            if (columns[i].isUnique()) {
                if (uniqueConstraintStmt.length() < 1) {
                    uniqueConstraintStmt.append(",").append(getContinuationString());
                    uniqueConstraintStmt.append(indent).append(" UNIQUE (");
                } else {
                    uniqueConstraintStmt.append(",");
                }
                uniqueConstraintStmt.append(columns[i].getIdentifier().toString());
            }
        }
        if (uniqueConstraintStmt.length() > 1) {
            uniqueConstraintStmt.append(")");
            createStmt.append(uniqueConstraintStmt.toString());
        }
    }
    // FOREIGN KEY(col [,col] ) REFERENCES {TBL} (col [,col])
    if (supportsOption(FK_IN_END_CREATE_STATEMENTS)) {
        StringBuilder fkConstraintStmt = new StringBuilder();
        ClassLoaderResolver clr = table.getStoreManager().getNucleusContext().getClassLoaderResolver(null);
        List<ForeignKey> fks = table.getExpectedForeignKeys(clr);
        if (fks != null && !fks.isEmpty()) {
            for (ForeignKey fk : fks) {
                // TODO Ensure that the other table exists, for now assume it does
                createStmt.append(",").append(getContinuationString());
                if (fk.getName() != null) {
                    String identifier = factory.getIdentifierInAdapterCase(fk.getName());
                    createStmt.append(indent).append("CONSTRAINT ").append(identifier).append(" ").append(fk.toString());
                } else {
                    createStmt.append(indent).append(fk.toString());
                }
            }
        }
        if (fkConstraintStmt.length() > 1) {
            createStmt.append(fkConstraintStmt.toString());
        }
    }
    // CHECK (column_identifier IN (literal[,literal]))
    if (supportsOption(CHECK_IN_END_CREATE_STATEMENTS)) {
        StringBuilder checkConstraintStmt = new StringBuilder();
        for (int i = 0; i < columns.length; ++i) {
            if (columns[i].getCheckConstraints() != null) {
                checkConstraintStmt.append(",").append(getContinuationString());
                checkConstraintStmt.append(indent).append(columns[i].getCheckConstraints());
            }
        }
        if (checkConstraintStmt.length() > 1) {
            createStmt.append(checkConstraintStmt.toString());
        }
    }
    createStmt.append(getContinuationString()).append(")");
    return createStmt.toString();
}
Also used : Column(org.datanucleus.store.rdbms.table.Column) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) PrimaryKey(org.datanucleus.store.rdbms.key.PrimaryKey) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey)

Example 7 with PrimaryKey

use of org.datanucleus.store.rdbms.key.PrimaryKey in project datanucleus-rdbms by datanucleus.

the class ClassTable method getPrimaryKey.

/**
 * Accessor for the primary key for this table. Overrides the method in TableImpl
 * to add on any specification of PK name in the metadata.
 * @return The primary key.
 */
public PrimaryKey getPrimaryKey() {
    PrimaryKey pk = super.getPrimaryKey();
    PrimaryKeyMetaData pkmd = cmd.getPrimaryKeyMetaData();
    if (pkmd != null && pkmd.getName() != null) {
        pk.setName(pkmd.getName());
    }
    return pk;
}
Also used : PrimaryKey(org.datanucleus.store.rdbms.key.PrimaryKey) PrimaryKeyMetaData(org.datanucleus.metadata.PrimaryKeyMetaData)

Example 8 with PrimaryKey

use of org.datanucleus.store.rdbms.key.PrimaryKey in project datanucleus-rdbms by datanucleus.

the class ClassTable method getForeignKeyForForeignKeyMetaData.

/**
 * Convenience method to create a FK for the specified ForeignKeyMetaData.
 * Used for foreign-keys specified at &lt;class&gt; level.
 * @param fkmd ForeignKey MetaData
 * @return The ForeignKey
 */
private ForeignKey getForeignKeyForForeignKeyMetaData(ForeignKeyMetaData fkmd) {
    if (fkmd == null) {
        return null;
    }
    // Create the ForeignKey base details
    ForeignKey fk = new ForeignKey(dba, fkmd.isDeferred());
    fk.setForMetaData(fkmd);
    if (fkmd.getFkDefinitionApplies()) {
        // User-defined FK definition should be used
        return fk;
    }
    // Find the target of the foreign-key
    AbstractClassMetaData acmd = cmd;
    if (fkmd.getTable() == null) {
        // Can't create a FK if we don't know where it goes to
        NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("058105", acmd.getFullClassName()));
        return null;
    }
    DatastoreIdentifier tableId = storeMgr.getIdentifierFactory().newTableIdentifier(fkmd.getTable());
    ClassTable refTable = (ClassTable) storeMgr.getDatastoreClass(tableId);
    if (refTable == null) {
        // TODO Go to the datastore and query for this table to get the columns of the PK
        NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("058106", acmd.getFullClassName(), fkmd.getTable()));
        return null;
    }
    PrimaryKey pk = refTable.getPrimaryKey();
    List targetCols = pk.getColumns();
    // Generate the columns for the source of the foreign-key
    List<Column> sourceCols = new ArrayList<>();
    ColumnMetaData[] colmds = fkmd.getColumnMetaData();
    String[] memberNames = fkmd.getMemberNames();
    if (colmds != null && colmds.length > 0) {
        // FK specified via <column>
        for (int i = 0; i < colmds.length; i++) {
            // Find the column and add to the source columns for the FK
            DatastoreIdentifier colId = storeMgr.getIdentifierFactory().newColumnIdentifier(colmds[i].getName());
            Column sourceCol = columnsByIdentifier.get(colId);
            if (sourceCol == null) {
                NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("058107", acmd.getFullClassName(), fkmd.getTable(), colmds[i].getName(), toString()));
                return null;
            }
            sourceCols.add(sourceCol);
        }
    } else if (memberNames != null && memberNames.length > 0) {
        // FK specified via <field>
        for (int i = 0; i < memberNames.length; i++) {
            // Find the metadata for the actual field with the same name as this "foreign-key" field
            // and add all columns to the source columns for the FK
            AbstractMemberMetaData realMmd = getMetaDataForMember(memberNames[i]);
            if (realMmd == null) {
                throw new NucleusUserException("Table " + this + " has foreign-key specified on member " + memberNames[i] + " but that member does not exist in the class that this table represents");
            }
            JavaTypeMapping fieldMapping = memberMappingsMap.get(realMmd);
            int countCols = fieldMapping.getNumberOfDatastoreMappings();
            for (int j = 0; j < countCols; j++) {
                // Add each column of this field to the FK definition
                sourceCols.add(fieldMapping.getDatastoreMapping(j).getColumn());
            }
        }
    }
    if (sourceCols.size() != targetCols.size()) {
        // Different number of cols in this table and target table
        NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("058108", acmd.getFullClassName(), fkmd.getTable(), "" + sourceCols.size(), "" + targetCols.size()));
    }
    // Add all column mappings to the ForeignKey
    if (sourceCols.size() > 0) {
        for (int i = 0; i < sourceCols.size(); i++) {
            Column source = sourceCols.get(i);
            String targetColName = (colmds != null && colmds[i] != null) ? colmds[i].getTarget() : null;
            // Default to matching via the natural order
            Column target = (Column) targetCols.get(i);
            if (targetColName != null) {
                // User has specified the target column for this col so try it in our target list
                for (int j = 0; j < targetCols.size(); j++) {
                    Column targetCol = (Column) targetCols.get(j);
                    if (targetCol.getIdentifier().getName().equalsIgnoreCase(targetColName)) {
                        // Found the required column
                        target = targetCol;
                        break;
                    }
                }
            }
            fk.addColumn(source, target);
        }
    }
    return fk;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) PrimaryKey(org.datanucleus.store.rdbms.key.PrimaryKey) MacroString(org.datanucleus.util.MacroString) ForeignKey(org.datanucleus.store.rdbms.key.ForeignKey) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) List(java.util.List) ArrayList(java.util.ArrayList) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 9 with PrimaryKey

use of org.datanucleus.store.rdbms.key.PrimaryKey in project datanucleus-rdbms by datanucleus.

the class TableImpl method validatePrimaryKey.

/**
 * Utility method to validate the primary key of the table.
 * Will throw a WrongPrimaryKeyException if the PK is incorrect.
 * TODO Add an auto_create parameter on this
 * @param conn Connection to use
 * @return Whether it validates
 * @throws SQLException When an error occurs in the valdiation
 */
protected boolean validatePrimaryKey(Connection conn) throws SQLException {
    Map actualPKs = getExistingPrimaryKeys(conn);
    PrimaryKey expectedPK = getPrimaryKey();
    if (expectedPK.size() == 0) {
        if (!actualPKs.isEmpty()) {
            throw new WrongPrimaryKeyException(this.toString(), expectedPK.toString(), StringUtils.collectionToString(actualPKs.values()));
        }
    } else {
        if (actualPKs.size() != 1 || !actualPKs.values().contains(expectedPK)) {
            throw new WrongPrimaryKeyException(this.toString(), expectedPK.toString(), StringUtils.collectionToString(actualPKs.values()));
        }
    }
    return true;
}
Also used : WrongPrimaryKeyException(org.datanucleus.store.rdbms.exceptions.WrongPrimaryKeyException) PrimaryKey(org.datanucleus.store.rdbms.key.PrimaryKey) HashMap(java.util.HashMap) Map(java.util.Map)

Example 10 with PrimaryKey

use of org.datanucleus.store.rdbms.key.PrimaryKey in project datanucleus-rdbms by datanucleus.

the class TableImpl method getSQLCreateStatements.

/**
 * Accessor for the SQL CREATE statements for this table.
 * @param props Properties for controlling the table creation
 * @return List of statements.
 */
protected List<String> getSQLCreateStatements(Properties props) {
    assertIsInitialized();
    Column[] cols = null;
    // Pass 1 : populate positions defined in metadata as vendor extension "index"
    Iterator<org.datanucleus.store.schema.table.Column> iter = columns.iterator();
    while (iter.hasNext()) {
        Column col = (Column) iter.next();
        ColumnMetaData colmd = col.getColumnMetaData();
        Integer colPos = (colmd != null ? colmd.getPosition() : null);
        if (colPos != null) {
            int index = colPos.intValue();
            if (index < columns.size() && index >= 0) {
                if (cols == null) {
                    cols = new Column[columns.size()];
                }
                if (cols[index] != null) {
                    throw new NucleusUserException("Column index " + index + " has been specified multiple times : " + cols[index] + " and " + col);
                }
                cols[index] = col;
            }
        }
    }
    // Pass 2 : fill in spaces for columns with undefined positions
    if (cols != null) {
        iter = columns.iterator();
        while (iter.hasNext()) {
            Column col = (Column) iter.next();
            ColumnMetaData colmd = col.getColumnMetaData();
            Integer colPos = (colmd != null ? colmd.getPosition() : null);
            if (colPos == null) {
                // No index set for this column, so assign to next free position
                for (int i = 0; i < cols.length; i++) {
                    if (cols[i] == null) {
                        cols[i] = col;
                    }
                }
            }
        }
    } else {
        cols = columns.toArray(new Column[columns.size()]);
    }
    List<String> stmts = new ArrayList<>();
    stmts.add(dba.getCreateTableStatement(this, cols, props, storeMgr.getIdentifierFactory()));
    PrimaryKey pk = getPrimaryKey();
    if (pk.size() > 0) {
        // Some databases define the primary key on the create table
        // statement so we don't have a Statement for the primary key here.
        String pkStmt = dba.getAddPrimaryKeyStatement(pk, storeMgr.getIdentifierFactory());
        if (pkStmt != null) {
            stmts.add(pkStmt);
        }
    }
    return stmts;
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) PrimaryKey(org.datanucleus.store.rdbms.key.PrimaryKey) ColumnMetaData(org.datanucleus.metadata.ColumnMetaData)

Aggregations

PrimaryKey (org.datanucleus.store.rdbms.key.PrimaryKey)12 Iterator (java.util.Iterator)4 ForeignKey (org.datanucleus.store.rdbms.key.ForeignKey)4 HashMap (java.util.HashMap)3 HashSet (java.util.HashSet)3 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)3 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)3 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)3 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)3 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 Set (java.util.Set)2 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)2 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)2 PrimaryKeyMetaData (org.datanucleus.metadata.PrimaryKeyMetaData)2 DatastoreIdentifier (org.datanucleus.store.rdbms.identifier.DatastoreIdentifier)2 Index (org.datanucleus.store.rdbms.key.Index)2 EmbeddedPCMapping (org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping)2 Column (org.datanucleus.store.rdbms.table.Column)2 List (java.util.List)1