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.meta;
20
21 import java.sql.SQLException;
22
23 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
24 import org.apache.openjpa.jdbc.kernel.JDBCStore;
25 import org.apache.openjpa.jdbc.meta.strats.NoneFieldStrategy;
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.Index;
30 import org.apache.openjpa.jdbc.schema.Table;
31 import org.apache.openjpa.jdbc.schema.Unique;
32 import org.apache.openjpa.jdbc.sql.Joins;
33 import org.apache.openjpa.jdbc.sql.Result;
34 import org.apache.openjpa.jdbc.sql.Row;
35 import org.apache.openjpa.jdbc.sql.RowManager;
36 import org.apache.openjpa.jdbc.sql.SQLBuffer;
37 import org.apache.openjpa.jdbc.sql.Select;
38 import org.apache.openjpa.jdbc.sql.SelectExecutor;
39 import org.apache.openjpa.kernel.FetchConfiguration;
40 import org.apache.openjpa.kernel.OpenJPAStateManager;
41 import org.apache.openjpa.lib.log.Log;
42 import org.apache.openjpa.lib.util.Localizer;
43 import org.apache.openjpa.meta.FieldMetaData;
44 import org.apache.openjpa.meta.JavaTypes;
45 import org.apache.openjpa.util.InternalException;
46 import org.apache.openjpa.util.MetaDataException;
47
48 /**
49 * Specialization of metadata for relational databases.
50 *
51 * @author Abe White
52 */
53 public class FieldMapping
54 extends FieldMetaData
55 implements ValueMapping, FieldStrategy {
56
57 private static final Localizer _loc = Localizer.forPackage
58 (FieldMapping.class);
59
60 private final ValueMapping _val;
61 private final ValueMapping _key;
62 private final ValueMapping _elem;
63 private final FieldMappingInfo _info;
64 private final JDBCColumnOrder _orderCol = new JDBCColumnOrder();
65 private FieldStrategy _strategy = null;
66
67 private ForeignKey _fk = null;
68 private ColumnIO _io = null;
69 private Unique _unq = null;
70 private Index _idx = null;
71 private boolean _outer = false;
72 private int _fetchMode = Integer.MAX_VALUE;
73
74 /**
75 * Constructor.
76 */
77 public FieldMapping(String name, Class type, ClassMapping owner) {
78 super(name, type, owner);
79 _info = owner.getMappingRepository().newMappingInfo(this);
80 _val = (ValueMapping) getValue();
81 _key = (ValueMapping) getKey();
82 _elem = (ValueMapping) getElement();
83
84 setUsesIntermediate(false);
85 setUsesImplData(Boolean.FALSE);
86 }
87
88 ///////
89 // ORM
90 ///////
91
92 /**
93 * Raw mapping data about field's join to parent table, as well as
94 * miscellaneous specialized columns like order column.
95 */
96 public FieldMappingInfo getMappingInfo() {
97 return _info;
98 }
99
100 /**
101 * The strategy used to map this mapping.
102 */
103 public FieldStrategy getStrategy() {
104 return _strategy;
105 }
106
107 /**
108 * The strategy used to map this mapping. The <code>adapt</code>
109 * parameter determines whether to adapt when mapping the strategy;
110 * use null if the strategy should not be mapped.
111 */
112 public void setStrategy(FieldStrategy strategy, Boolean adapt) {
113 // set strategy first so we can access it during mapping
114 FieldStrategy orig = _strategy;
115 _strategy = strategy;
116 if (strategy != null) {
117 try {
118 strategy.setFieldMapping(this);
119 if (adapt != null)
120 strategy.map(adapt.booleanValue());
121 } catch (RuntimeException re) {
122 // reset strategy
123 _strategy = orig;
124 throw re;
125 }
126
127 // if set to unmapped, clear defined field cache in parent
128 if (!isMapped())
129 getDefiningMapping().clearDefinedFieldCache();
130 }
131 }
132
133 /**
134 * The mapping's primary table.
135 */
136 public Table getTable() {
137 if (_fk != null)
138 return _fk.getTable();
139 if (_val.getForeignKey() != null)
140 return _val.getForeignKey().getTable();
141 return getDefiningMapping().getTable();
142 }
143
144 /**
145 * I/O information on the join columns.
146 */
147 public ColumnIO getJoinColumnIO() {
148 return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
149 }
150
151 /**
152 * I/O information on the join columns.
153 */
154 public void setJoinColumnIO(ColumnIO io) {
155 _io = io;
156 }
157
158 /**
159 * Foreign key linking the field table to the class' primary table.
160 */
161 public ForeignKey getJoinForeignKey() {
162 return _fk;
163 }
164
165 /**
166 * Foreign key linking the field table to the class' primary table.
167 */
168 public void setJoinForeignKey(ForeignKey fk) {
169 _fk = fk;
170 }
171
172 /**
173 * Unique constraint on join foreign key columns.
174 */
175 public Unique getJoinUnique() {
176 return _unq;
177 }
178
179 /**
180 * Unique constraint on join foreign key columns.
181 */
182 public void setJoinUnique(Unique unq) {
183 _unq = unq;
184 }
185
186 /**
187 * Index on join foreign key columns.
188 */
189 public Index getJoinIndex() {
190 return _idx;
191 }
192
193 /**
194 * Index on join foreign key columns.
195 */
196 public void setJoinIndex(Index idx) {
197 _idx = idx;
198 }
199
200 /**
201 * Whether to use an outer join from the class' primary table.
202 */
203 public boolean isJoinOuter() {
204 return _outer;
205 }
206
207 /**
208 * Whether to use an outer join from the class' primary table.
209 */
210 public void setJoinOuter(boolean outer) {
211 _outer = outer;
212 }
213
214 /**
215 * Field order column, if any.
216 */
217 public Column getOrderColumn() {
218 return _orderCol.getColumn();
219 }
220
221 /**
222 * Field order column, if any.
223 */
224 public void setOrderColumn(Column order) {
225 _orderCol.setColumn(order);
226 }
227
228 /**
229 * I/O information for order column.
230 */
231 public ColumnIO getOrderColumnIO() {
232 return _orderCol.getColumnIO();
233 }
234
235 /**
236 * I/O information for order column.
237 */
238 public void setOrderColumnIO(ColumnIO io) {
239 _orderCol.setColumnIO(io);
240 }
241
242 /**
243 * Increment the reference count of used schema components.
244 */
245 public void refSchemaComponents() {
246 if (_fk != null) {
247 _fk.ref();
248 _fk.refColumns();
249 }
250 if (_orderCol.getColumn() != null)
251 _orderCol.getColumn().ref();
252 _val.refSchemaComponents();
253 _key.refSchemaComponents();
254 _elem.refSchemaComponents();
255 }
256
257 /**
258 * Clear mapping information, including strategy.
259 */
260 public void clearMapping() {
261 _strategy = null;
262 _fk = null;
263 _unq = null;
264 _idx = null;
265 _outer = false;
266 _orderCol.setColumn(null);
267 _val.clearMapping();
268 _key.clearMapping();
269 _elem.clearMapping();
270 _info.clear();
271 setResolve(MODE_MAPPING, false);
272 }
273
274 /**
275 * Update {@link MappingInfo} with our current mapping information.
276 */
277 public void syncMappingInfo() {
278 if (isVersion()) {
279 // we rely on the fact that the version will setup our mapping
280 // info correctly when it is synced
281 } else if (getMappedByMapping() != null) {
282 _info.clear();
283 _val.getValueInfo().clear();
284 _key.getValueInfo().clear();
285 _elem.getValueInfo().clear();
286
287 FieldMapping mapped = getMappedByMapping();
288 _info.syncStrategy(this);
289 if (_orderCol.getColumn() != null
290 && mapped.getOrderColumn() == null)
291 _info.syncOrderColumn(this);
292 _val.getValueInfo().setUseClassCriteria
293 (_val.getUseClassCriteria());
294 _key.getValueInfo().setUseClassCriteria
295 (_key.getUseClassCriteria());
296 _elem.getValueInfo().setUseClassCriteria
297 (_elem.getUseClassCriteria());
298 } else {
299 _info.syncWith(this);
300 _val.syncMappingInfo();
301 _key.syncMappingInfo();
302 _elem.syncMappingInfo();
303 }
304 }
305
306 /**
307 * Returns true if field class does not use the "none" strategy (including
308 * if it has a null strategy, and therefore is probably in the process of
309 * being mapped).
310 */
311 public boolean isMapped() {
312 return _strategy != NoneFieldStrategy.getInstance();
313 }
314
315 //////////////////////
316 // MetaData interface
317 //////////////////////
318
319 /**
320 * The eager fetch mode, as one of the eager constants in
321 * {@link JDBCFetchConfiguration}.
322 */
323 public int getEagerFetchMode() {
324 if (_fetchMode == Integer.MAX_VALUE)
325 _fetchMode = FetchConfiguration.DEFAULT;
326 return _fetchMode;
327 }
328
329 /**
330 * The eager fetch mode, as one of the eager constants in
331 * {@link JDBCFetchConfiguration}.
332 */
333 public void setEagerFetchMode(int mode) {
334 _fetchMode = mode;
335 }
336
337 /**
338 * Convenience method to perform cast from
339 * {@link FieldMetaData#getRepository}
340 */
341 public MappingRepository getMappingRepository() {
342 return (MappingRepository) getRepository();
343 }
344
345 /**
346 * Convenience method to perform cast from
347 * {@link FieldMetaData#getDefiningMetaData}
348 */
349 public ClassMapping getDefiningMapping() {
350 return (ClassMapping) getDefiningMetaData();
351 }
352
353 /**
354 * Convenience method to perform cast from
355 * {@link FieldMetaData#getDeclaringMetaData}
356 */
357 public ClassMapping getDeclaringMapping() {
358 return (ClassMapping) getDeclaringMetaData();
359 }
360
361 /**
362 * Convenience method to perform cast from {@link FieldMetaData#getKey}
363 */
364 public ValueMapping getKeyMapping() {
365 return _key;
366 }
367
368 /**
369 * Convenience method to perform cast from {@link FieldMetaData#getElement}
370 */
371 public ValueMapping getElementMapping() {
372 return _elem;
373 }
374
375 /**
376 * Convenience method to perform cast from {@link FieldMetaData#getValue}
377 */
378 public ValueMapping getValueMapping() {
379 return (ValueMapping) getValue();
380 }
381
382 /**
383 * Convenience method to perform cast from
384 * {@link FieldMetaData#getMappedByMetaData}
385 */
386 public FieldMapping getMappedByMapping() {
387 return (FieldMapping) getMappedByMetaData();
388 }
389
390 /**
391 * Convenience method to perform cast from
392 * {@link FieldMetaData#getInverseMetaDatas}
393 */
394 public FieldMapping[] getInverseMappings() {
395 return (FieldMapping[]) getInverseMetaDatas();
396 }
397
398 public boolean resolve(int mode) {
399 int cur = getResolve();
400 if (super.resolve(mode))
401 return true;
402 if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
403 resolveMapping();
404 if ((mode & MODE_MAPPING_INIT) != 0 && (cur & MODE_MAPPING_INIT) == 0)
405 initializeMapping();
406 return false;
407 }
408
409 /**
410 * Resolve the mapping information for this field.
411 */
412 private void resolveMapping() {
413 MappingRepository repos = getMappingRepository();
414 if (repos.getMappingDefaults().defaultMissingInfo()) {
415 // copy embedded template mapping info
416 ClassMapping cls = getDefiningMapping();
417 if (cls.getEmbeddingMapping() != null) {
418 ClassMapping orig = repos.getMapping(cls.getDescribedType(),
419 cls.getEnvClassLoader(), true);
420 FieldMapping tmplate = orig.getFieldMapping(getName());
421 if (tmplate != null)
422 copyMappingInfo(tmplate);
423 }
424 // copy superclass field info
425 else if (cls.isMapped() && cls.getPCSuperclass() != null
426 && cls.getDescribedType() != getDeclaringType()) {
427 FieldMapping sup = cls.getPCSuperclassMapping().
428 getFieldMapping(getName());
429 if (sup != null)
430 copyMappingInfo(sup);
431 }
432 }
433
434 if (_strategy == null) {
435 if (isVersion())
436 _strategy = NoneFieldStrategy.getInstance();
437 else
438 repos.getStrategyInstaller().installStrategy(this);
439 }
440 Log log = getRepository().getLog();
441 if (log.isTraceEnabled())
442 log.trace(_loc.get("field-strategy", getName(),
443 _strategy.getAlias()));
444
445 // mark mapped columns
446 if (_orderCol.getColumn() != null) {
447 if (getOrderColumnIO().isInsertable(0, false))
448 _orderCol.getColumn().setFlag(Column.FLAG_DIRECT_INSERT, true);
449 if (getOrderColumnIO().isUpdatable(0, false))
450 _orderCol.getColumn().setFlag(Column.FLAG_DIRECT_UPDATE, true);
451 }
452 if (_fk != null) {
453 Column[] cols = _fk.getColumns();
454 ColumnIO io = getJoinColumnIO();
455 for (int i = 0; i < cols.length; i++) {
456 if (io.isInsertable(i, false))
457 cols[i].setFlag(Column.FLAG_FK_INSERT, true);
458 if (io.isUpdatable(i, false))
459 cols[i].setFlag(Column.FLAG_FK_UPDATE, true);
460 }
461 }
462
463 _val.resolve(MODE_MAPPING);
464 _key.resolve(MODE_MAPPING);
465 _elem.resolve(MODE_MAPPING);
466 }
467
468 /**
469 * Copy mapping info from the given instance to this one.
470 */
471 public void copyMappingInfo(FieldMapping fm) {
472 setMappedBy(fm.getMappedBy());
473 _info.copy(fm.getMappingInfo());
474 _val.copyMappingInfo(fm.getValueMapping());
475 _key.copyMappingInfo(fm.getKeyMapping());
476 _elem.copyMappingInfo(fm.getElementMapping());
477 }
478
479 /**
480 * Prepare mapping for runtime use.
481 */
482 private void initializeMapping() {
483 _val.resolve(MODE_MAPPING_INIT);
484 _key.resolve(MODE_MAPPING_INIT);
485 _val.resolve(MODE_MAPPING_INIT);
486 if (_strategy != null)
487 _strategy.initialize();
488 }
489
490 public void copy(FieldMetaData fmd) {
491 super.copy(fmd);
492 if (_fetchMode == Integer.MAX_VALUE)
493 _fetchMode = ((FieldMapping) fmd).getEagerFetchMode();
494 }
495
496 protected boolean validateDataStoreExtensionPrefix(String prefix) {
497 return "jdbc-".equals(prefix);
498 }
499
500 ////////////////////////////////
501 // FieldStrategy implementation
502 ////////////////////////////////
503
504 public String getAlias() {
505 return assertStrategy().getAlias();
506 }
507
508 public void map(boolean adapt) {
509 assertStrategy().map(adapt);
510 }
511
512 /**
513 * Map this field to its table, optionally requiring that it be
514 * in another table. Utility method for use by mapping strategies.
515 */
516 public void mapJoin(boolean adapt, boolean joinRequired) {
517 Table table = _info.getTable(this, joinRequired, adapt);
518
519 if(table != null && table.equals(getDefiningMapping().getTable())) {
520 // Don't create a join if the field's table is the same as the
521 // class's table.
522 table = null;
523 }
524
525 ForeignKey join = null;
526 if (table != null)
527 join = _info.getJoin(this, table, adapt);
528 if (join == null && joinRequired)
529 throw new MetaDataException(_loc.get("join-required", this));
530
531 if (join == null) {
532 _info.assertNoJoin(this, true);
533 _info.assertNoForeignKey(this, !adapt);
534 _info.assertNoUnique(this, !adapt);
535 _info.assertNoIndex(this, !adapt);
536 } else {
537 _fk = join;
538 _io = _info.getColumnIO();
539 _outer = _info.isJoinOuter();
540 _unq = _info.getJoinUnique(this, false, adapt);
541 _idx = _info.getJoinIndex(this, adapt);
542 }
543 }
544
545 /**
546 * Maps the primary key on the secondary table for this field, if the
547 * user's defaults create one. This must be called after
548 * this field is mapped so that it's table has its columns set.
549 */
550 public void mapPrimaryKey(boolean adapt) {
551 if (adapt && _fk != null && _fk.getTable().getPrimaryKey() == null)
552 getMappingRepository().getMappingDefaults().
553 installPrimaryKey(this, _fk.getTable());
554 }
555
556 public void initialize() {
557 assertStrategy().initialize();
558 }
559
560 public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
561 throws SQLException {
562 assertStrategy().insert(sm, store, rm);
563 }
564
565 public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
566 throws SQLException {
567 assertStrategy().update(sm, store, rm);
568 }
569
570 public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
571 throws SQLException {
572 assertStrategy().delete(sm, store, rm);
573 }
574
575 /**
576 * Delete the row for this object if the reference foreign key exists.
577 * Utility method for use by mapping strategies.
578 */
579 public void deleteRow(OpenJPAStateManager sm, JDBCStore store,
580 RowManager rm)
581 throws SQLException {
582 if (_fk != null) {
583 Row row = rm.getRow(getTable(), Row.ACTION_DELETE, sm, true);
584 row.whereForeignKey(_fk, sm);
585 }
586 }
587
588 /**
589 * Return the row to use for this field. This method is meant only for
590 * single-value fields that might reside in a table that is joined to
591 * the primary table through the join foreign key. It is not
592 * meant for multi-valued fields like collections and maps. The method
593 * checks whether we're using an outer join and if so it deletes the
594 * field's previous value, then if the field is non-null returns an insert
595 * row for the new value. The join foreign key will already be set on
596 * the returned row; mapping strategies just need to set their own values.
597 * Utility method for use by mapping strategies.
598 */
599 public Row getRow(OpenJPAStateManager sm, JDBCStore store, RowManager rm,
600 int action)
601 throws SQLException {
602 Row row = null;
603 boolean newOuterRow = false;
604 if (_fk != null && _outer && action != Row.ACTION_DELETE) {
605 // if updating with outer join, delete old value first, then insert;
606 // we can't just update b/c the row might not exist
607 if (action == Row.ACTION_UPDATE) {
608 // maybe some other field already is updating?
609 row = rm.getRow(getTable(), Row.ACTION_UPDATE, sm, false);
610 if (row == null) {
611 Row del = rm.getRow(getTable(), Row.ACTION_DELETE, sm,
612 true);
613 del.whereForeignKey(_fk, sm);
614 }
615 } else
616 row = rm.getRow(getTable(), Row.ACTION_INSERT, sm, false);
617
618 // only update/insert if the row exists already or the value is
619 // not null/default
620 if (row == null && !isNullValue(sm)) {
621 row = rm.getRow(getTable(), Row.ACTION_INSERT, sm, true);
622 newOuterRow = true;
623 }
624 } else
625 row = rm.getRow(getTable(), action, sm, true);
626
627 // setup fk
628 if (row != null && _fk != null) {
629 if (row.getAction() == Row.ACTION_INSERT)
630 row.setForeignKey(_fk, _io, sm);
631 else
632 row.whereForeignKey(_fk, sm);
633
634 // if this is a new outer joined row, mark it invalid until
635 // some mapping actually sets information on it
636 if (newOuterRow)
637 row.setValid(false);
638 }
639 return row;
640 }
641
642 /**
643 * Return true if this field is null/default in the given instance.
644 */
645 private boolean isNullValue(OpenJPAStateManager sm) {
646 switch (getTypeCode()) {
647 case JavaTypes.BOOLEAN:
648 return !sm.fetchBoolean(getIndex());
649 case JavaTypes.BYTE:
650 return sm.fetchByte(getIndex()) == 0;
651 case JavaTypes.CHAR:
652 return sm.fetchChar(getIndex()) == 0;
653 case JavaTypes.DOUBLE:
654 return sm.fetchDouble(getIndex()) == 0;
655 case JavaTypes.FLOAT:
656 return sm.fetchFloat(getIndex()) == 0;
657 case JavaTypes.INT:
658 return sm.fetchInt(getIndex()) == 0;
659 case JavaTypes.LONG:
660 return sm.fetchLong(getIndex()) == 0;
661 case JavaTypes.SHORT:
662 return sm.fetchShort(getIndex()) == 0;
663 case JavaTypes.STRING:
664 return sm.fetchString(getIndex()) == null;
665 default:
666 return sm.fetchObject(getIndex()) == null;
667 }
668 }
669
670 public Boolean isCustomInsert(OpenJPAStateManager sm, JDBCStore store) {
671 return assertStrategy().isCustomInsert(sm, store);
672 }
673
674 public Boolean isCustomUpdate(OpenJPAStateManager sm, JDBCStore store) {
675 return assertStrategy().isCustomUpdate(sm, store);
676 }
677
678 public Boolean isCustomDelete(OpenJPAStateManager sm, JDBCStore store) {
679 return assertStrategy().isCustomDelete(sm, store);
680 }
681
682 public void customInsert(OpenJPAStateManager sm, JDBCStore store)
683 throws SQLException {
684 assertStrategy().customInsert(sm, store);
685 }
686
687 public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
688 throws SQLException {
689 assertStrategy().customUpdate(sm, store);
690 }
691
692 public void customDelete(OpenJPAStateManager sm, JDBCStore store)
693 throws SQLException {
694 assertStrategy().customDelete(sm, store);
695 }
696
697 public void setFieldMapping(FieldMapping owner) {
698 assertStrategy().setFieldMapping(owner);
699 }
700
701 public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
702 JDBCStore store, JDBCFetchConfiguration fetch) {
703 return assertStrategy().supportsSelect(sel, type, sm, store, fetch);
704 }
705
706 public void selectEagerParallel(SelectExecutor sel, OpenJPAStateManager sm,
707 JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
708 assertStrategy().selectEagerParallel(sel, sm, store, fetch, eagerMode);
709 }
710
711 public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
712 JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
713 assertStrategy().selectEagerJoin(sel, sm, store, fetch, eagerMode);
714 }
715
716 public boolean isEagerSelectToMany() {
717 return assertStrategy().isEagerSelectToMany();
718 }
719
720 public int select(Select sel, OpenJPAStateManager sm, JDBCStore store,
721 JDBCFetchConfiguration fetch, int eagerMode) {
722 return assertStrategy().select(sel, sm, store, fetch, eagerMode);
723 }
724
725 /**
726 * Return any joins needed to get from the primary table to this table.
727 */
728 public Joins join(Select sel) {
729 if (_fk == null)
730 return null;
731
732 Joins joins = sel.newJoins();
733 if (_outer)
734 return joins.outerJoin(_fk, true, false);
735 return joins.join(_fk, true, false);
736 }
737
738 /**
739 * Add a <code>wherePrimaryKey</code> or <code>whereForeignKey</code>
740 * condition to the given select, depending on whether we have a join
741 * foreign key.
742 */
743 public void wherePrimaryKey(Select sel, OpenJPAStateManager sm,
744 JDBCStore store) {
745 if (_fk != null)
746 sel.whereForeignKey(_fk, sm.getObjectId(), getDefiningMapping(),
747 store);
748 else
749 sel.wherePrimaryKey(sm.getObjectId(), getDefiningMapping(),
750 store);
751 }
752
753 /**
754 * Add ordering to the given select for all non-relation order values,
755 * including the synthetic order column, if any.
756 *
757 * @param elem the related type we're fetching, or null
758 * @param joins the joins to this field's table
759 */
760 public void orderLocal(Select sel, ClassMapping elem, Joins joins) {
761 _orderCol.order(sel, elem, joins);
762 JDBCOrder[] orders = (JDBCOrder[]) getOrders();
763 for (int i = 0; i < orders.length; i++)
764 if (!orders[i].isInRelation())
765 orders[i].order(sel, elem, joins);
766 }
767
768 /**
769 * Add ordering to the given select for all relation-based values.
770 *
771 * @param elem the related type we're fetching
772 * @param joins the joins across the relation
773 */
774 public void orderRelation(Select sel, ClassMapping elem, Joins joins) {
775 JDBCOrder[] orders = (JDBCOrder[]) getOrders();
776 for (int i = 0; i < orders.length; i++)
777 if (orders[i].isInRelation())
778 orders[i].order(sel, elem, joins);
779 }
780
781 public Object loadEagerParallel(OpenJPAStateManager sm, JDBCStore store,
782 JDBCFetchConfiguration fetch, Object res)
783 throws SQLException {
784 return assertStrategy().loadEagerParallel(sm, store, fetch, res);
785 }
786
787 public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
788 JDBCFetchConfiguration fetch, Result res)
789 throws SQLException {
790 assertStrategy().loadEagerJoin(sm, store, fetch, res);
791 }
792
793 public void load(OpenJPAStateManager sm, JDBCStore store,
794 JDBCFetchConfiguration fetch, Result res)
795 throws SQLException {
796 assertStrategy().load(sm, store, fetch, res);
797 }
798
799 public void load(OpenJPAStateManager sm, JDBCStore store,
800 JDBCFetchConfiguration fetch)
801 throws SQLException {
802 assertStrategy().load(sm, store, fetch);
803 }
804
805 public Object toDataStoreValue(Object val, JDBCStore store) {
806 return assertStrategy().toDataStoreValue(val, store);
807 }
808
809 public Object toKeyDataStoreValue(Object val, JDBCStore store) {
810 return assertStrategy().toKeyDataStoreValue(val, store);
811 }
812
813 public void appendIsEmpty(SQLBuffer sql, Select sel, Joins joins) {
814 assertStrategy().appendIsEmpty(sql, sel, joins);
815 }
816
817 public void appendIsNotEmpty(SQLBuffer sql, Select sel, Joins joins) {
818 assertStrategy().appendIsNotEmpty(sql, sel, joins);
819 }
820
821 public void appendIsNull(SQLBuffer sql, Select sel, Joins joins) {
822 assertStrategy().appendIsNull(sql, sel, joins);
823 }
824
825 public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) {
826 assertStrategy().appendIsNotNull(sql, sel, joins);
827 }
828
829 public void appendSize(SQLBuffer sql, Select sel, Joins joins) {
830 assertStrategy().appendSize(sql, sel, joins);
831 }
832
833 public Joins join(Joins joins, boolean forceOuter) {
834 return assertStrategy().join(joins, forceOuter);
835 }
836
837 public Joins joinKey(Joins joins, boolean forceOuter) {
838 return assertStrategy().joinKey(joins, forceOuter);
839 }
840
841 public Joins joinRelation(Joins joins, boolean forceOuter,
842 boolean traverse) {
843 return assertStrategy().joinRelation(joins, forceOuter, traverse);
844 }
845
846 public Joins joinKeyRelation(Joins joins, boolean forceOuter,
847 boolean traverse) {
848 return assertStrategy().joinKeyRelation(joins, forceOuter, traverse);
849 }
850
851 /**
852 * Joins from the owning class' table to the table where this field lies
853 * using the join foreign key. Utility method for use by mapping strategies.
854 */
855 public Joins join(Joins joins, boolean forceOuter, boolean toMany) {
856 if (_fk == null)
857 return joins;
858 if (_outer || forceOuter)
859 return joins.outerJoin(_fk, true, toMany);
860 return joins.join(_fk, true, toMany);
861 }
862
863 public Object loadProjection(JDBCStore store, JDBCFetchConfiguration fetch,
864 Result res, Joins joins)
865 throws SQLException {
866 return assertStrategy().loadProjection(store, fetch, res, joins);
867 }
868
869 public Object loadKeyProjection(JDBCStore store,
870 JDBCFetchConfiguration fetch, Result res, Joins joins)
871 throws SQLException {
872 return assertStrategy()
873 .loadKeyProjection(store, fetch, res, joins);
874 }
875
876 public boolean isVersionable() {
877 return assertStrategy().isVersionable();
878 }
879
880 public void where(OpenJPAStateManager sm, JDBCStore store, RowManager rm,
881 Object prevValue)
882 throws SQLException {
883 assertStrategy().where(sm, store, rm, prevValue);
884 }
885
886 private FieldStrategy assertStrategy() {
887 if (_strategy == null)
888 throw new InternalException();
889 return _strategy;
890 }
891
892 ///////////////////////////////
893 // ValueMapping implementation
894 ///////////////////////////////
895
896 public ValueMappingInfo getValueInfo() {
897 return _val.getValueInfo();
898 }
899
900 public ValueHandler getHandler() {
901 return _val.getHandler();
902 }
903
904 public void setHandler(ValueHandler handler) {
905 _val.setHandler(handler);
906 }
907
908 public FieldMapping getFieldMapping() {
909 return this;
910 }
911
912 public ClassMapping getTypeMapping() {
913 return _val.getTypeMapping();
914 }
915
916 public ClassMapping getDeclaredTypeMapping() {
917 return _val.getDeclaredTypeMapping();
918 }
919
920 public ClassMapping getEmbeddedMapping() {
921 return _val.getEmbeddedMapping();
922 }
923
924 public FieldMapping getValueMappedByMapping() {
925 return _val.getValueMappedByMapping();
926 }
927
928 public Column[] getColumns() {
929 // pcl: 6 July 2007: this seems a bit hacky, but if the mapping is a
930 // version, it will have a NoneFieldMapping (since the version strategy
931 // for the class takes care of it's mapping), and NoneFieldStrategies
932 // do not have columns.
933 if (isVersion())
934 return getDeclaringMapping().getVersion().getColumns();
935 else
936 return _val.getColumns();
937 }
938
939 public void setColumns(Column[] cols) {
940 _val.setColumns(cols);
941 }
942
943 public ColumnIO getColumnIO() {
944 return _val.getColumnIO();
945 }
946
947 public void setColumnIO(ColumnIO io) {
948 _val.setColumnIO(io);
949 }
950
951 public ForeignKey getForeignKey() {
952 return _val.getForeignKey();
953 }
954
955 public ForeignKey getForeignKey(ClassMapping target) {
956 return _val.getForeignKey(target);
957 }
958
959 public void setForeignKey(ForeignKey fk) {
960 _val.setForeignKey(fk);
961 }
962
963 public int getJoinDirection() {
964 return _val.getJoinDirection();
965 }
966
967 public void setJoinDirection(int direction) {
968 _val.setJoinDirection(direction);
969 }
970
971 public void setForeignKey(Row row, OpenJPAStateManager sm)
972 throws SQLException {
973 _val.setForeignKey(row, sm);
974 }
975
976 public void whereForeignKey(Row row, OpenJPAStateManager sm)
977 throws SQLException {
978 _val.whereForeignKey(row, sm);
979 }
980
981 public ClassMapping[] getIndependentTypeMappings() {
982 return _val.getIndependentTypeMappings();
983 }
984
985 public int getSelectSubclasses() {
986 return _val.getSelectSubclasses();
987 }
988
989 public Unique getValueUnique() {
990 return _val.getValueUnique();
991 }
992
993 public void setValueUnique(Unique unq) {
994 _val.setValueUnique(unq);
995 }
996
997 public Index getValueIndex() {
998 return _val.getValueIndex();
999 }
1000
1001 public void setValueIndex(Index idx) {
1002 _val.setValueIndex(idx);
1003 }
1004
1005 public boolean getUseClassCriteria() {
1006 return _val.getUseClassCriteria();
1007 }
1008
1009 public void setUseClassCriteria(boolean criteria) {
1010 _val.setUseClassCriteria(criteria);
1011 }
1012
1013 public int getPolymorphic() {
1014 return _val.getPolymorphic();
1015 }
1016
1017 public void setPolymorphic(int poly) {
1018 _val.setPolymorphic(poly);
1019 }
1020
1021 public void mapConstraints(String name, boolean adapt) {
1022 _val.mapConstraints(name, adapt);
1023 }
1024
1025 public void copyMappingInfo(ValueMapping vm) {
1026 _val.copyMappingInfo(vm);
1027 }
1028 }