FileDocCategorySizeDatePackage
UpdateQueryPlan.javaAPI DocGlassfish v2 API15058Fri May 04 22:35:16 BST 2007com.sun.jdo.spi.persistence.support.sqlstore.sql.generator

UpdateQueryPlan

public class UpdateQueryPlan extends QueryPlan
This class is used to generated update/insert/delete statements.

Fields Summary
private boolean
batch
Flag indicating whether we use batch update.
private com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl
updateDesc
Constructors Summary
public UpdateQueryPlan(com.sun.jdo.spi.persistence.support.sqlstore.ActionDesc desc, com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager store)


         
        super(desc, store);
        this.updateDesc = (UpdateObjectDescImpl) desc;
        this.action = getAction(updateDesc.getUpdateAction());
    
Methods Summary
private voidaddBasetableConstraint(UpdateStatement statement)

        QueryTable table = (QueryTable) statement.getQueryTables().get(0);
        KeyDesc key = table.getTableDesc().getKey();

        ArrayList localFields = key.getFields();
        ArrayList columns = key.getColumns();

        addConstraints(statement, localFields, localFields, columns);
    
private voidaddColumn(LocalFieldDesc fieldDesc, java.lang.Object value)
Specifies an field the data for which needs to be updated, and the mapped columns for which therefor need to be updated. For update queries the column will be put in the set lists, and for insert queries the column will be put into the insert values lists.

param
fieldDesc Updated field corresponding to a column in the database.
param
value New value.


        // Ignore secondary tracked fields.
        if ((fieldDesc.sqlProperties & FieldDesc.PROP_SECONDARY_TRACKED_FIELD) > 0) {
            return;
        }

        for (Iterator iter = fieldDesc.getColumnElements(); iter.hasNext(); ) {
            ColumnElement columnElement = (ColumnElement) iter.next();
            TableElement tableElement = columnElement.getDeclaringTable();

            if (tableElement == null) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.configuration.fieldnotable", // NOI18N
                        fieldDesc.getName()));
            }

            QueryTable t = findQueryTable(tableElement);
            UpdateStatement s = null;

            if (t == null) {
                t = addQueryTable(tableElement, null);
                s = (UpdateStatement) addStatement(t);
            } else {
                s = (UpdateStatement) getStatement(t);
            }

            if (fieldDesc.isVersion() && action == ACT_UPDATE) {
                // For update, version columns will be flagged specially.
                s.addVersionColumn(columnElement);
            } else {
                s.addColumn(columnElement, value);
            }

        }
    
private voidaddColumns()
For inserts and updates we figure out values (they might be hidden) and add the columns necessary. addColumn will figure out which tables need to be included.

        if ((action == ACT_UPDATE) || (action == ACT_INSERT)) {
            List updatedFields = updateDesc.getUpdatedFields();
            int size = (updatedFields != null) ? updatedFields.size() : 0;
            for (int i = 0; i < size; i++) {
                LocalFieldDesc f = (LocalFieldDesc) updatedFields.get(i);
                Object value = batch ? f : updateDesc.getAfterValue(f);
                addColumn(f, value);
            }
        }
    
private voidaddConstraint(UpdateStatement statement, LocalFieldDesc lf, LocalFieldDesc ff, org.netbeans.modules.dbschema.ColumnElement ce, boolean isBeforeImageRequired)


        if (action != ACT_INSERT) {
            if (batch) {
                statement.addConstraint(ce, lf, ff);
            }
            else {
                Object value = isBeforeImageRequired ?
                    updateDesc.getBeforeValue(ff) : updateDesc.getAfterValue(ff);
                statement.addConstraint(lf, value);
            }
        } else {
            Object value = batch ? ff : updateDesc.getAfterValue(ff);
            statement.addColumn(ce, value);
        }
    
private voidaddConstraints(UpdateStatement statement, java.util.ArrayList localFields, java.util.ArrayList foreignFields, java.util.ArrayList columns)


        boolean isBeforeImageRequired = updateDesc.isBeforeImageRequired();
        for (int i = 0; i < localFields.size(); i++) {
            LocalFieldDesc lf = (LocalFieldDesc) localFields.get(i);
            LocalFieldDesc ff = (LocalFieldDesc) foreignFields.get(i);
            ColumnElement ce = (ColumnElement) columns.get(i);

            addConstraint(statement, lf, ff, ce, isBeforeImageRequired);
        }

        // Add the constraint on the version field if needed.
        if (getConfig().hasVersionConsistency() && action != ACT_INSERT) {
            QueryTable table = (QueryTable) statement.getQueryTables().get(0);
            LocalFieldDesc versionField = table.getTableDesc().getVersionField();
            ColumnElement ce = (ColumnElement) versionField.getColumnElements().next();

            addConstraint(statement, versionField, versionField, ce, false);
        }

        statement.markConstraintAdded();
    
private voidaddSecondaryTableConstraint(UpdateStatement statement)

        QueryTable table = (QueryTable) statement.getQueryTables().get(0);
        ReferenceKeyDesc key = table.getTableDesc().getPrimaryTableKey();

        ArrayList localFields = key.getReferencingKey().getFields();
        ArrayList foreignFields = key.getReferencedKey().getFields();
        ArrayList columns = key.getReferencingKey().getColumns();

        addConstraints(statement, localFields, foreignFields, columns);
    
public voidbuild()

        build(false);
    
