Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » sql » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
   10    * http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing,
   13    * software distributed under the License is distributed on an
   14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    * KIND, either express or implied.  See the License for the
   16    * specific language governing permissions and limitations
   17    * under the License.    
   18    */
   19   package org.apache.openjpa.jdbc.sql;
   20   
   21   import java.sql.SQLException;
   22   
   23   import org.apache.commons.lang.ObjectUtils;
   24   import org.apache.openjpa.jdbc.meta.ClassMapping;
   25   import org.apache.openjpa.jdbc.meta.RelationId;
   26   import org.apache.openjpa.jdbc.schema.Column;
   27   import org.apache.openjpa.jdbc.schema.ColumnIO;
   28   import org.apache.openjpa.jdbc.schema.ForeignKey;
   29   import org.apache.openjpa.jdbc.schema.Table;
   30   import org.apache.openjpa.kernel.OpenJPAStateManager;
   31   import org.apache.openjpa.lib.util.Localizer;
   32   import org.apache.openjpa.util.InvalidStateException;
   33   
   34   /**
   35    * Primary table row that tracks foreign keys and auto-inc columns.
   36    *
   37    * @author Abe White
   38    * @nojavadoc
   39    */
   40   public class PrimaryRow
   41       extends RowImpl {
   42   
   43       // VALID flag in superclass uses 2 << 0
   44       private static final byte PK_SET = 2 << 1;
   45       private static final byte PK_WHERE = 2 << 2;
   46       private static final byte DEPENDENT = 2 << 4;
   47   
   48       private static final Localizer _loc = Localizer.forPackage
   49           (PrimaryRow.class);
   50   
   51       private OpenJPAStateManager _pk = null;
   52       private ColumnIO _pkIO = null;
   53       private OpenJPAStateManager[] _fkSet = null;
   54       private ColumnIO[] _fkIO = null;
   55       private OpenJPAStateManager[] _fkWhere = null;
   56       private OpenJPAStateManager[] _relSet = null;
   57       private RelationId[] _callbacks = null;
   58       private Object _failed = null;
   59       private int _idx = -1;
   60   
   61       /**
   62        * Constructor; supply table and action.
   63        */
   64       public PrimaryRow(Table table, int action, OpenJPAStateManager owner) {
   65           this(table.getColumns(), action, owner);
   66       }
   67   
   68       protected PrimaryRow(Column[] cols, int action, OpenJPAStateManager owner) {
   69           super(cols, action);
   70           _pk = owner;
   71       }
   72   
   73       /**
   74        * Mark this row as dependent on some other row.
   75        */
   76       public boolean isDependent() {
   77           return (flags & DEPENDENT) > 0;
   78       }
   79   
   80       /**
   81        * Mark this row as dependent on some other row.
   82        */
   83       public void setDependent(boolean dependent) {
   84           if (dependent)
   85               flags |= DEPENDENT;
   86           else
   87               flags &= ~DEPENDENT;
   88       }
   89   
   90       /**
   91        * The index of this row in ordered row list.
   92        */
   93       public int getIndex() {
   94           return _idx;
   95       }
   96   
   97       /**
   98        * The index of this row in ordered row list.
   99        */
  100       public void setIndex(int idx) {
  101           _idx = idx;
  102       }
  103   
  104       public Object getFailedObject() {
  105           return _failed;
  106       }
  107   
  108       public void setFailedObject(Object failed) {
  109           _failed = failed;
  110       }
  111   
  112       public OpenJPAStateManager getPrimaryKey() {
  113           return _pk;
  114       }
  115   
  116       public void setPrimaryKey(OpenJPAStateManager sm)
  117           throws SQLException {
  118           setPrimaryKey(null, sm);
  119       }
  120   
  121       public void setPrimaryKey(ColumnIO io, OpenJPAStateManager sm) {
  122           _pk = sm;
  123           flags |= PK_SET;
  124           _pkIO = io;
  125   
  126           // force valid
  127           setValid(true);
  128       }
  129   
  130       public void wherePrimaryKey(OpenJPAStateManager sm)
  131           throws SQLException {
  132           _pk = sm;
  133           flags |= PK_WHERE;
  134   
  135           // force valid
  136           if (getAction() == ACTION_DELETE)
  137               setValid(true);
  138       }
  139   
  140       /**
  141        * Return the I/O information for the given set foreign key.
  142        */
  143       public ColumnIO getForeignKeyIO(ForeignKey fk) {
  144           return (_fkIO == null) ? null : _fkIO[fk.getIndex()];
  145       }
  146   
  147       /**
  148        * Return the value for the given foreign key. Values not needed for
  149        * constraint analyses are not recorded.
  150        */
  151       public OpenJPAStateManager getForeignKeySet(ForeignKey fk) {
  152           return (_fkSet == null) ? null : _fkSet[fk.getIndex()];
  153       }
  154   
  155       /**
  156        * Return the value for the given foreign key. Values not needed for
  157        * constraint analyses are not recorded.
  158        */
  159       public OpenJPAStateManager getForeignKeyWhere(ForeignKey fk) {
  160           return (_fkWhere == null) ? null : _fkWhere[fk.getIndex()];
  161       }
  162   
  163       public void setForeignKey(ForeignKey fk, OpenJPAStateManager sm)
  164           throws SQLException {
  165           setForeignKey(fk, null, sm);
  166       }
  167   
  168       public void setForeignKey(ForeignKey fk, ColumnIO io,
  169           OpenJPAStateManager sm)
  170           throws SQLException {
  171           if (!delayForeignKey(fk, sm, true))
  172               super.setForeignKey(fk, io, sm);
  173           else
  174               recordForeignKey(fk, io, sm, true);
  175       }
  176   
  177       public void whereForeignKey(ForeignKey fk, OpenJPAStateManager sm)
  178           throws SQLException {
  179           if (!delayForeignKey(fk, sm, false))
  180               super.whereForeignKey(fk, sm);
  181           else
  182               recordForeignKey(fk, null, sm, false);
  183       }
  184   
  185       public void clearForeignKey(ForeignKey fk)
  186           throws SQLException {
  187           super.clearForeignKey(fk);
  188           if (_fkSet != null)
  189               _fkSet[fk.getIndex()] = null;
  190           if (_fkIO != null)
  191               _fkIO[fk.getIndex()] = null;
  192       }
  193   
  194       /**
  195        * If this is a delete, delay foreign keys to other deleted objects if
  196        * the key is restricted. If this is an update or insert, delay foreign
  197        * keys to other inserts if the key is not logical. If the foreign key
  198        * is to a new record and the columns are auto-inc, record it.
  199        */
  200       private boolean delayForeignKey(ForeignKey fk, OpenJPAStateManager sm,
  201           boolean set) {
  202           if (sm == null)
  203               return false;
  204   
  205           if (getAction() == ACTION_DELETE)
  206               return sm.isDeleted() && !fk.isDeferred()
  207                   && fk.getDeleteAction() == ForeignKey.ACTION_RESTRICT;
  208   
  209           if (!sm.isNew() || sm.isFlushed())
  210               return false;
  211           if (!fk.isDeferred() && !fk.isLogical())
  212               return true;
  213           if (fk.isPrimaryKeyAutoAssigned())
  214               return true;
  215           return false;
  216       }
  217   
  218       /**
  219        * Record a delayed foreign key.
  220        */
  221       private void recordForeignKey(ForeignKey fk, ColumnIO io,
  222           OpenJPAStateManager sm, boolean set) {
  223           if (set) {
  224               // force valid
  225               if (canSetAny(io, fk.getColumns().length
  226                   + fk.getConstantColumns().length, false))
  227                   setValid(true);
  228   
  229               if (_fkSet == null)
  230                   _fkSet = new OpenJPAStateManager[getTable().
  231                       getForeignKeys().length];
  232               _fkSet[fk.getIndex()] = sm;
  233   
  234               if (_fkIO != null)
  235                   _fkIO[fk.getIndex()] = io;
  236               else if (io != null && ((getAction() == ACTION_INSERT
  237                   && !io.isAllInsertable(fk, false))
  238                   || (getAction() != ACTION_INSERT
  239                   && !io.isAllUpdatable(fk, false)))) {
  240                   _fkIO = new ColumnIO[_fkSet.length];
  241                   _fkIO[fk.getIndex()] = io;
  242               }
  243           } else {
  244               // force valid
  245               if (getAction() == ACTION_DELETE)
  246                   setValid(true);
  247   
  248               if (_fkWhere == null)
  249                   _fkWhere = new OpenJPAStateManager[getTable().
  250                       getForeignKeys().length];
  251               _fkWhere[fk.getIndex()] = sm;
  252           }
  253       }
  254   
  255       /**
  256        * Return the recorded value for the given relation id column. Only
  257        * values that are dependent on a new, unflushed auto-assigned instance
  258        * are recorded.
  259        */
  260       public OpenJPAStateManager getRelationIdSet(Column col) {
  261           return (_relSet == null) ? null : _relSet[getRelationIdIndex(col)];
  262       }
  263   
  264       /**
  265        * Return the recorded callbacks for the given relation id column. Only
  266        * values that are dependent on a new, unflushed auto-assigned instance
  267        * are recorded.
  268        */
  269       public RelationId getRelationIdCallback(Column col) {
  270           return (_callbacks == null) ? null
  271               : _callbacks[getRelationIdIndex(col)];
  272       }
  273   
  274       public void setRelationId(Column col, OpenJPAStateManager sm,
  275           RelationId rel)
  276           throws SQLException {
  277           if (sm == null || sm.getObjectId() != null || !sm.isNew()
  278               || sm.isFlushed() || !isPrimaryKeyAutoAssigned(sm))
  279               super.setRelationId(col, sm, rel);
  280           else {
  281               if (_relSet == null) {
  282                   Column[] cols = getTable().getRelationIdColumns();
  283                   _relSet = new OpenJPAStateManager[cols.length];
  284                   _callbacks = new RelationId[cols.length];
  285               }
  286               int idx = getRelationIdIndex(col);
  287               _relSet[idx] = sm;
  288               _callbacks[idx] = rel;
  289           }
  290       }
  291   
  292       public void clearRelationId(Column col)
  293           throws SQLException {
  294           super.clearRelationId(col);
  295           if (_relSet != null) {
  296               int idx = getRelationIdIndex(col);
  297               _relSet[idx] = null;
  298               _callbacks[idx] = null;
  299           }
  300       }
  301   
  302       /**
  303        * Return the index into our relation id array of the value for the
  304        * given column.
  305        */
  306       private int getRelationIdIndex(Column col) {
  307           Column[] cols = getTable().getRelationIdColumns();
  308           for (int i = 0; i < cols.length; i++)
  309               if (cols[i] == col)
  310                   return i;
  311           return -1;
  312       }
  313   
  314       /**
  315        * Return true if any primary key columns of the given instance are
  316        * auto-assigned.
  317        */
  318       private static boolean isPrimaryKeyAutoAssigned(OpenJPAStateManager sm) {
  319           ClassMapping cls = (ClassMapping) sm.getMetaData();
  320           while (cls.getJoinablePCSuperclassMapping() != null)
  321               cls = cls.getJoinablePCSuperclassMapping();
  322           Column[] cols = cls.getPrimaryKeyColumns();
  323           for (int i = 0; i < cols.length; i++)
  324               if (cols[i].isAutoAssigned())
  325                   return true;
  326           return false;
  327       }
  328   
  329       protected void setObject(Column col, Object val, int metaType,
  330           boolean overrideDefault)
  331           throws SQLException {
  332           // make sure we're not setting two different values
  333           Object prev = getSet(col);
  334           if (prev != null) {
  335               if (prev == NULL)
  336                   prev = null;
  337               if (!rowValueEquals(prev, val)) {
  338                   throw new InvalidStateException(_loc.get("diff-values",
  339                       new Object[]{ col.getFullName(),
  340                           (prev == null) ? null : prev.getClass(), prev,
  341                           (val == null) ? null : val.getClass(), val })).
  342                       setFatal(true);
  343               }
  344           }
  345           super.setObject(col, val, metaType, overrideDefault);
  346       }
  347   
  348       /**
  349        * Return true if the two values should be considered equal.
  350        */
  351       private static boolean rowValueEquals(Object o1, Object o2) {
  352           if (ObjectUtils.equals(o1, o2))
  353               return true;
  354   
  355           // check for numeric equality (bug #1151)
  356           return o1 instanceof Number && o2 instanceof Number
  357               && ((Number) o1).doubleValue() == ((Number) o2).doubleValue();
  358       }
  359   
  360       protected String generateSQL(DBDictionary dict) {
  361           try {
  362               if ((flags & PK_SET) > 0)
  363                   super.setPrimaryKey(_pkIO, _pk);
  364               if ((flags & PK_WHERE) > 0)
  365                   super.wherePrimaryKey(_pk);
  366               if (_fkSet != null) {
  367                   ForeignKey[] fks = getTable().getForeignKeys();
  368                   ColumnIO io;
  369                   for (int i = 0; i < _fkSet.length; i++) {
  370                       if (_fkSet[i] != null) {
  371                           io = (_fkIO == null) ? null : _fkIO[i];
  372                           super.setForeignKey(fks[i], io, _fkSet[i]);
  373                       }
  374                   }
  375               }
  376               if (_relSet != null) {
  377                   Column[] cols = getTable().getRelationIdColumns();
  378                   for (int i = 0; i < _relSet.length; i++)
  379                       if (_relSet[i] != null)
  380                           super.setRelationId(cols[i], _relSet[i], _callbacks[i]);
  381               }
  382               if (_fkWhere != null) {
  383                   ForeignKey[] fks = getTable().getForeignKeys();
  384                   for (int i = 0; i < _fkWhere.length; i++)
  385                       if (_fkWhere[i] != null)
  386                           super.whereForeignKey(fks[i], _fkWhere[i]);
  387               }
  388           }
  389           catch (SQLException se) {
  390               throw SQLExceptions.getStore(se, dict);
  391           }
  392           return super.generateSQL(dict);
  393       }
  394   
  395       protected RowImpl newInstance(Column[] cols, int action) {
  396           return new PrimaryRow(cols, action, _pk);
  397       }
  398   
  399       public void copyInto(RowImpl row, boolean whereOnly) {
  400           super.copyInto(row, whereOnly);
  401           if (!(row instanceof PrimaryRow))
  402               return;
  403   
  404           PrimaryRow prow = (PrimaryRow) row;
  405           prow._pk = _pk;
  406           prow._pkIO = _pkIO;
  407           if ((flags & PK_WHERE) > 0)
  408               prow.flags |= PK_WHERE;
  409           if (!whereOnly && (flags & PK_SET) > 0)
  410               prow.flags |= PK_SET;
  411   
  412           if (_fkWhere != null) {
  413               if (prow._fkWhere == null)
  414                   prow._fkWhere = new OpenJPAStateManager[_fkWhere.length];
  415               System.arraycopy(_fkWhere, 0, prow._fkWhere, 0, _fkWhere.length);
  416           }
  417           if (!whereOnly && _fkSet != null) {
  418               if (prow._fkSet == null)
  419                   prow._fkSet = new OpenJPAStateManager[_fkSet.length];
  420               System.arraycopy(_fkSet, 0, prow._fkSet, 0, _fkSet.length);
  421               if (_fkIO != null) {
  422                   if (prow._fkIO == null)
  423                       prow._fkIO = new ColumnIO[_fkIO.length];
  424                   System.arraycopy(_fkIO, 0, prow._fkIO, 0, _fkIO.length);
  425               }
  426           }
  427           if (!whereOnly && _relSet != null) {
  428               if (prow._relSet == null) {
  429                   prow._relSet = new OpenJPAStateManager[_relSet.length];
  430                   prow._callbacks = new RelationId[_callbacks.length];
  431               }
  432               System.arraycopy(_relSet, 0, prow._relSet, 0, _relSet.length);
  433               System.arraycopy(_callbacks, 0, prow._callbacks, 0,
  434                   _callbacks.length);
  435           }
  436       }
  437   }

Save This Page
Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » sql » [javadoc | source]