001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc;
012:
013: import com.versant.core.common.Debug;
014: import com.versant.core.metadata.FetchGroup;
015: import com.versant.core.metadata.FetchGroupField;
016: import com.versant.core.metadata.FieldMetaData;
017:
018: import java.util.ArrayList;
019: import java.util.List;
020:
021: import com.versant.core.common.BindingSupportImpl;
022: import com.versant.core.jdbc.metadata.JdbcClass;
023: import com.versant.core.jdbc.metadata.JdbcFetchGroup;
024:
025: /**
026: * This is a tree like data structure that is created with sql generation.
027: * The aim of this structure is to help with the reading rs that is obtained from
028: * the sql.
029: */
030: public class FgDs {
031:
032: public static String INCLUDING_SUBCLASSES = "INCLUDING_SUBCLASSES";
033: public static String INCLUDING_SUBCLASSES_OUTER = "INCLUDING_SUBCLASSES_OUTER";
034: public static String EXCLUDING_SUBCLASSES = "EXCLUDING_SUBCLASSES";
035: public static String EXCLUDING_SUBCLASSES_OUTER = "EXCLUDING_SUBCLASSES_OUTER";
036:
037: public JoinStructure valueJs;
038: public JoinStructure keyJs;
039: /**
040: * If this is the root then the owner will be null.
041: */
042: public FgDs owner;
043: /**
044: * This is the fetchGroup that this ds represents
045: */
046: public FetchGroup fg;
047: /**
048: * This is a array that is created for performance. It is created in updateCounts.
049: */
050: private FgDs[] sameTableFgDsArray;
051: /**
052: * This is the fetchGroups that were added as result of fg.
053: */
054: private List sameTableFgDsCol;
055: /**
056: * This is a list of fetch groups as added by reference navigation.
057: */
058: private List refFgDsCol;
059: /**
060: * This is the amount to skip in the rs. This encapsulates all of its children
061: * as well.
062: */
063: public int columnSkipCount;
064: private boolean clsIdAdded;
065:
066: public String name;
067:
068: private boolean finished;
069:
070: private JoinStructure rootValueJoinStruct;
071: public FieldMetaData refFmd;
072:
073: /**
074: * Cache sql strings to retrieve the fg for a getState call.
075: */
076: private String sql;
077: private String sqlForUpdate;
078: private boolean refIdFieldsAdded;
079:
080: private int opts;
081:
082: public FgDs(FgDs owner, FetchGroup fg, String name, int opts) {
083: this .name = name;
084: this .owner = owner;
085: this .fg = fg;
086: columnSkipCount = fg.jdbcTotalCols;
087:
088: sameTableFgDsCol = new ArrayList();
089: refFgDsCol = new ArrayList();
090: this .opts = opts;
091: }
092:
093: public int getOpts() {
094: return opts;
095: }
096:
097: public String getSql(boolean forUpdate) {
098: if (forUpdate)
099: return sqlForUpdate;
100: return sql;
101: }
102:
103: public void setSql(String sql, boolean forUpdate) {
104: if (forUpdate) {
105: sqlForUpdate = sql;
106: } else {
107: this .sql = sql;
108: }
109: }
110:
111: public String toString() {
112: return this .getClass().getName() + "@"
113: + System.identityHashCode(this ) + " opts: " + opts;
114: }
115:
116: public boolean isJoinOk() {
117: if (owner == null) {
118: return (opts & JdbcFetchGroup.OPT_START_OUTER) == 0;
119: } else {
120: return owner.isJoinOk();
121: }
122: }
123:
124: public boolean isOuter() {
125: return (opts & JdbcFetchGroup.OPT_START_OUTER) != 0;
126: }
127:
128: public boolean isIncludingSubs() {
129: return (opts & JdbcFetchGroup.OPT_INC_SUBS) != 0;
130: }
131:
132: public JoinStructure getJoinStruct() {
133: if (Debug.DEBUG) {
134: if (owner != null) {
135: throw BindingSupportImpl.getInstance().internal(
136: "This may only be called on the root");
137: }
138: }
139: if (rootValueJoinStruct == null) {
140: rootValueJoinStruct = new JoinStructure(fg);
141: }
142: return rootValueJoinStruct;
143: }
144:
145: public void addRefIdFields() {
146: if (finished) {
147: throw BindingSupportImpl.getInstance().internal(
148: "The FgDs is already finished");
149: }
150: if (refIdFieldsAdded) {
151: throw BindingSupportImpl.getInstance().internal(
152: "The refIdFields is already added");
153: }
154: refIdFieldsAdded = true;
155: columnSkipCount += ((JdbcClass) fg.classMetaData.storeClass).table.pk.length;
156: }
157:
158: public boolean isRefIdFieldsAdded() {
159: return refIdFieldsAdded;
160: }
161:
162: /**
163: * Notify that a classId col was added.
164: */
165: public void addClsIdCount() {
166: if (finished) {
167: throw BindingSupportImpl.getInstance().internal(
168: "The FgDs is already finished");
169: }
170: if (clsIdAdded) {
171: throw BindingSupportImpl.getInstance().internal(
172: "ClsId already added");
173: }
174: clsIdAdded = true;
175: columnSkipCount++;
176: }
177:
178: public void addClsIdCount(int amount) {
179: if (finished) {
180: throw BindingSupportImpl.getInstance().internal(
181: "The FgDs is already finished");
182: }
183: if (clsIdAdded) {
184: throw BindingSupportImpl.getInstance().internal(
185: "ClsId already added");
186: }
187: clsIdAdded = true;
188: columnSkipCount += amount;
189: }
190:
191: public void addSameTable(FgDs sameTableFgDs) {
192: if (finished) {
193: throw BindingSupportImpl.getInstance().internal(
194: "The FgDs is already finished");
195: }
196: sameTableFgDsCol.add(sameTableFgDs);
197: }
198:
199: /**
200: * This is called to finish the FgDs. After this the structure is immutable.
201: */
202: public void updateCounts() {
203: if (finished) {
204: throw BindingSupportImpl.getInstance().internal(
205: "The FgDs is already finished");
206: }
207: finished = true;
208: for (int i = 0; i < sameTableFgDsCol.size(); i++) {
209: FgDs fgDs = (FgDs) sameTableFgDsCol.get(i);
210: fgDs.updateCounts();
211: columnSkipCount += fgDs.columnSkipCount;
212: }
213:
214: for (int i = 0; i < refFgDsCol.size(); i++) {
215: FgDs fgDs = (FgDs) refFgDsCol.get(i);
216: fgDs.updateCounts();
217: columnSkipCount += fgDs.columnSkipCount;
218: }
219:
220: sameTableFgDsArray = new FgDs[sameTableFgDsCol.size()];
221: sameTableFgDsCol.toArray(sameTableFgDsArray);
222: sameTableFgDsCol = null;
223: if (owner == null) {
224: ((JdbcFetchGroup) fg.storeFetchGroup).setFgDs(this );
225: }
226: if (rootValueJoinStruct != null)
227: rootValueJoinStruct.finish();
228: }
229:
230: public void addReference(FgDs refFgDs, FieldMetaData aFmd) {
231: if (finished) {
232: throw BindingSupportImpl.getInstance().internal(
233: "The FgDs is already finished");
234: }
235: refFgDsCol.add(refFgDs);
236: refFgDs.refFmd = aFmd;
237: }
238:
239: public boolean isEmpty() {
240: return refFgDsCol.isEmpty();
241: }
242:
243: /**
244: * This returns Ref fg's
245: *
246: * @param index
247: * @return
248: */
249: public FgDs get(int index) {
250: if (index >= refFgDsCol.size()) {
251: return null;
252: }
253: return (FgDs) refFgDsCol.get(index);
254: }
255:
256: public void dump(String indent) {
257: if (!Debug.DEBUG)
258: return;
259: System.out.println(indent + "fg name = " + fg + "@"
260: + System.identityHashCode(this ) + " class "
261: + fg.classMetaData.cls.getName() + " finished = "
262: + finished);
263: System.out.println(indent + "name = " + name);
264: System.out.println(indent + "TotcolCount " + columnSkipCount
265: + " ownColCount " + fg.jdbcTotalCols);
266: StringBuffer sb = new StringBuffer();
267: for (int i = 0; i < fg.fields.length; i++) {
268: FetchGroupField field = fg.fields[i];
269: sb.append(field.fmd.name + ", ");
270: }
271: System.out.println(indent + "fg fields = " + sb.toString());
272: System.out.println(indent + "refIdFieldsAdded = "
273: + refIdFieldsAdded);
274: System.out.println(indent + "listing children-----");
275: if (sameTableFgDsCol != null) {
276: System.out.println(indent + sameTableFgDsCol.size()
277: + " same table fgs ----");
278: for (int i = 0; i < sameTableFgDsCol.size(); i++) {
279: FgDs ds = (FgDs) sameTableFgDsCol.get(i);
280: ds.dump(indent + " ");
281: }
282: } else {
283: System.out.println(indent + sameTableFgDsArray.length
284: + " same table fgs ----");
285: for (int i = 0; i < sameTableFgDsArray.length; i++) {
286: FgDs fgDs = sameTableFgDsArray[i];
287: fgDs.dump(indent + " ");
288: }
289: }
290: System.out
291: .println(indent + refFgDsCol.size() + " ref fgs ----");
292: for (int i = 0; i < refFgDsCol.size(); i++) {
293: com.versant.core.jdbc.FgDs fgDs = (com.versant.core.jdbc.FgDs) refFgDsCol
294: .get(i);
295: fgDs.dump(indent + " ");
296: }
297: System.out
298: .println(indent + "---------------------------------");
299: }
300:
301: public int getChildrenColumnCount() {
302: return columnSkipCount - fg.jdbcTotalCols
303: - (clsIdAdded ? 1 : 0);
304: }
305:
306: public FgDs[] getSameTableFgDss() {
307: if (!finished) {
308: throw BindingSupportImpl.getInstance().internal(
309: "This fgds was never finised");
310: }
311: return sameTableFgDsArray;
312: }
313:
314: public int getAmountOfRefFgDs() {
315: return refFgDsCol.size();
316: }
317:
318: public FgDs getFirtsFor(FetchGroup afg) {
319: if (!finished) {
320: throw BindingSupportImpl.getInstance().internal(
321: "This fgds was never finised");
322: }
323: for (int i = 0; i < sameTableFgDsCol.size(); i++) {
324: FgDs fgDs = (FgDs) sameTableFgDsCol.get(i);
325: if (fgDs.fg == afg)
326: return fgDs;
327: }
328: return null;
329: }
330:
331: public boolean isFinished() {
332: return finished;
333: }
334:
335: /**
336: * This will return a List of pass2 FetchGroupFields.
337: */
338: public List getPass2FetchGroupFields() {
339: ArrayList result = new ArrayList();
340: addPass2Fields(result, fg);
341:
342: if (sameTableFgDsArray != null) {
343: for (int i = 0; i < sameTableFgDsArray.length; i++) {
344: addPass2Fields(result, sameTableFgDsArray[i].fg);
345: }
346: }
347: return result;
348: }
349:
350: private static void addPass2Fields(ArrayList result, FetchGroup aFg) {
351: FetchGroupField[] fields = aFg.fields;
352: for (int i = 0; i < fields.length; i++) {
353: FetchGroupField field = fields[i];
354: if (field.fmd.secondaryField) {
355: result.add(field);
356: }
357: }
358: }
359:
360: public List getRefFgs() {
361: return refFgDsCol;
362: }
363: }
|