public voidbuild(boolean batch)
Builds a UpdateQueryPlan for an object based update type (i.e. insert, update, delete) ActionDesc.

param
batch Flag indicating whether we use batch update.


        if ((status & ST_BUILT) > 0) return;

        this.batch = batch;

        generateStatements();

        addColumns();

        if (statements.size() > 0) {
            processStatements();
        }

        processJoinTables();

        status = status | ST_BUILT;
    
public booleancheckBatchThreshold(com.sun.jdo.spi.persistence.support.sqlstore.Transaction tran)
Determines if the amount of batched operations exceeded a threshold.

param
tran the transaction
return
true if the amount of batched operations exceeded a threshold

        for (int i = 0, size = statements.size(); i < size; i++) {
            UpdateStatement updateStatement = (UpdateStatement) statements.get(i);
            if (updateStatement.exceedsBatchThreshold(tran))
                return true;
        }
        return false;
    
private voidgenerateStatements()

        // For insert and delete we build a statement for each table
        if ((action == ACT_DELETE) || (action == ACT_INSERT)) {
            Iterator iter = config.getTables();
            while (iter.hasNext()) {
                TableDesc t = (TableDesc) iter.next();

                // Skip join tables
                if (!t.isJoinTable()) {
                    if (findQueryTable(t.getTableElement()) == null)
                        addStatement(addQueryTable(t));
                }
            }

            // For insert statements, we need to reverse the order.
            if (action == ACT_INSERT) {
                int i = 0;
                int j = statements.size() - 1;

                while (i < j) {
                    Statement s = (Statement) statements.get(i);
                    statements.set(i, statements.get(j));
                    statements.set(j, s);
                    i++;
                    j--;
                }
            }
        }
    
private static intgetAction(int updateAction)

        if (updateAction == ActionDesc.LOG_CREATE) {
            return ACT_INSERT;
        } else if (updateAction == ActionDesc.LOG_DESTROY) {
            return ACT_DELETE;
        } else if (updateAction == ActionDesc.LOG_UPDATE) {
            return ACT_UPDATE;
        } else {
            return ACT_NOOP;
        }
    
protected StatementnewStatement()

        return new UpdateStatement(store.getVendorType(), this, batch);
    
private voidprocessJoinTables()

        Collection fields = updateDesc.getUpdatedJoinTableFields();

        if (fields == null) return;

        Iterator fieldIter = fields.iterator();

        ArrayList deleteStatements = new ArrayList();
        ArrayList insertStatements = new ArrayList();

        while (fieldIter.hasNext()) {
            ForeignFieldDesc f = (ForeignFieldDesc) fieldIter.next();
            Collection descs = updateDesc.getUpdateJoinTableDescs(f);
            Iterator descIter = descs.iterator();

            ColumnElement c = (ColumnElement) f.assocLocalColumns.get(0);
            QueryTable t = addQueryTable(config.findTableDesc(c.getDeclaringTable()));

            while (descIter.hasNext()) {
                UpdateJoinTableDesc desc = (UpdateJoinTableDesc) descIter.next();
                int action = getAction(desc.getAction());

                UpdateStatement s = (UpdateStatement) createStatement(t);
                s.setAction(action);

                if (action == ACT_INSERT) {
                    insertStatements.add(s);
                } else if (action == ACT_DELETE) {

                    // RESOLVE: There are redundant deletes from join tables that causes
                    // update to fail with no rows affected. To work around this problem
                    // for now, we set the minAffectedRows to 0.
                    // We need to figure out why there are redundant deletes.

                    s.minAffectedRows = 0;
                    deleteStatements.add(s);
                }

                s.addLocalConstraints(action, f, desc.getParentStateManager());
                s.addForeignConstraints(action, f, desc.getForeignStateManager());
            }
        }

        // All join table delete statements have to go first and all
        // join table insert statements have to go last.

        ArrayList oldStatements = statements;
        statements = deleteStatements;
        statements.addAll(oldStatements);
        statements.addAll(insertStatements);
    
private voidprocessRelatedStatements(UpdateStatement statement)

        ArrayList secondaryTableStatements = statement.getSecondaryTableStatements();

        if (secondaryTableStatements != null) {
            for (int i = 0; i < secondaryTableStatements.size(); i++) {
                UpdateStatement secondaryTableStatement = (UpdateStatement) secondaryTableStatements.get(i);

                if (!secondaryTableStatement.isConstraintAdded()) {
                    processRelatedStatements(secondaryTableStatement);

                    addSecondaryTableConstraint(secondaryTableStatement);
                }
            }
        }
    
protected voidprocessStatements()

        int size = statements.size();

        if (size > 1) {
            super.processStatements();

            for (int i = 0; i < size; i++) {
                UpdateStatement statement = (UpdateStatement) statements.get(i);

                if (!statement.isConstraintAdded())
                    processRelatedStatements(statement);
            }
        }

        UpdateStatement masterStatement = null;

        if (size == 1)
            masterStatement = (UpdateStatement) statements.get(0);
        else {
            // Look for the master statement. It should be the one
            // with no constraints added.
            for (int i = 0; i < size; i++) {
                masterStatement = (UpdateStatement) statements.get(i);

                if (!masterStatement.isConstraintAdded()) break;
            }
        }

        if (action != ACT_INSERT)
            addBasetableConstraint(masterStatement);

        if ((action != ACT_INSERT) && (updateDesc.getConcurrency() != null))
            updateDesc.getConcurrency().update(this);