0001: /*
0002: * Copyright (c) 1998 - 2005 Versant Corporation
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * Versant Corporation - initial API and implementation
0010: */
0011: package com.versant.core.jdbc.metadata;
0012:
0013: import com.versant.core.jdbc.sql.JdbcNameGenerator;
0014: import com.versant.core.jdbc.sql.exp.*;
0015: import com.versant.core.jdbc.*;
0016: import com.versant.core.jdbc.query.JdbcJDOQLCompiler;
0017: import com.versant.core.server.*;
0018: import com.versant.core.metadata.parser.JdoElement;
0019: import com.versant.core.metadata.parser.JdoExtension;
0020: import com.versant.core.metadata.parser.JdoExtensionKeys;
0021: import com.versant.core.metadata.*;
0022: import com.versant.core.common.OID;
0023: import com.versant.core.common.State;
0024: import com.versant.core.common.Utils;
0025: import com.versant.core.util.CharBuf;
0026: import com.versant.core.common.*;
0027: import com.versant.core.jdo.query.Node;
0028: import com.versant.core.jdo.query.OrderNode;
0029: import com.versant.core.common.Debug;
0030:
0031: import java.io.PrintStream;
0032: import java.util.ArrayList;
0033: import java.util.List;
0034: import java.util.Map;
0035: import java.sql.*;
0036:
0037: import com.versant.core.common.BindingSupportImpl;
0038:
0039: /**
0040: * This is a Map field stored using a link table.
0041: */
0042: public class JdbcMapField extends JdbcLinkCollectionField {
0043:
0044: private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
0045: private static final OID[] EMPTY_OID_ARRAY = new OID[0];
0046:
0047: /**
0048: * The column(s) holding the keys. This array will have length 1 unless
0049: * the keys are of a PC class with a composite primary key.
0050: */
0051: public JdbcColumn keyColumns[];
0052: /**
0053: * Should the keys be considered a dependent? If they are
0054: * they will be deleted if removed from the map or if our
0055: * instance is deleted. This only makes sense if the keys are instances
0056: * of a PC class.
0057: */
0058: public boolean keysDependent;
0059: /**
0060: * Are the keys OID's?
0061: */
0062: public boolean keysAreOIDs;
0063: /**
0064: * Should a join be done to pick up the fields for keys when they are
0065: * read? This only makes sense if the key is a PC class.
0066: */
0067: public int useKeyJoin;
0068:
0069: private transient boolean createKeyConstraint;
0070: private transient String keyConstraintName;
0071:
0072: public void dump(PrintStream out, String indent) {
0073: super .dump(out, indent);
0074: String is = indent + " ";
0075: if (keyColumns == null) {
0076: out.println(is + "keyColumns null");
0077: } else {
0078: for (int i = 0; i < keyColumns.length; i++) {
0079: out.println(is + "keyColumns[" + i + "] "
0080: + keyColumns[i]);
0081: }
0082: }
0083: out.println(is + "keysDependent " + keysDependent);
0084: out.println(is + "keysAreOIDs " + keysAreOIDs);
0085: out.println(is + "useKeyJoin " + toUseJoinString(useKeyJoin));
0086: }
0087:
0088: /**
0089: * Get the useKeyJoin value for this field. This is only valid for maps.
0090: */
0091: public int getUseKeyJoin() {
0092: return useKeyJoin;
0093: }
0094:
0095: /**
0096: * Complete the meta data for this collection. This must use info
0097: * already supplied in the .jdo file and add anything else needed.
0098: */
0099: public void processMetaData(JdoElement context,
0100: JdbcMetaDataBuilder mdb, boolean quiet) {
0101: keysAreOIDs = fmd.keyTypeMetaData != null;
0102: if (keysAreOIDs) {
0103: useKeyJoin = JdbcField.USE_JOIN_INNER;
0104: } else {
0105: useKeyJoin = JdbcField.USE_JOIN_NO;
0106: }
0107: super .processMetaData(context, mdb, quiet);
0108: }
0109:
0110: /**
0111: * Set the PK of the link table.
0112: */
0113: protected void createLinkTablePK() {
0114: linkTable.setPk(JdbcColumn.concat(ourPkColumns, keyColumns));
0115: }
0116:
0117: /**
0118: * Complete the key and value column related meta data.
0119: */
0120: protected void completeKeyAndValueColumnMetaData(
0121: JdbcClass jdbcClass, ArrayList cols, JdoElement context,
0122: JdoExtension[] linkNested, JdbcMetaDataBuilder mdb,
0123: boolean quiet) {
0124:
0125: // create the key column(s)
0126: JdoExtension ext = JdoExtension.find(JdoExtensionKeys.JDBC_KEY,
0127: linkNested);
0128: if (fmd.keyTypeMetaData != null) { // values are OIDs
0129: JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(
0130: fmd.classMetaData, mdb, fmd.keyTypeMetaData,
0131: context, JdbcMetaDataBuilder.KEY_FIELDNAME,
0132: ext == null ? null : ext.nested, quiet);
0133: keyColumns = rdb.getCols();
0134: cols.addAll(rdb.getColsList());
0135: createKeyConstraint = !rdb.isDoNotCreateConstraint();
0136: keyConstraintName = rdb.getConstraintName();
0137: } else {
0138: if (fmd.keyType == Object.class) {
0139: throw BindingSupportImpl.getInstance().runtime(
0140: "You must specify the key-type for maps\n"
0141: + fmd + "\n" + context.getContext());
0142: }
0143: JdbcColumn kc = mdb.createColumn(ext == null ? null
0144: : ext.nested, JdbcMetaDataBuilder.KEY_FIELDNAME,
0145: fmd.keyType);
0146: keyColumns = new JdbcColumn[] { kc };
0147: cols.add(kc);
0148: }
0149:
0150: int n = keyColumns.length;
0151: for (int i = 0; i < n; i++)
0152: keyColumns[i].setNulls(false);
0153:
0154: super .completeKeyAndValueColumnMetaData(jdbcClass, cols,
0155: context, linkNested, mdb, quiet);
0156: }
0157:
0158: /**
0159: * Name the key and value columns.
0160: */
0161: protected void nameKeyAndValueColumns(JdbcNameGenerator namegen,
0162: String linkTableNameForNamegen) {
0163: // name the keycolumn(s)
0164: if (keysAreOIDs) {
0165: String[] keyPkNames = JdbcColumn
0166: .getColumnNames(((JdbcClass) fmd.keyTypeMetaData.storeClass).table.pk);
0167: String[] linkKeyRefNames = JdbcColumn
0168: .getColumnNames(keyColumns);
0169: namegen.generateLinkTableValueRefNames(linkTable.name,
0170: keyPkNames, fmd.keyType.getName(), linkKeyRefNames,
0171: true);
0172: JdbcColumn.setColumnNames(keyColumns, linkKeyRefNames);
0173: } else {
0174: JdbcColumn c = keyColumns[0];
0175: if (c.name == null) {
0176: c.name = namegen.generateLinkTableValueName(
0177: linkTable.name, fmd.keyType, true);
0178: }
0179: }
0180:
0181: super .nameKeyAndValueColumns(namegen, linkTableNameForNamegen);
0182: }
0183:
0184: /**
0185: * Name our linkTable.
0186: */
0187: protected void nameLinkTable(JdbcNameGenerator namegen,
0188: JdbcClass jdbcClass) {
0189: linkTable.name = namegen.generateLinkTableName(
0190: jdbcClass.table.name, fmd.name, null);
0191: }
0192:
0193: /**
0194: * Create all the constraints for our link table.
0195: */
0196: protected List createConstraints(boolean pkConstraint,
0197: String pkConstraintName) {
0198: List constraints = super .createConstraints(pkConstraint,
0199: pkConstraintName);
0200:
0201: if (createKeyConstraint && keysAreOIDs
0202: && fmd.keyTypeMetaData.storeClass != null) {
0203: JdbcConstraint keyCon = new JdbcConstraint();
0204: keyCon.src = linkTable;
0205: keyCon.srcCols = keyColumns;
0206: keyCon.dest = ((JdbcClass) fmd.keyTypeMetaData.storeClass).table;
0207: keyCon.name = keyConstraintName;
0208: constraints.add(keyCon);
0209: }
0210:
0211: return constraints;
0212: }
0213:
0214: /**
0215: * Persist pass 2 field for a block of graph entries all with
0216: * the same class. The same ps'es can be used for all entries in the block.
0217: */
0218: public void persistPass2Block(PersistGraph graph, int blockStart,
0219: int blockEnd, CharBuf s, Connection con,
0220: boolean batchInserts, boolean batchUpdates)
0221: throws SQLException {
0222: PreparedStatement psdel = null;
0223: PreparedStatement psdelAll = null;
0224: PreparedStatement psins = null;
0225: int delCount = 0;
0226: try {
0227: String psdelSql = null;
0228: String psdelAllSql = null;
0229: String psinsSql = null;
0230: for (int pos = blockStart; pos < blockEnd; pos++) {
0231: State ns = graph.getNewState(pos);
0232: if (!ns.containsField(stateFieldNo))
0233: continue;
0234:
0235: MapDiff diff = (MapDiff) ns
0236: .getInternalObjectField(stateFieldNo);
0237:
0238: OID oid = graph.getOID(pos);
0239:
0240: if (diff == null
0241: || diff.status == CollectionDiff.STATUS_NEW) {
0242: if (!oid.isNew()) {
0243: if (psdelAll == null) {
0244: psdelAllSql = getDeleteAllLinkTableRowsSql(s);
0245: psdelAll = con
0246: .prepareStatement(psdelAllSql);
0247: }
0248: ((JdbcOID) oid).setParams(psdelAll, 1);
0249: if (batchUpdates) {
0250: psdelAll.addBatch();
0251: } else {
0252: try {
0253: psdelAll.execute();
0254: } catch (Exception e) {
0255: throw mapException(
0256: e,
0257: "Delete all link table rows failed: "
0258: + JdbcUtils.toString(e)
0259: + "\n"
0260: + "Field: "
0261: + fmd.getQName()
0262: + "\n"
0263: + "Instance: "
0264: + oid.toSString()
0265: + "\n"
0266: + JdbcUtils
0267: .getPreparedStatementInfo(
0268: psdelAllSql,
0269: psdelAll));
0270: }
0271: }
0272: }
0273: } else {
0274: Object[] deleted = diff.deletedKeys;
0275: if (deleted != null && deleted.length > 0) {
0276: if (psdel == null) {
0277: psdelSql = getDeleteLinkTableRowSql(s);
0278: psdel = con.prepareStatement(psdelSql);
0279: }
0280: deleteMapLinkTableRows(oid, deleted, psdel,
0281: batchUpdates, psdelSql);
0282: delCount += deleted.length;
0283: }
0284: }
0285:
0286: if (diff != null) {
0287: Object[] inserted = diff.insertedKeys;
0288: if (inserted != null && inserted.length > 0) {
0289: if (psins == null) {
0290: psinsSql = getInsertLinkTableRowSql(s);
0291: psins = con.prepareStatement(psinsSql);
0292: }
0293: insertMapLinkTableRows(oid, inserted,
0294: diff.insertedValues, psins,
0295: batchInserts, psinsSql);
0296: }
0297: }
0298: }
0299:
0300: if (batchUpdates) {
0301: execLinkTableBatchDeletes(delCount, psdel, psdelSql,
0302: psdelAll, psdelAllSql);
0303: }
0304: if (batchInserts && psins != null) {
0305: execLinkTableBatchInserts(psins, psinsSql);
0306: }
0307: } finally {
0308: cleanup(psdel);
0309: cleanup(psdelAll);
0310: cleanup(psins);
0311: }
0312: }
0313:
0314: /**
0315: * Delete keys from an map link table.
0316: */
0317: private void deleteMapLinkTableRows(OID oid, Object[] deleted,
0318: PreparedStatement psdel, boolean batch, String sql)
0319: throws SQLException {
0320: if (keysAreOIDs) {
0321: for (int j = deleted.length - 1; j >= 0; j--) {
0322: int pp = ((JdbcOID) oid).setParams(psdel, 1);
0323: ((JdbcOID) deleted[j]).setParams(psdel, pp);
0324: if (batch) {
0325: psdel.addBatch();
0326: } else {
0327: int uc;
0328: try {
0329: uc = psdel.executeUpdate();
0330: } catch (Exception e) {
0331: throw mapException(
0332: e,
0333: "Delete map link table row failed: "
0334: + JdbcUtils.toString(e)
0335: + "\n"
0336: + "Field: "
0337: + fmd.getTypeQName()
0338: + "\n"
0339: + "Key: "
0340: + ((OID) deleted[j])
0341: .toSString()
0342: + "\n"
0343: + "Instance: "
0344: + oid.toSString()
0345: + "\n"
0346: + JdbcUtils
0347: .getPreparedStatementInfo(
0348: sql, psdel));
0349: }
0350: if (uc == 0) {
0351: throw BindingSupportImpl
0352: .getInstance()
0353: .concurrentUpdate(
0354: "Map link table row not found: "
0355: + "Field: "
0356: + fmd.getTypeQName()
0357: + "\n"
0358: + "Key: "
0359: + ((OID) deleted[j])
0360: .toSString()
0361: + "\n"
0362: + "Instance: "
0363: + oid.toSString()
0364: + "\n"
0365: + JdbcUtils
0366: .getPreparedStatementInfo(
0367: sql,
0368: psdel),
0369: deleted[j]);
0370: }
0371: }
0372: }
0373: } else {
0374: JdbcColumn kc = keyColumns[0];
0375: for (int j = deleted.length - 1; j >= 0; j--) {
0376: int pp = ((JdbcOID) oid).setParams(psdel, 1);
0377: kc.set(psdel, pp, deleted[j]);
0378: if (batch) {
0379: psdel.addBatch();
0380: } else {
0381: int uc;
0382: try {
0383: uc = psdel.executeUpdate();
0384: } catch (Exception e) {
0385: throw mapException(
0386: e,
0387: "Delete map link table row failed: "
0388: + JdbcUtils.toString(e)
0389: + "\n"
0390: + "Field: "
0391: + fmd.getTypeQName()
0392: + "\n"
0393: + "Key: "
0394: + Utils.toString(deleted[j])
0395: + "\n"
0396: + "Instance: "
0397: + oid.toSString()
0398: + "\n"
0399: + JdbcUtils
0400: .getPreparedStatementInfo(
0401: sql, psdel));
0402: }
0403: if (uc == 0) {
0404: throw BindingSupportImpl
0405: .getInstance()
0406: .concurrentUpdate(
0407: "Map link table row not found: "
0408: + "Field: "
0409: + fmd.getTypeQName()
0410: + "\n"
0411: + "Key: "
0412: + Utils
0413: .toString(deleted[j])
0414: + "\n"
0415: + "Instance: "
0416: + oid.toSString()
0417: + "\n"
0418: + JdbcUtils
0419: .getPreparedStatementInfo(
0420: sql,
0421: psdel),
0422: oid);
0423: }
0424: }
0425: }
0426: }
0427: }
0428:
0429: /**
0430: * Insert rows into an map link table.
0431: */
0432: private void insertMapLinkTableRows(OID oid, Object[] insertedKeys,
0433: Object[] insertedValues, PreparedStatement psins,
0434: boolean batch, String sql) throws SQLException {
0435:
0436: JdbcColumn kc = keyColumns[0];
0437: JdbcColumn vc = valueColumns[0];
0438:
0439: // do the inserts
0440: int ilen = insertedKeys.length;
0441: for (int j = 0; j < ilen; j++) {
0442: int pp = ((JdbcOID) oid).setParams(psins, 1);
0443:
0444: // set key
0445: if (keysAreOIDs) {
0446: pp = ((JdbcOID) insertedKeys[j]).setParams(psins, pp);
0447: } else {
0448: kc.set(psins, pp++, insertedKeys[j]);
0449: }
0450:
0451: // set value
0452: if (valuesAreOIDs) {
0453: if (insertedValues[j] == null) {
0454: JdbcGenericOID.setNullParams(psins, pp,
0455: fmd.elementTypeMetaData);
0456: } else {
0457: ((JdbcOID) insertedValues[j]).setParams(psins, pp);
0458: }
0459: } else {
0460: vc.set(psins, pp, insertedValues[j]);
0461: }
0462:
0463: if (batch) {
0464: psins.addBatch();
0465: } else {
0466: try {
0467: psins.execute();
0468: } catch (Exception e) {
0469: String keyStr = keysAreOIDs ? ((OID) insertedKeys[j])
0470: .toSString()
0471: : Utils.toString(insertedKeys[j]);
0472: String valueStr = valuesAreOIDs ? ((OID) insertedValues[j])
0473: .toSString()
0474: : Utils.toString(insertedValues[j]);
0475: throw mapException(e,
0476: "Insert link table row failed: "
0477: + JdbcUtils.toString(e)
0478: + "\n"
0479: + "Field: "
0480: + fmd.getQName()
0481: + "\n"
0482: + "Instance: "
0483: + oid.toSString()
0484: + "\n"
0485: + "Key: "
0486: + keyStr
0487: + "\n"
0488: + "Value: "
0489: + valueStr
0490: + "\n"
0491: + JdbcUtils
0492: .getPreparedStatementInfo(
0493: sql, psins));
0494: }
0495: }
0496: }
0497: }
0498:
0499: /**
0500: * Get a SelectExp to select all the rows in this map using the
0501: * supplied fetch group field to control joins and so on.
0502: */
0503: public SelectExp getSelectExp(JdbcStorageManager dataStore,
0504: FetchGroupField field, FgDs[] fgDses) {
0505: SelectExp root = super .getSelectExp(dataStore, field, fgDses);
0506:
0507: // prepend our key columns to the select list
0508: SqlExp e = JdbcColumn.toSqlExp(keyColumns, root,
0509: root.selectList);
0510: root.selectList = e;
0511:
0512: // add a join for the keys if required
0513: if (keysAreOIDs) {
0514: if (field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO) {
0515: SelectExp se = new SelectExp();
0516: JdbcClass keyJdbcClass = (JdbcClass) fmd.keyTypeMetaData.storeClass;
0517: se.table = keyJdbcClass.table;
0518: se.outer = field.jdbcUseKeyJoin == JdbcField.USE_JOIN_OUTER;
0519: dataStore
0520: .addSelectFetchGroup(
0521: se,
0522: field.nextKeyFetchGroup,
0523: true,
0524: fgDses[1] = ((JdbcFetchGroup) field.nextKeyFetchGroup.storeFetchGroup)
0525: .getFgDs(true, se.outer), false);
0526: root.addJoin(keyColumns, se.table.pk, se);
0527: }
0528: }
0529: return root;
0530: }
0531:
0532: public SelectExp getSelectFilterJoinExp(boolean value,
0533: SelectExp lhSe, SelectExp rootSe, boolean addRootJoin) {
0534: SelectExp root = new SelectExp();
0535: root.table = linkTable;
0536:
0537: SelectExp se = new SelectExp();
0538: if (value) {
0539: se.table = ((JdbcClass) fmd.elementTypeMetaData.storeClass).table;
0540: root.addJoin(valueColumns, se.table.pk, se);
0541: } else {
0542: se.table = ((JdbcClass) fmd.keyTypeMetaData.storeClass).table;
0543: root.addJoin(keyColumns, se.table.pk, se);
0544: }
0545:
0546: lhSe.addJoin(lhSe.table.pk, ourPkColumns, root);
0547: return se;
0548: }
0549:
0550: public SelectExp getSelectFilterExp(JdbcStorageManager sm,
0551: FetchGroupField field, ColFieldHolder colFHolder) {
0552: SelectExp root = new SelectExp();
0553: root.table = linkTable;
0554:
0555: // add value columns to the select list
0556: SqlExp e = JdbcColumn.toSqlExp(valueColumns, root);
0557: root.selectList = e;
0558:
0559: // prepend our key columns to the select list
0560: e = JdbcColumn.toSqlExp(keyColumns, root, root.selectList);
0561: root.selectList = e;
0562:
0563: // prepend our pk columns to the select list
0564: e = JdbcColumn.toSqlExp(ourPkColumns, root, root.selectList);
0565: root.selectList = e;
0566: //add the order by to the owner
0567: root.appendOrderByForColumns(ourPkColumns);
0568:
0569: if (valuesAreOIDs) {
0570: if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO
0571: || fmd.ordering != null) {
0572: SelectExp se = new SelectExp();
0573: JdbcClass valueJdbcClass = (JdbcClass) fmd.elementTypeMetaData.storeClass;
0574: se.table = valueJdbcClass.table;
0575: se.outer = field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER;
0576: FgDs fgDs = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
0577: .getFgDs(true, se.outer);
0578: sm.addSelectFetchGroup(se, field.nextFetchGroup, true,
0579: fgDs, false);
0580: colFHolder.valueJs = fgDs.getJoinStruct();
0581:
0582: root.addJoin(valueColumns, se.table.pk, se);
0583:
0584: if (fmd.ordering != null) {
0585: se.addOrderBy(fmd.ordering, false);
0586: root.appendOrderByExp(se.orderByList);
0587: se.orderByList = null;
0588: }
0589: }
0590: } else {
0591: if (fmd.ordering != null) {
0592: // the ordering can only be 'this ascending' or 'this descending'
0593: boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING;
0594: root.appendOrderByExp(new OrderExp(valueColumns[0]
0595: .toSqlExp(root), desc));
0596: // there will be only one entry in valueColumns as this is
0597: // not a collection of PC instances
0598: }
0599: }
0600:
0601: if (fmd.ordered) {
0602: if (fmd.ordering != null) {
0603: throw BindingSupportImpl.getInstance().internal(
0604: "ordered == true && ordering != null, "
0605: + fmd.getTypeQName());
0606: }
0607: root.appendOrderByForColumns(linkTable.pkSimpleCols);
0608: }
0609:
0610: // add a join for the keys if required
0611: if (keysAreOIDs) {
0612: if (field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO) {
0613: SelectExp se = new SelectExp();
0614: JdbcClass keyJdbcClass = (JdbcClass) fmd.keyTypeMetaData.storeClass;
0615: se.table = keyJdbcClass.table;
0616: se.outer = field.jdbcUseKeyJoin == JdbcField.USE_JOIN_OUTER;
0617:
0618: FgDs fgDs = ((JdbcFetchGroup) field.nextKeyFetchGroup.storeFetchGroup)
0619: .getFgDs(true, se.outer);
0620: sm.addSelectFetchGroup(se, field.nextKeyFetchGroup,
0621: true, fgDs, false);
0622: colFHolder.keyJs = fgDs.getJoinStruct();
0623: root.addJoin(keyColumns, se.table.pk, se);
0624: }
0625: }
0626: return root;
0627: }
0628:
0629: public int fetchFrom(ResultSet rs, OID oid, State state,
0630: FetchGroupField field, boolean forUpdate,
0631: StateContainer container, boolean fetchPass2Fields,
0632: int colIndex, FetchInfo fetchInfo, JdbcStorageManager sm)
0633: throws SQLException {
0634: ArrayList keys = new ArrayList();
0635: ArrayList values = new ArrayList();
0636:
0637: // get info to extract the keys
0638: ClassMetaData keyCmd = fmd.keyTypeMetaData;
0639: boolean keyJoined = field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO;
0640: FetchGroup keyNFG = field.nextKeyFetchGroup;
0641: JdbcColumn kc = keyColumns[0];
0642: int keyScc = keyColumns.length;
0643: OID keyOid = null;
0644:
0645: // get info to extract the values
0646: ClassMetaData valueCmd = fmd.elementTypeMetaData;
0647: boolean valueJoined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO;
0648: FetchGroup nfg = field.nextFetchGroup;
0649: JdbcColumn vc = valueColumns[0];
0650: int valueScc = valueColumns.length;
0651:
0652: MutableInt nextIndex = null;
0653: if (valuesAreOIDs)
0654: nextIndex = new MutableInt();
0655: boolean first = true;
0656: for (;;) {
0657: if (first) {
0658: first = false;
0659: } else {
0660: if (!rs.next())
0661: break;
0662: }
0663:
0664: OID owningOid = fmd.classMetaData.createOID(false);
0665: if (!((JdbcOID) owningOid).copyKeyFields(rs, colIndex)) {
0666: //no elements found
0667: break;
0668: }
0669: int index = colIndex + ourPkColumns.length;
0670:
0671: if (keysAreOIDs) {
0672: keyOid = keyCmd.createOID(false);
0673: boolean isNull = !((JdbcOID) keyOid).copyKeyFields(rs,
0674: colIndex);
0675: if (!isNull)
0676: keys.add(keyOid);
0677: } else {
0678: keys.add(kc.get(rs, colIndex));
0679: }
0680: index += keyScc;
0681:
0682: if (valuesAreOIDs) {
0683: OID valueOid = valueCmd.createOID(false);
0684: boolean isNull = !((JdbcOID) valueOid).copyKeyFields(
0685: rs, index);
0686: index += valueScc;
0687: if (!isNull)
0688: values.add(valueOid);
0689:
0690: if (!isNull && valueJoined) {
0691: if (container.isStateRequired(valueOid, nfg)) {
0692: State valueState = sm
0693: .createStateImp(
0694: rs,
0695: valueOid,
0696: field.nextFetchGroup,
0697: forUpdate,
0698: index,
0699: nextIndex,
0700: true,
0701: container,
0702: ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
0703: .getFgDs(true, true),
0704: fetchPass2Fields, false, null);
0705: index = nextIndex.value;
0706: container.addState(valueOid, valueState);
0707: } else {
0708: index = sm
0709: .skipState(
0710: index,
0711: ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
0712: .getFgDs(true, true));
0713: }
0714: }
0715: } else {
0716: values.add(vc.get(rs, index));
0717: index += valueScc;
0718: }
0719:
0720: if (keysAreOIDs && keyJoined
0721: && container.isStateRequired(keyOid, keyNFG)) {
0722: State keyState = sm
0723: .createStateImp(
0724: rs,
0725: keyOid,
0726: field.nextKeyFetchGroup,
0727: forUpdate,
0728: index,
0729: null,
0730: true,
0731: container,
0732: ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
0733: .getFgDs(true, true),
0734: fetchPass2Fields, false, null);
0735: container.addState(keyOid, keyState);
0736: }
0737: }
0738:
0739: MapEntries me = new MapEntries();
0740: if (keysAreOIDs) {
0741: me.keys = new OID[keys.size()];
0742: keys.toArray(me.keys);
0743: } else {
0744: me.keys = keys.toArray();
0745: }
0746: if (valuesAreOIDs) {
0747: me.values = new OID[values.size()];
0748: values.toArray(me.values);
0749: } else {
0750: me.values = values.toArray();
0751: }
0752: state.setInternalObjectField(fmd.stateFieldNo, me);
0753: return keys.size();
0754: }
0755:
0756: public SelectExp getSelectExpFrom(JdbcStorageManager sm,
0757: SelectExp joinToExp, FetchGroupField field, FgDs owningFgDs) {
0758: SelectExp root = super .getSelectExpFromImp(joinToExp, field,
0759: sm, owningFgDs);
0760: root.selectList = JdbcColumn.toSqlExp(keyColumns, root,
0761: root.selectList);
0762: root.selectList = JdbcColumn.toSqlExp(ourPkColumns, root,
0763: root.selectList);
0764:
0765: // add a join for the keys if required
0766: if (keysAreOIDs) {
0767: if (field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO) {
0768: SelectExp se = new SelectExp();
0769: JdbcClass keyJdbcClass = (JdbcClass) fmd.keyTypeMetaData.storeClass;
0770: se.table = keyJdbcClass.table;
0771: se.outer = true;
0772: FgDs fgDs = ((JdbcFetchGroup) field.nextKeyFetchGroup.storeFetchGroup)
0773: .getFgDs(true, se.outer);
0774: sm.addSelectFetchGroup(se, field.nextKeyFetchGroup,
0775: true, fgDs, false);
0776: owningFgDs.keyJs = fgDs.getJoinStruct();
0777: root.addJoin(keyColumns, se.table.pk, se);
0778: }
0779: }
0780: return root;
0781: }
0782:
0783: /**
0784: * Fetch the values for this field.
0785: */
0786: public int fetch(JdbcStorageManager sm, OID oid, State state,
0787: FetchGroupField field, boolean forUpdate,
0788: StateContainer container, boolean fetchPass2Fields,
0789: ColFieldHolder colFHolder) throws SQLException {
0790: JoinStructure valueJs = null;
0791: JoinStructure keyJs = null;
0792:
0793: FgDs[] fgDses = new FgDs[2];
0794:
0795: String sql = forUpdate ? field.jdbcSelectSqlForUpdate
0796: : field.jdbcSelectSql;
0797: if (sql == null) {
0798: SelectExp se = getSelectExp(sm, field, fgDses);
0799: CharBuf s = sm.generateSql(se);
0800: sql = s.toString();
0801: if (forUpdate) {
0802: field.jdbcSelectSqlForUpdate = sql;
0803: } else {
0804: field.jdbcSelectSql = sql;
0805: }
0806: }
0807:
0808: if (valuesAreOIDs) {
0809: fgDses[0] = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
0810: .getExistingFgDs(
0811: true,
0812: field.jdbcUseJoin != JdbcField.USE_JOIN_INNER);
0813: if (colFHolder != null) {
0814: if (fgDses[0] != null) {
0815: colFHolder.valueJs = fgDses[0].getJoinStruct();
0816: }
0817: }
0818: }
0819: if (keysAreOIDs) {
0820: fgDses[1] = ((JdbcFetchGroup) field.nextKeyFetchGroup.storeFetchGroup)
0821: .getExistingFgDs(
0822: true,
0823: field.jdbcUseKeyJoin == JdbcField.USE_JOIN_OUTER);
0824: if (colFHolder != null) {
0825: if (fgDses[1] != null) {
0826: colFHolder.keyJs = fgDses[1].getJoinStruct();
0827: }
0828: }
0829: }
0830:
0831: PreparedStatement ps = null;
0832: ResultSet rs = null;
0833: try {
0834: ps = sm.con().prepareStatement(sql);
0835:
0836: ArrayList keys = new ArrayList();
0837: ArrayList values = new ArrayList();
0838:
0839: // get info to extract the keys
0840: final boolean keyJoined = field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO;
0841: int keyScc = keyColumns.length;
0842: OID keyOid = null;
0843:
0844: // get info to extract the values
0845: final boolean valueJoined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO
0846: || fmd.ordering != null;
0847: final int valueScc = valueColumns.length;
0848:
0849: // process the rows
0850: ((JdbcOID) oid).setParams(ps, 1);
0851: try {
0852: rs = ps.executeQuery();
0853: } catch (Exception e) {
0854: throw mapException(e, "Fetch link table rows failed: "
0855: + JdbcUtils.toString(e) + "\n" + "Field: "
0856: + fmd.getTypeQName() + "\n" + "Instance: "
0857: + oid.toSString() + "\n"
0858: + JdbcUtils.getPreparedStatementInfo(sql, ps));
0859: }
0860:
0861: MutableInt nextIndex = null;
0862: if (valuesAreOIDs)
0863: nextIndex = new MutableInt();
0864: for (; rs.next();) {
0865:
0866: if (keysAreOIDs) {
0867: keyOid = fmd.keyTypeMetaData.createOID(false);
0868: ((JdbcOID) keyOid).copyKeyFields(rs, 1);
0869: keys.add(keyOid);
0870: } else {
0871: keys.add(keyColumns[0].get(rs, 1));
0872: }
0873: int index = 1 + keyScc;
0874:
0875: if (valuesAreOIDs) {
0876: OID valueOid = fmd.elementTypeMetaData
0877: .createOID(false);
0878: if (((JdbcOID) valueOid).copyKeyFields(rs, index)) {
0879: values.add(valueOid);
0880: index += valueScc;
0881: if (valueJoined) {
0882: if (container.isStateRequired(valueOid,
0883: field.nextFetchGroup)) {
0884: container.addState(valueOid, sm
0885: .createStateImp(rs, valueOid,
0886: field.nextFetchGroup,
0887: forUpdate, index,
0888: nextIndex, true,
0889: container, fgDses[0],
0890: fetchPass2Fields,
0891: false, valueJs));
0892: index = nextIndex.value;
0893: } else {
0894: index = sm.skipState(index, fgDses[0]);
0895: }
0896: }
0897: } else {
0898: index += valueScc;
0899: values.add(null);
0900: }
0901: } else {
0902: values.add(valueColumns[0].get(rs, index));
0903: index += valueScc;
0904: }
0905:
0906: if (keysAreOIDs
0907: && keyJoined
0908: && container.isStateRequired(keyOid,
0909: field.nextKeyFetchGroup)) {
0910: container.addState(keyOid, sm.createStateImp(rs,
0911: keyOid, field.nextKeyFetchGroup, forUpdate,
0912: index, null, true, container, fgDses[1],
0913: fetchPass2Fields, false, keyJs));
0914: }
0915: }
0916:
0917: MapEntries me = new MapEntries();
0918: if (keysAreOIDs) {
0919: me.keys = new OID[keys.size()];
0920: keys.toArray(me.keys);
0921: } else {
0922: me.keys = keys.toArray();
0923: }
0924: if (valuesAreOIDs) {
0925: me.values = new OID[values.size()];
0926: values.toArray(me.values);
0927: } else {
0928: me.values = values.toArray();
0929: }
0930: state.setInternalObjectField(fmd.stateFieldNo, me);
0931: // @todo what about empty/null checking?
0932:
0933: return keys.size();
0934: } finally {
0935: cleanup(rs);
0936: cleanup(ps);
0937: }
0938: }
0939:
0940: /**
0941: * Fetch the values for this field using parallel query processing.
0942: */
0943: public int fetchWithFilter(JdbcStorageManager sm,
0944: StateContainer oidStates, FetchGroupField field,
0945: ResultSet rs, boolean forUpdate, OID oidToCheckOn,
0946: OID[] lastReadStateOID, ClassMetaData cmd,
0947: ColFieldHolder colFHolder) throws SQLException {
0948:
0949: ClassMetaData keyCmd = fmd.keyTypeMetaData;
0950: boolean keyJoined = field.jdbcUseKeyJoin != JdbcField.USE_JOIN_NO;
0951: FetchGroup keyNFG = field.nextKeyFetchGroup;
0952: JdbcColumn kc = keyColumns[0];
0953: int keyScc = keyColumns.length;
0954:
0955: // get info to extract the values
0956: ClassMetaData valueCmd = fmd.elementTypeMetaData;
0957: boolean valueJoined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO;
0958: FetchGroup nfg = field.nextFetchGroup;
0959: JdbcColumn vc = valueColumns[0];
0960: int valueScc = valueColumns.length;
0961:
0962: int rootOIDLength = ((JdbcClass) cmd.storeClass).table.pkSimpleColumnCount;
0963: int stateOIDPKLen = ((JdbcClass) fmd.classMetaData.storeClass).table.pkSimpleColumnCount;
0964:
0965: //the oid just read from the rs row
0966: OID rootOid = cmd.createOID(false);
0967: //the oid read from the previous rs row
0968: OID prevRootOid = cmd.createOID(false);
0969: OID tmpOID = null;
0970:
0971: OID stateOID = fmd.classMetaData.createOID(false);
0972: OID prevStateOID = fmd.classMetaData.createOID(false);
0973: OID tmpStateOID = null;
0974:
0975: boolean currentRowValid = false;
0976: boolean prevRowValid = false;
0977:
0978: final ArrayList keys = new ArrayList();
0979: final ArrayList values = new ArrayList();
0980:
0981: MutableInt nextIndex = null;
0982: if (valuesAreOIDs)
0983: nextIndex = new MutableInt();
0984: int returnState = 0;
0985:
0986: FgDs fgDsValue = null;
0987: if (valuesAreOIDs) {
0988: fgDsValue = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
0989: .getExistingFgDs(
0990: true,
0991: field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER);
0992: if (colFHolder != null) {
0993: colFHolder.valueJs = fgDsValue.getJoinStruct();
0994: }
0995: }
0996:
0997: FgDs fgDsKeys = null;
0998: if (keysAreOIDs) {
0999: fgDsKeys = ((JdbcFetchGroup) field.nextKeyFetchGroup.storeFetchGroup)
1000: .getFgDs(
1001: true,
1002: field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER);
1003: if (colFHolder != null) {
1004: colFHolder.keyJs = fgDsKeys.getJoinStruct();
1005: }
1006: }
1007:
1008: //This oid was read previously so we have to read the rest of the row now.
1009: if (lastReadStateOID[0] != null) {
1010: // System.out.println("--- FINISHING LAST ROW READ");
1011: int index = 1 + rootOIDLength + stateOIDPKLen;
1012:
1013: prevRootOid = lastReadStateOID[0];
1014: // index += rootOIDLength;
1015:
1016: stateOID = lastReadStateOID[1];
1017: // index += stateOIDPKLen;
1018:
1019: currentRowValid = oidStates.containsKey(stateOID);
1020: if (currentRowValid) {
1021: returnState |= STATUS_VALID_ROWS;
1022: OID keyOid = null;
1023: if (keysAreOIDs) {
1024: keyOid = keyCmd.createOID(false);
1025: ((JdbcOID) keyOid).copyKeyFields(rs, index);
1026: keys.add(keyOid);
1027: } else {
1028: keys.add(kc.get(rs, index));
1029: }
1030: index += keyScc;
1031:
1032: if (valuesAreOIDs) {
1033: OID valueOid = valueCmd.createOID(false);
1034: ((JdbcOID) valueOid).copyKeyFields(rs, index);
1035: index += valueScc;
1036: values.add(valueOid);
1037: if (valueJoined) {
1038: if (oidStates.isStateRequired(valueOid, nfg)) {
1039: State valueState = sm.createStateImp(rs,
1040: valueOid, field.nextFetchGroup,
1041: forUpdate, index, nextIndex, true,
1042: oidStates, fgDsValue, false, false,
1043: null);
1044:
1045: index = nextIndex.value;
1046: // valueOid.resolve(valueState);
1047: oidStates.addState(valueOid, valueState);
1048: } else {
1049: index = sm.skipState(index, fgDsValue);
1050: }
1051: }
1052: } else {
1053: values.add(vc.get(rs, index));
1054: index += valueScc;
1055: }
1056:
1057: if (keysAreOIDs && keyJoined
1058: && oidStates.isStateRequired(keyOid, keyNFG)) {
1059: State keyState = sm.createStateImp(rs, keyOid,
1060: field.nextKeyFetchGroup, forUpdate, index,
1061: nextIndex, true, oidStates, fgDsKeys,
1062: false, false, colFHolder.keyJs);
1063: oidStates.addState(keyOid, keyState);
1064: }
1065: if (nextIndex != null)
1066: nextIndex.value = 0;
1067: }
1068:
1069: //preserve the prevRootOid
1070: tmpOID = rootOid;
1071: rootOid = prevRootOid;
1072: prevRootOid = tmpOID;
1073:
1074: //preserve the prevStateOID
1075: tmpStateOID = stateOID;
1076: stateOID = prevStateOID;
1077: prevStateOID = tmpStateOID;
1078:
1079: prevRowValid = currentRowValid;
1080: }
1081:
1082: for (; rs.next();) {
1083: int index = 1;
1084:
1085: ((JdbcOID) rootOid).copyKeyFields(rs, index);
1086: index += rootOIDLength;
1087:
1088: ((JdbcOID) stateOID).copyKeyFields(rs, index);
1089: index += stateOIDPKLen;
1090:
1091: currentRowValid = oidStates.containsKey(stateOID);
1092:
1093: if (!stateOID.equals(prevStateOID) && prevRowValid) {
1094: if (Debug.DEBUG) {
1095: if (oidStates.get(prevStateOID) == null) {
1096: ((StatesReturned) oidStates).dump();
1097: throw new NullPointerException(prevStateOID
1098: .toSString()
1099: + " oidStates " + oidStates);
1100: }
1101: }
1102: if (updateStateFilter(keys, values, oidStates
1103: .get(prevStateOID))) {
1104: returnState |= STATUS_DATA_ADDED;
1105: }
1106:
1107: if (oidToCheckOn.equals(prevRootOid)
1108: && !oidToCheckOn.equals(rootOid)) {
1109: lastReadStateOID[0] = rootOid;
1110: lastReadStateOID[1] = stateOID;
1111: returnState |= STATUS_VALID_ROWS;
1112: return returnState;
1113: }
1114:
1115: keys.clear();
1116: values.clear();
1117: }
1118:
1119: if (currentRowValid) {
1120: returnState |= STATUS_VALID_ROWS;
1121: OID keyOid = null;
1122: if (keysAreOIDs) {
1123: keyOid = keyCmd.createOID(false);
1124: ((JdbcOID) keyOid).copyKeyFields(rs, index);
1125: keys.add(keyOid);
1126: } else {
1127: keys.add(kc.get(rs, index));
1128: }
1129: index += keyScc;
1130:
1131: if (valuesAreOIDs) {
1132: OID valueOid = valueCmd.createOID(false);
1133: ((JdbcOID) valueOid).copyKeyFields(rs, index);
1134: index += valueScc;
1135: values.add(valueOid);
1136: if (valueJoined) {
1137: if (oidStates.isStateRequired(valueOid, nfg)) {
1138: State valueState = sm
1139: .createStateImp(
1140: rs,
1141: valueOid,
1142: field.nextFetchGroup,
1143: forUpdate,
1144: index,
1145: nextIndex,
1146: true,
1147: oidStates,
1148: ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
1149: .getFgDs(
1150: true,
1151: field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER),
1152: false, false, null);
1153:
1154: index = nextIndex.value;
1155: oidStates.addState(valueOid, valueState);
1156: } else {
1157: index = sm
1158: .skipState(
1159: index,
1160: ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
1161: .getFgDs(
1162: true,
1163: field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER));
1164: }
1165: }
1166: } else {
1167: values.add(vc.get(rs, index));
1168: index += valueScc;
1169: }
1170:
1171: if (keysAreOIDs && keyJoined
1172: && oidStates.isStateRequired(keyOid, keyNFG)) {
1173: State keyState = sm
1174: .createStateImp(
1175: rs,
1176: keyOid,
1177: field.nextKeyFetchGroup,
1178: forUpdate,
1179: index,
1180: nextIndex,
1181: true,
1182: oidStates,
1183: ((JdbcFetchGroup) field.nextKeyFetchGroup.storeFetchGroup)
1184: .getFgDs(
1185: true,
1186: field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER),
1187: false, false, colFHolder.keyJs);
1188: oidStates.addState(keyOid, keyState);
1189: }
1190:
1191: if (nextIndex != null)
1192: nextIndex.value = 0;
1193: }
1194:
1195: //preserve the prevRootOid
1196: tmpOID = rootOid;
1197: rootOid = prevRootOid;
1198: prevRootOid = tmpOID;
1199:
1200: //preserve the prevStateOID
1201: tmpStateOID = stateOID;
1202: stateOID = prevStateOID;
1203: prevStateOID = tmpStateOID;
1204:
1205: prevRowValid = currentRowValid;
1206: }
1207:
1208: rs.close();
1209: returnState |= STATUS_CLOSED;
1210: if ((returnState & STATUS_VALID_ROWS) == STATUS_VALID_ROWS) {
1211: if (updateStateFilter(keys, values, oidStates
1212: .get(prevStateOID))) {
1213: returnState |= STATUS_DATA_ADDED;
1214: }
1215: }
1216: return returnState;
1217: }
1218:
1219: public void fillStateWithEmpty(FetchGroupField field, State state) {
1220: if (!state.containsField(fmd.stateFieldNo)) {
1221: MapEntries me = new MapEntries();
1222: me.preGenerated = true;
1223: if (keysAreOIDs) {
1224: me.keys = EMPTY_OID_ARRAY;
1225: } else {
1226: me.keys = EMPTY_OBJECT_ARRAY;
1227: }
1228: if (valuesAreOIDs) {
1229: me.values = EMPTY_OID_ARRAY;
1230: } else {
1231: me.values = EMPTY_OBJECT_ARRAY;
1232: }
1233: state.setInternalObjectField(fmd.stateFieldNo, me);
1234: }
1235: }
1236:
1237: /**
1238: * Update the supplied state with a MapEntries intsance. This method expects
1239: * the field to be filled with a non-null value.
1240: */
1241: private boolean updateStateFilter(ArrayList keys, ArrayList values,
1242: State state) {
1243: if (Debug.DEBUG) {
1244: //TODO START IF(DEBUG)
1245: if (!state.containsField(fmd.stateFieldNo)) {
1246: throw BindingSupportImpl.getInstance()
1247: .internal(
1248: "The mapField '" + fmd.name
1249: + "' is not filled");
1250: }
1251: if (state.getInternalObjectField(fmd.stateFieldNo) == null) {
1252: throw BindingSupportImpl.getInstance().internal(
1253: "The mapField '" + fmd.name
1254: + "' is filled with a null value");
1255: }
1256: //TODO END IF(DEBUG)
1257: }
1258:
1259: /**
1260: * The field is already resolved for client and this should be a state
1261: * that was retrieved from the localPMCache
1262: */
1263: if ((state.getInternalObjectField(fmd.stateFieldNo) instanceof Map)) {
1264: // if (state.txId != TxId.PM_STATE_ID) {
1265: // throw BindingSupportImpl.getInstance().internal(
1266: // "The field is filled with " +
1267: // "a Map instance, but the state is not a localPmCache state");
1268: // }
1269: return false;
1270: }
1271:
1272: if (!((MapEntries) state
1273: .getInternalObjectField(fmd.stateFieldNo)).preGenerated) {
1274: return false;
1275: }
1276:
1277: MapEntries me = new MapEntries();
1278: if (keysAreOIDs) {
1279: me.keys = new OID[keys.size()];
1280: keys.toArray(me.keys);
1281: } else {
1282: me.keys = keys.toArray();
1283: }
1284: if (valuesAreOIDs) {
1285: me.values = new OID[values.size()];
1286: values.toArray(me.values);
1287: } else {
1288: me.values = values.toArray();
1289: }
1290: state.setInternalObjectField(fmd.stateFieldNo, me);
1291: return true;
1292: }
1293:
1294: /**
1295: * Convert this field into a containsKey expression.
1296: */
1297: public SqlExp toContainsKeySqlExp(JdbcJDOQLCompiler comp,
1298: SelectExp root, Node args) {
1299: return toContainsSqlExp(keyColumns, fmd.keyTypeMetaData, comp,
1300: root, args);
1301: }
1302:
1303: /**
1304: * Add our key columns to the row.
1305: */
1306: protected void addFetchAllRowsKey(SqlExp e, SelectExp se) {
1307: for (; e.next != null; e = e.next)
1308: ;
1309: e.next = JdbcColumn.toSqlExp(keyColumns, se);
1310: }
1311:
1312: /**
1313: * Fetch a row of values for this field. This is used when bulk copying
1314: * one database to another to read all the rows in a given link table.
1315: * Return the index of the last column read + 1.
1316: */
1317: public int readRow(ResultSet rs, JdbcLinkCollectionField.LinkRow row)
1318: throws SQLException {
1319: int pos = super .readRow(rs, row);
1320: if (keysAreOIDs) {
1321: OID keyOid = fmd.keyTypeMetaData.createOID(false);
1322: ((JdbcOID) keyOid).copyKeyFields(rs, pos);
1323: row.key = keyOid;
1324: pos += keyColumns.length;
1325: } else {
1326: row.key = keyColumns[0].get(rs, pos++);
1327: }
1328: return pos;
1329: }
1330:
1331: /**
1332: * Set a row of values for this field on a PreparedStatement.
1333: * This is used when bulk copying one database to another.
1334: */
1335: public void writeRow(PreparedStatement ps, LinkRow row)
1336: throws SQLException {
1337: row.owner.setCmd(fmd.classMetaData);
1338: int pos = row.owner.setParams(ps, 1);
1339: if (keysAreOIDs) {
1340: JdbcGenericOID k = (JdbcGenericOID) row.key;
1341: k.setCmd(fmd.classMetaData);
1342: pos = k.setParams(ps, pos);
1343: } else {
1344: keyColumns[0].set(ps, pos++, row.key);
1345: }
1346: if (valuesAreOIDs) {
1347: JdbcGenericOID v = (JdbcGenericOID) row.value;
1348: v.setCmd(fmd.classMetaData);
1349: v.setParams(ps, pos);
1350: } else {
1351: valueColumns[0].set(ps, pos, row.value);
1352: }
1353: }
1354:
1355: }
|