Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » kernel » exps » [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.kernel.exps;
   20   
   21   import java.io.Serializable;
   22   import java.sql.SQLException;
   23   import java.util.Iterator;
   24   import java.util.LinkedList;
   25   import java.util.ListIterator;
   26   
   27   import org.apache.commons.lang.ObjectUtils;
   28   import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
   29   import org.apache.openjpa.jdbc.meta.ClassMapping;
   30   import org.apache.openjpa.jdbc.meta.FieldMapping;
   31   import org.apache.openjpa.jdbc.meta.ValueMapping;
   32   import org.apache.openjpa.jdbc.schema.Column;
   33   import org.apache.openjpa.jdbc.schema.ForeignKey;
   34   import org.apache.openjpa.jdbc.schema.Schemas;
   35   import org.apache.openjpa.jdbc.sql.Joins;
   36   import org.apache.openjpa.jdbc.sql.Result;
   37   import org.apache.openjpa.jdbc.sql.SQLBuffer;
   38   import org.apache.openjpa.jdbc.sql.Select;
   39   import org.apache.openjpa.kernel.Filters;
   40   import org.apache.openjpa.lib.util.Localizer;
   41   import org.apache.openjpa.meta.ClassMetaData;
   42   import org.apache.openjpa.meta.FieldMetaData;
   43   import org.apache.openjpa.meta.JavaTypes;
   44   import org.apache.openjpa.meta.XMLMetaData;
   45   import org.apache.openjpa.util.UserException;
   46   
   47   /**
   48    * A path represents a traversal into fields of a candidate object.
   49    *
   50    * @author Abe White
   51    */
   52   public class PCPath
   53       extends AbstractVal
   54       implements JDBCPath {
   55   
   56       private static final int PATH = 0;
   57       private static final int BOUND_VAR = 1;
   58       private static final int UNBOUND_VAR = 2;
   59       private static final int UNACCESSED_VAR = 3;
   60       private static final int XPATH = 4;
   61   
   62       private static final Localizer _loc = Localizer.forPackage(PCPath.class);
   63   
   64       private final ClassMapping _candidate;
   65       private ClassMapping _class = null;
   66       private LinkedList _actions = null;
   67       private boolean _key = false;
   68       private int _type = PATH;
   69       private String _varName = null;
   70       private Class _cast = null;
   71       private boolean _cid = false;
   72       private FieldMetaData _xmlfield = null;
   73   
   74       /**
   75        * Return a path starting with the 'this' ptr.
   76        */
   77       public PCPath(ClassMapping type) {
   78           _candidate = type;
   79       }
   80   
   81       /**
   82        * Return a path starting from the given variable.
   83        */
   84       public PCPath(ClassMapping candidate, Variable var) {
   85           _candidate = candidate;
   86           _actions = new LinkedList();
   87   
   88           PCPath other = var.getPCPath();
   89           Action action = new Action();
   90           if (other == null) {
   91               _type = UNBOUND_VAR;
   92               action.op = Action.UNBOUND_VAR;
   93               action.data = var;
   94           } else {
   95               // bound variable; copy path
   96               _type = UNACCESSED_VAR;
   97               _actions.addAll(other._actions);
   98               _key = other._key;
   99   
  100               action.op = Action.VAR;
  101               action.data = var.getName();
  102           }
  103           _actions.add(action);
  104           _cast = var.getType(); // initial type is var type
  105       }
  106   
  107       /**
  108        * Return a path starting from the given subquery.
  109        */
  110       public PCPath(SubQ sub) {
  111           _candidate = sub.getCandidate();
  112           _actions = new LinkedList();
  113   
  114           Action action = new Action();
  115           action.op = Action.SUBQUERY;
  116           action.data = sub.getCandidateAlias();
  117           _actions.add(action);
  118           _cast = sub.getType(); // initial type is subquery type
  119           _varName = sub.getCandidateAlias();
  120       }
  121   
  122       /**
  123        * Set the path as a binding of the given variable.
  124        */
  125       public void addVariableAction(Variable var) {
  126           _varName = var.getName();
  127       }
  128   
  129       /**
  130        * Return true if this is a bound variable that has not been accessed
  131        * after binding. Useful for filters like
  132        * "coll.contains (var) && var == null", which should really
  133        * just act like "coll.contains (null)".
  134        */
  135       public boolean isUnaccessedVariable() {
  136           return _type == UNACCESSED_VAR;
  137       }
  138   
  139       /**
  140        * Return whether this is a path involving a variable.
  141        */
  142       public boolean isVariablePath() {
  143           return _type != PATH;
  144       }
  145   
  146       /**
  147        * If this path is part of a contains clause, then alias it to the
  148        * proper contains id before initialization.
  149        */
  150       public synchronized void setContainsId(String id) {
  151           if (_cid)
  152               return;
  153   
  154           // treat it just like a unique variable
  155           Action action = new Action();
  156           action.op = Action.VAR;
  157           action.data = id;
  158           if (_actions == null)
  159               _actions = new LinkedList();
  160           _actions.add(action);
  161           _cid = true;
  162       }
  163   
  164       public ClassMetaData getMetaData() {
  165           return _class;
  166       }
  167   
  168       public void setMetaData(ClassMetaData meta) {
  169           _class = (ClassMapping) meta;
  170       }
  171   
  172       public boolean isKey() {
  173           return _key;
  174       }
  175       
  176       public boolean isXPath() {
  177           return _type == XPATH;
  178       }
  179       
  180       public String getXPath() {
  181           StringBuffer xpath = new StringBuffer();
  182           Action action;
  183           Iterator itr = _actions.iterator();
  184           
  185           // Skip variable actions since they are not part of the xpath
  186           // until we reach the first xpath action.
  187           // The first xpath action maps to the root of an xml document.
  188           do 
  189               action = (Action) itr.next(); 
  190           while (action.op != Action.GET_XPATH);
  191           
  192           // Skip XmlRootElement:
  193           // We can't rely on the accuracy of the name of the root element,
  194           // because it could be set to some default by JAXB XML Binding.
  195           // The caller(DBDictionary) should start with "/*" or "/*/",
  196           // we build the remaining xpath that follows the root element.
  197           while (itr.hasNext()) {
  198               action = (Action) itr.next();
  199               if (((XMLMetaData) action.data).getXmlname() != null)                 
  200                   xpath.append(((XMLMetaData) action.data).getXmlname());
  201               else
  202                   xpath.append("*");
  203               if (itr.hasNext())
  204                   xpath.append("/");
  205           }
  206           return xpath.toString();
  207       }
  208       
  209       public String getPath() {
  210           if (_actions == null)
  211               return (_varName == null) ? "" : _varName + ".";
  212   
  213           StringBuffer path = new StringBuffer();
  214           Action action;
  215           for (Iterator itr = _actions.iterator(); itr.hasNext();) {
  216               action = (Action) itr.next();
  217               if (action.op == Action.VAR || action.op == Action.SUBQUERY)
  218                   path.append(action.data);
  219               else if (action.op == Action.UNBOUND_VAR)
  220                   path.append(((Variable) action.data).getName());
  221               else 
  222                   path.append(((FieldMapping) action.data).getName());
  223               path.append('.');
  224           }
  225           if (_varName != null)
  226               path.append(_varName).append('.');
  227           return path.toString();
  228       }
  229   
  230       public ClassMapping getClassMapping(ExpState state) {
  231           PathExpState pstate = (PathExpState) state;
  232           if (pstate.field == null)
  233               return _class;
  234           if (_key) {
  235               if (pstate.field.getKey().getTypeCode() == JavaTypes.PC)
  236                   return pstate.field.getKeyMapping().getTypeMapping();
  237               return null;
  238           }
  239           if (pstate.field.getElement().getTypeCode() == JavaTypes.PC)
  240               return pstate.field.getElementMapping().getTypeMapping();
  241           if (pstate.field.getTypeCode() == JavaTypes.PC)
  242               return pstate.field.getTypeMapping();
  243           return null;
  244       }
  245   
  246       public FieldMapping getFieldMapping(ExpState state) {
  247           return ((PathExpState) state).field;
  248       }
  249   
  250       public Column[] getColumns(ExpState state) {
  251           PathExpState pstate = (PathExpState) state;
  252           if (pstate.cols == null)
  253               pstate.cols = calculateColumns(pstate);
  254           return pstate.cols;
  255       }
  256   
  257       /**
  258        * The columns used by this path.
  259        */
  260       private Column[] calculateColumns(PathExpState pstate) {
  261           if (_key) {
  262               if (!pstate.joinedRel 
  263                   && pstate.field.getKey().getValueMappedBy() != null)
  264                   joinRelation(pstate, _key, false, false);
  265               else if (pstate.joinedRel 
  266                   && pstate.field.getKey().getTypeCode() == JavaTypes.PC)
  267                   return pstate.field.getKeyMapping().getTypeMapping().
  268                       getPrimaryKeyColumns();
  269               return pstate.field.getKeyMapping().getColumns();
  270           }
  271           if (pstate.field != null) {
  272               switch (pstate.field.getTypeCode()) {
  273                   case JavaTypes.MAP:
  274                   case JavaTypes.ARRAY:
  275                   case JavaTypes.COLLECTION:
  276                       ValueMapping elem = pstate.field.getElementMapping();
  277                       if (pstate.joinedRel && elem.getTypeCode() == JavaTypes.PC)
  278                           return elem.getTypeMapping().getPrimaryKeyColumns();
  279                       if (elem.getColumns().length > 0)
  280                           return elem.getColumns();
  281                       return pstate.field.getColumns();
  282                   case JavaTypes.PC:
  283                       if (pstate.joinedRel)
  284                           return pstate.field.getTypeMapping().
  285                               getPrimaryKeyColumns();
  286                       return pstate.field.getColumns();
  287                   default:
  288                       return pstate.field.getColumns();
  289               }
  290           }
  291           return (_class == null) ? Schemas.EMPTY_COLUMNS
  292               : _class.getPrimaryKeyColumns();
  293       }
  294   
  295       public boolean isVariable() {
  296           if (_actions == null)
  297               return false;
  298           Action action = (Action) _actions.getLast();
  299           return action.op == Action.UNBOUND_VAR || action.op == Action.VAR; 
  300       }
  301   
  302       public void get(FieldMetaData field, boolean nullTraversal) {
  303           if (_actions == null)
  304               _actions = new LinkedList();
  305           Action action = new Action();
  306           action.op = (nullTraversal) ? Action.GET_OUTER : Action.GET;
  307           action.data = field;
  308           _actions.add(action);
  309           if (_type == UNACCESSED_VAR)
  310               _type = BOUND_VAR;
  311           _cast = null;
  312           _key = false;
  313       }
  314       
  315       public void get(FieldMetaData fmd, XMLMetaData meta) {
  316           if (_actions == null)
  317               _actions = new LinkedList();
  318           Action action = new Action();
  319           action.op = Action.GET_XPATH;
  320           action.data = meta;
  321           _actions.add(action);
  322           _cast = null;
  323           _key = false;
  324           _type = XPATH;
  325           _xmlfield = fmd;
  326       }
  327       
  328       public void get(XMLMetaData meta, String name) {
  329           Action action = new Action();
  330           action.op = Action.GET_XPATH;
  331           action.data = meta.getFieldMapping(name);
  332           _actions.add(action);
  333           _cast = null;
  334           _key = false;
  335           _type = XPATH;
  336       }
  337       
  338       public XMLMetaData getXmlMapping() {
  339           Action act = (Action) _actions.getLast();
  340           if (act != null)
  341               return (XMLMetaData) act.data;
  342           return null;
  343       }
  344   
  345       public synchronized void getKey() {
  346           if (_cid)
  347               return;
  348   
  349           // change the last action to a get key
  350           Action action = (Action) _actions.getLast();
  351           action.op = Action.GET_KEY;
  352           _cast = null;
  353           _key = true;
  354       }
  355   
  356       public FieldMetaData last() {
  357           Action act = lastFieldAction();
  358           return (act == null) ? null : isXPath() ? _xmlfield :
  359               (FieldMetaData) act.data;
  360       }
  361   
  362       /**
  363        * Return the last action that gets a field.
  364        */
  365       private Action lastFieldAction() {
  366           if (_actions == null)
  367               return null;
  368   
  369           if (isXPath())
  370               return (Action) _actions.getLast();
  371           
  372           ListIterator itr = _actions.listIterator(_actions.size());
  373           Action prev;
  374           while (itr.hasPrevious()) {
  375               prev = (Action) itr.previous();
  376               if (prev.op == Action.GET || prev.op == Action.GET_OUTER
  377                   || prev.op == Action.GET_KEY)
  378                   return prev;
  379           }
  380           return null;
  381       }
  382   
  383       public Class getType() {
  384           if (_cast != null)
  385               return _cast;
  386           Action act = lastFieldAction();
  387           if (act != null && act.op == Action.GET_XPATH)
  388               return ((XMLMetaData) act.data).getType();
  389           
  390           FieldMetaData fld = (act == null) ? null : (FieldMetaData) act.data;
  391           boolean key = act != null && act.op == Action.GET_KEY;
  392           if (fld != null) {
  393               switch (fld.getDeclaredTypeCode()) {
  394                   case JavaTypes.ARRAY:
  395                       if (fld.getDeclaredType() == byte[].class
  396                           || fld.getDeclaredType() == Byte[].class
  397                           || fld.getDeclaredType() == char[].class
  398                           || fld.getDeclaredType() == Character[].class)
  399                           return fld.getDeclaredType();
  400                       return fld.getElement().getDeclaredType();
  401                   case JavaTypes.MAP:
  402                       if (key)
  403                           return fld.getKey().getDeclaredType();
  404                       return fld.getElement().getDeclaredType();
  405                   case JavaTypes.COLLECTION:
  406                       return fld.getElement().getDeclaredType();
  407                   default:
  408                       return fld.getDeclaredType();
  409               }
  410           }
  411           if (_class != null)
  412               return _class.getDescribedType();
  413           return Object.class;
  414       }
  415   
  416       public void setImplicitType(Class type) {
  417           _cast = type;
  418       }
  419   
  420       public ExpState initialize(Select sel, ExpContext ctx, int flags) {
  421           PathExpState pstate = new PathExpState(sel.newJoins());
  422           boolean key = false;
  423           boolean forceOuter = false;
  424           ClassMapping rel = _candidate;
  425   
  426           // iterate to the final field
  427           ClassMapping owner;
  428           ClassMapping from, to;
  429           Action action;
  430           Variable var;
  431           Iterator itr = (_actions == null) ? null : _actions.iterator();
  432           FieldMapping field;
  433           while (itr != null && itr.hasNext()) {
  434               action = (Action) itr.next();
  435   
  436               // treat subqueries like variables for alias generation purposes
  437               if (action.op == Action.VAR)
  438                   pstate.joins = pstate.joins.setVariable((String) action.data);
  439               else if (action.op == Action.SUBQUERY)
  440                   pstate.joins = pstate.joins.setSubselect((String) action.data);
  441               else if (action.op == Action.UNBOUND_VAR) {
  442                   // unbound vars are cross-joined to the candidate table
  443                   var = (Variable) action.data;
  444                   rel = (ClassMapping) var.getMetaData();
  445                   pstate.joins = pstate.joins.setVariable(var.getName());
  446                   pstate.joins = pstate.joins.crossJoin(_candidate.getTable(), 
  447                       rel.getTable());
  448               } else {
  449                   // move past the previous field, if any
  450                   field = (action.op == Action.GET_XPATH) ? (FieldMapping) _xmlfield :
  451                       (FieldMapping) action.data;
  452                   if (pstate.field != null) {
  453                       // if this is the second-to-last field and the last is
  454                       // the related field this field joins to, no need to
  455                       // traverse: just use this field's fk columns
  456                       if (!itr.hasNext() && (flags & JOIN_REL) == 0
  457                           && isJoinedField(pstate.field, key, field)) {
  458                           pstate.cmpfield = field;
  459                           break;
  460                       }
  461                       rel = traverseField(pstate, key, forceOuter, false);
  462                   }
  463   
  464                   // mark if the next traversal should go through
  465                   // the key rather than value
  466                   key = action.op == Action.GET_KEY;
  467                   forceOuter |= action.op == Action.GET_OUTER;
  468   
  469                   // get mapping for the current field
  470                   pstate.field = field;
  471                   owner = pstate.field.getDefiningMapping();
  472                   if (pstate.field.getManagement() 
  473                       != FieldMapping.MANAGE_PERSISTENT)
  474                       throw new UserException(_loc.get("non-pers-field", 
  475                           pstate.field));
  476   
  477                   // find the most-derived type between the declared relation
  478                   // type and the field's owner, and join from that type to
  479                   // the lesser derived type
  480                   if (rel != owner && rel != null) {
  481                       if (rel.getDescribedType().isAssignableFrom
  482                           (owner.getDescribedType())) {
  483                           from = owner;
  484                           to = rel;
  485                       } else {
  486                           from = rel;
  487                           to = owner;
  488                       }
  489   
  490                       for (; from != null && from != to;
  491                           from = from.getJoinablePCSuperclassMapping())
  492                           pstate.joins = from.joinSuperclass(pstate.joins, false);
  493                   }
  494                   // nothing more to do from here on as we encountered an xpath action
  495                   if (action.op == Action.GET_XPATH)
  496                       break;
  497               }
  498           }
  499           if (_varName != null)
  500               pstate.joins = pstate.joins.setVariable(_varName);
  501   
  502           // if we're not comparing to null or doing an isEmpty, then
  503           // join into the data on the final field; obviously we can't do these
  504           // joins when comparing to null b/c the whole purpose is to see
  505           // whether the joins even exist
  506           if ((flags & NULL_CMP) == 0)
  507               traverseField(pstate, key, forceOuter, true);
  508           pstate.joinedRel = false;
  509           if ((flags & JOIN_REL) != 0)
  510               joinRelation(pstate, key, forceOuter || (flags & FORCE_OUTER) != 0,
  511                   false);
  512           return pstate;
  513       }
  514   
  515       /**
  516        * Return whether the given source field joins to the given target field.
  517        */
  518       private static boolean isJoinedField(FieldMapping src, boolean key, 
  519           FieldMapping target) {
  520           ValueMapping vm;
  521           switch (src.getTypeCode()) {
  522               case JavaTypes.ARRAY:
  523               case JavaTypes.COLLECTION:
  524                   vm = src.getElementMapping();
  525                   break;
  526               case JavaTypes.MAP:
  527                   vm = (key) ? src.getKeyMapping() : src.getElementMapping();
  528                   break;
  529               default:
  530                   vm = src;
  531           }
  532           if (vm.getJoinDirection() != ValueMapping.JOIN_FORWARD)
  533               return false;
  534           ForeignKey fk = vm.getForeignKey();
  535           if (fk == null)
  536               return false; 
  537           
  538           // foreign key must join to target columns
  539           Column[] rels = fk.getColumns();
  540           Column[] pks = target.getColumns(); 
  541           if (rels.length != pks.length)
  542               return false;
  543           for (int i = 0; i < rels.length; i++)
  544               if (fk.getPrimaryKeyColumn(rels[i]) != pks[i])
  545                   return false;
  546           return true;
  547       }
  548   
  549       /**
  550        * Expression state.
  551        */
  552       public static class PathExpState
  553           extends ExpState {
  554   
  555           public FieldMapping field = null;
  556           public FieldMapping cmpfield = null;
  557           public Column[] cols = null;
  558           public boolean joinedRel = false;
  559   
  560           public PathExpState(Joins joins) {
  561               super(joins);
  562           }
  563       }
  564   
  565       /**
  566        * Traverse into the previous field of a relation path.
  567        *
  568        * @param last whether this is the last field in the path
  569        * @return the mapping of the related type, or null
  570        */
  571       private ClassMapping traverseField(PathExpState pstate, boolean key, 
  572           boolean forceOuter, boolean last) {
  573           if (pstate.field == null)
  574               return null;
  575   
  576           // traverse into field value
  577           if (key)
  578               pstate.joins = pstate.field.joinKey(pstate.joins, forceOuter);
  579           else
  580               pstate.joins = pstate.field.join(pstate.joins, forceOuter);
  581   
  582           // if this isn't the last field, traverse into the relation
  583           if (!last)
  584               joinRelation(pstate, key, forceOuter, true);
  585   
  586           // return the maping of the related type, if any
  587           if (key)
  588               return pstate.field.getKeyMapping().getTypeMapping();
  589           if (pstate.field.getElement().getTypeCode() == JavaTypes.PC)
  590               return pstate.field.getElementMapping().getTypeMapping();
  591           return pstate.field.getTypeMapping();
  592       }
  593   
  594       /**
  595        * Join into the relation represented by the current field, if any.
  596        */
  597       private void joinRelation(PathExpState pstate, boolean key, 
  598           boolean forceOuter, boolean traverse) {
  599           if (pstate.field == null)
  600               return;
  601           if (key)
  602               pstate.joins = pstate.field.joinKeyRelation(pstate.joins, 
  603                   forceOuter, traverse);
  604           else
  605               pstate.joins = pstate.field.joinRelation(pstate.joins, forceOuter,
  606                   traverse);
  607           pstate.joinedRel = true;
  608       }
  609   
  610       public Object toDataStoreValue(Select sel, ExpContext ctx, ExpState state, 
  611           Object val) {
  612           PathExpState pstate = (PathExpState) state;
  613           FieldMapping field = (pstate.cmpfield != null) ? pstate.cmpfield 
  614               : pstate.field;
  615           if (isXPath())
  616               return val;
  617           if (field != null) {
  618               if (_key)
  619                   return field.toKeyDataStoreValue(val, ctx.store);
  620               if (field.getElement().getDeclaredTypeCode() != JavaTypes.OBJECT)
  621                   return field.toDataStoreValue(val, ctx.store);
  622   
  623               val = field.getExternalValue(val, ctx.store.getContext());
  624               return field.toDataStoreValue(val, ctx.store);
  625           }
  626           return _class.toDataStoreValue(val, _class.getPrimaryKeyColumns(),
  627               ctx.store);
  628       }
  629   
  630       public void select(Select sel, ExpContext ctx, ExpState state, 
  631           boolean pks) {
  632           selectColumns(sel, ctx, state, pks);
  633       }
  634   
  635       public void selectColumns(Select sel, ExpContext ctx, ExpState state, 
  636           boolean pks) {
  637           ClassMapping mapping = getClassMapping(state);
  638           PathExpState pstate = (PathExpState) state;
  639           if (mapping == null || !pstate.joinedRel)
  640               sel.select(getColumns(state), pstate.joins);
  641           else if (pks)
  642               sel.select(mapping.getPrimaryKeyColumns(), pstate.joins);
  643           else {
  644               // select the mapping; allow any subs because we know this must
  645               // be either a relation, in which case it will already be
  646               // constrained by the joins, or 'this', in which case the
  647               // JDBCExpressionFactory takes care of adding class conditions for
  648               // the candidate class on the select
  649               int subs = (_type == UNBOUND_VAR) ? Select.SUBS_JOINABLE
  650                   : Select.SUBS_ANY_JOINABLE;
  651               sel.select(mapping, subs, ctx.store, ctx.fetch,
  652                   JDBCFetchConfiguration.EAGER_NONE, sel.outer(pstate.joins));
  653           }
  654       }
  655   
  656       public void groupBy(Select sel, ExpContext ctx, ExpState state) {
  657           ClassMapping mapping = getClassMapping(state);
  658           PathExpState pstate = (PathExpState) state;
  659           if (mapping == null || !pstate.joinedRel)
  660               sel.groupBy(getColumns(state), sel.outer(pstate.joins));
  661           else {
  662               int subs = (_type == UNBOUND_VAR) ? Select.SUBS_JOINABLE
  663                   : Select.SUBS_ANY_JOINABLE;
  664               sel.groupBy(mapping, subs, ctx.store, ctx.fetch, 
  665                   sel.outer(pstate.joins));
  666           }
  667       }
  668   
  669       public void orderBy(Select sel, ExpContext ctx, ExpState state, 
  670           boolean asc) {
  671           sel.orderBy(getColumns(state), asc, sel.outer(state.joins), false);
  672       }
  673   
  674       public Object load(ExpContext ctx, ExpState state, Result res)
  675           throws SQLException {
  676           return load(ctx, state, res, false);
  677       }
  678   
  679       Object load(ExpContext ctx, ExpState state, Result res, boolean pks)
  680           throws SQLException {
  681           ClassMapping mapping = getClassMapping(state);
  682           PathExpState pstate = (PathExpState) state;
  683           if (mapping != null && (pstate.field == null 
  684               || !pstate.field.isEmbedded())) {
  685               if (pks)
  686                   return mapping.getObjectId(ctx.store, res, null, true, 
  687                       pstate.joins);
  688               return res.load(mapping, ctx.store, ctx.fetch, pstate.joins);
  689           }
  690   
  691           Object ret;
  692           if (_key)
  693               ret = pstate.field.loadKeyProjection(ctx.store, ctx.fetch, res, 
  694                   pstate.joins);
  695           else
  696               ret = pstate.field.loadProjection(ctx.store, ctx.fetch, res, 
  697                   pstate.joins);
  698           if (_cast != null)
  699               ret = Filters.convert(ret, _cast);
  700           return ret;
  701       }
  702   
  703       public void calculateValue(Select sel, ExpContext ctx, ExpState state, 
  704           Val other, ExpState otherState) {
  705           // we don't create the SQL b/c it forces the Select to cache aliases
  706           // for the tables we use, and these aliases might not ever be used if
  707           // we eventually call appendIsEmpty or appendIsNull rather than appendTo
  708       }
  709   
  710       public int length(Select sel, ExpContext ctx, ExpState state) {
  711           return getColumns(state).length;
  712       }
  713   
  714       public void appendTo(Select sel, ExpContext ctx, ExpState state, 
  715           SQLBuffer sql, int index) {
  716           Column col = getColumns(state)[index];
  717   
  718           // if select is null, it means we are not aliasing columns
  719           // (e.g., during a bulk update)
  720           if (sel == null)
  721               sql.append(col.getName());
  722           else if (_type == XPATH)
  723               // if this is an xpath, append xpath string
  724               sql.append(getXPath());
  725           else
  726               sql.append(sel.getColumnAlias(col, state.joins));
  727       }
  728   
  729       public void appendIsEmpty(Select sel, ExpContext ctx, ExpState state, 
  730           SQLBuffer sql) {
  731           PathExpState pstate = (PathExpState) state;
  732           if (pstate.field == null)
  733               sql.append(FALSE);
  734           else
  735               pstate.field.appendIsEmpty(sql, sel, pstate.joins);
  736       }
  737   
  738       public void appendIsNotEmpty(Select sel, ExpContext ctx, ExpState state, 
  739           SQLBuffer sql) {
  740           PathExpState pstate = (PathExpState) state;
  741           if (pstate.field == null)
  742               sql.append(FALSE);
  743           else
  744               pstate.field.appendIsNotEmpty(sql, sel, pstate.joins);
  745       }
  746   
  747       public void appendSize(Select sel, ExpContext ctx, ExpState state, 
  748           SQLBuffer sql) {
  749           PathExpState pstate = (PathExpState) state;
  750           if (pstate.field == null)
  751               sql.append("1");
  752           else
  753               pstate.field.appendSize(sql, sel, pstate.joins);
  754       }
  755   
  756       public void appendIsNull(Select sel, ExpContext ctx, ExpState state, 
  757           SQLBuffer sql) {
  758           PathExpState pstate = (PathExpState) state;
  759           if (pstate.field == null)
  760               sql.append(FALSE);
  761           else
  762               pstate.field.appendIsNull(sql, sel, pstate.joins);
  763       }
  764   
  765       public void appendIsNotNull(Select sel, ExpContext ctx, ExpState state, 
  766           SQLBuffer sql) {
  767           PathExpState pstate = (PathExpState) state;
  768           if (pstate.field == null)
  769               sql.append(TRUE);
  770           else
  771               pstate.field.appendIsNotNull(sql, sel, pstate.joins);
  772       }
  773   
  774       public int hashCode() {
  775           if (_actions == null)
  776               return _candidate.hashCode();
  777           return _candidate.hashCode() ^ _actions.hashCode();
  778       }
  779   
  780       public boolean equals(Object other) {
  781           if (other == this)
  782               return true;
  783           if (!(other instanceof PCPath))
  784               return false;
  785           PCPath path = (PCPath) other;
  786           return ObjectUtils.equals(_candidate, path._candidate)
  787               && ObjectUtils.equals(_actions, path._actions);
  788       }
  789   
  790       /**
  791        * Helper class representing an action.
  792        */
  793       private static class Action
  794           implements Serializable {
  795   
  796           public static final int GET = 0;
  797           public static final int GET_OUTER = 1;
  798           public static final int GET_KEY = 2;
  799           public static final int VAR = 3;
  800           public static final int SUBQUERY = 4;
  801           public static final int UNBOUND_VAR = 5;
  802           public static final int CAST = 6;
  803           public static final int GET_XPATH = 7;
  804   
  805           public int op = -1;
  806           public Object data = null;
  807   
  808           public String toString() {
  809               return op + "|" + data;
  810           }
  811   
  812           public int hashCode() {
  813               if (data == null)
  814                   return op;
  815               return op ^ data.hashCode();
  816           }
  817   
  818           public boolean equals(Object other) {
  819               if (other == this)
  820                   return true;
  821               Action a = (Action) other;
  822               return op == a.op
  823                   && ObjectUtils.equals(data, a.data);
  824           }
  825       }
  826   }

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