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.metadata;
012:
013: import com.versant.core.common.State;
014: import com.versant.core.metadata.ClassMetaData;
015: import com.versant.core.metadata.FetchGroupField;
016: import com.versant.core.metadata.parser.JdoElement;
017: import com.versant.core.metadata.parser.JdoExtension;
018: import com.versant.core.common.OID;
019: import com.versant.core.common.*;
020: import com.versant.core.server.StateContainer;
021: import com.versant.core.jdbc.*;
022: import com.versant.core.jdbc.sql.exp.SelectExp;
023: import com.versant.core.util.CharBuf;
024:
025: import java.io.PrintStream;
026: import java.sql.Connection;
027: import java.sql.ResultSet;
028: import java.sql.SQLException;
029: import java.sql.Statement;
030:
031: import com.versant.core.common.BindingSupportImpl;
032:
033: /**
034: * Base class for field that are Collections, Maps or arrays.
035: */
036: public abstract class JdbcCollectionField extends JdbcField {
037:
038: public static int STATUS_CLOSED = 1;
039: public static int STATUS_VALID_ROWS = 2;
040: public static int STATUS_DATA_ADDED = 4;
041:
042: public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
043: public static final OID[] EMPTY_OID_ARRAY = new OID[0];
044: public static final Object[] PRE_GEN_EMPTY_OBJECT_ARRAY = new Object[0];
045:
046: /**
047: * The column(s) holding primary key of the main table for our class.
048: * These could be in the link table or in the value PC class table.
049: */
050: public JdbcColumn[] ourPkColumns;
051: /**
052: * The column holding the sequence number for each value (null if the
053: * collection is not ordered).
054: */
055: public JdbcColumn sequenceColumn;
056:
057: public void dump(PrintStream out, String indent) {
058: super .dump(out, indent);
059: String is = indent + " ";
060: if (ourPkColumns == null) {
061: out.println(is + "ourPkColumns null");
062: } else {
063: for (int i = 0; i < ourPkColumns.length; i++) {
064: out.println(is + "ourPkColumns[" + i + "] "
065: + ourPkColumns[i]);
066: }
067: }
068: out.println(is + "sequenceColumn " + sequenceColumn);
069: }
070:
071: /**
072: * Complete the meta data for this collection. This must use info
073: * already supplied in the .jdo file and add anything else needed.
074: */
075: public void processMetaData(JdoElement context,
076: JdbcMetaDataBuilder mdb, boolean quiet) {
077: fmd.primaryField = false;
078: fmd.secondaryField = true;
079:
080: // make sure there are no jdbc-XXX extensions on the field element
081: // itself - they should be nested in the collection, map or array
082: // element
083: JdoExtension[] a = fmd.jdoField == null ? null
084: : fmd.jdoField.extensions;
085: if (a != null) {
086: for (int i = 0; i < a.length; i++) {
087: if (a[i].isJdbc()) {
088: fmd.addError(BindingSupportImpl.getInstance()
089: .runtime(
090: "Unexpected extension: " + a[i]
091: + "\n"
092: + context.getContext()),
093: quiet);
094: }
095: }
096: }
097: }
098:
099: public void deletePass2Block(DeletePacket graph, int blockStart,
100: int blockEnd, CharBuf s, Connection con, boolean batch)
101: throws SQLException {
102: //ignore
103: }
104:
105: /**
106: * This is called for the first logical row of a crossjoin resultset.
107: */
108: protected boolean updateForFirstRow(FetchInfo fetchInfo,
109: boolean mustBreak, ResultSet rs, int colIndex, OID oid)
110: throws SQLException {
111: fetchInfo.onNextRow = false;
112: //if this keyOid was already checked in the previous round then
113: //it must not be read again
114: if (fetchInfo.breakStatus == FetchInfo.BREAK_STATUS_NULL) {
115: //the oid was read in previous round and was null
116: mustBreak = true;
117: fetchInfo.breakStatus = FetchInfo.BREAK_STATUS_DEFAULT;
118: } else if (fetchInfo.breakStatus == FetchInfo.BREAK_STATUS_DEFAULT) {
119: //the oid was not read in previous round so read it now
120: mustBreak = checkKeyOid(rs, colIndex, fetchInfo, mustBreak,
121: oid);
122: }
123: return mustBreak;
124: }
125:
126: protected boolean checkKeyOid(ResultSet rs, int colIndex,
127: FetchInfo fetchInfo, boolean mustBreak, OID oid)
128: throws SQLException {
129: OID keyOid;
130: keyOid = fmd.classMetaData.createOID(false);
131:
132: if (!((JdbcOID) keyOid).copyKeyFields(rs, colIndex)) {
133: fetchInfo.breakStatus = FetchInfo.BREAK_STATUS_NULL;
134: fetchInfo.nextOid = null;
135: mustBreak = true;
136: }
137:
138: if (!oid.equals(keyOid)) {
139: fetchInfo.breakStatus = FetchInfo.BREAK_STATUS_VALID;
140: fetchInfo.nextOid = keyOid;
141: fetchInfo.onNextRow = true;
142: mustBreak = true;
143: }
144: return mustBreak;
145: }
146:
147: /**
148: * Create a empty collection data structure in the state. This is used for parallel
149: * query processing.
150: */
151: public abstract void fillStateWithEmpty(FetchGroupField field,
152: State state);
153:
154: /**
155: * Fetch the values for this field.
156: */
157: public abstract int fetch(JdbcStorageManager sm, OID oid,
158: State state, FetchGroupField field, boolean forUpdate,
159: StateContainer container, boolean fetchPass2Fields,
160: ColFieldHolder colFHolder) throws SQLException;
161:
162: public abstract int fetchFrom(ResultSet rs, OID oid, State state,
163: FetchGroupField field, boolean forUpdate,
164: StateContainer container, boolean fetchPass2Fields,
165: int colIndex, FetchInfo fetchInfo, JdbcStorageManager sm)
166: throws SQLException;
167:
168: /**
169: * Fetch the values for this field using parallel query processing.
170: */
171: public abstract int fetchWithFilter(JdbcStorageManager sm,
172: StateContainer oidStates, FetchGroupField field,
173: ResultSet rs, boolean forUpdate, OID oidToCheckOn,
174: OID[] lastReadStateOID, ClassMetaData cmd,
175: ColFieldHolder colFHolder) throws SQLException;
176:
177: /**
178: * Create the select exp for this collection.
179: */
180: public abstract SelectExp getSelectFilterExp(JdbcStorageManager sm,
181: FetchGroupField field, ColFieldHolder colFHolder);
182:
183: public abstract SelectExp getSelectExpFrom(JdbcStorageManager sm,
184: SelectExp joinToExp, FetchGroupField field, FgDs owningFgDs);
185:
186: /**
187: * Create a join select exp through this.
188: */
189: public abstract SelectExp getSelectFilterJoinExp(boolean value,
190: SelectExp lhSe, SelectExp rootSe, boolean addRootJoin);
191:
192: protected void cleanup(Statement s) {
193: if (s != null) {
194: try {
195: s.close();
196: } catch (SQLException x) {
197: // ignore
198: }
199: }
200: }
201:
202: protected void cleanup(ResultSet rs) {
203: if (rs != null) {
204: try {
205: rs.close();
206: } catch (SQLException x) {
207: // ignore
208: }
209: }
210: }
211: }
|