Source Code Cross Referenced for JdbcLinkCollectionField.java in  » Testing » PolePosition-0.20 » com » versant » core » jdbc » metadata » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » PolePosition 0.20 » com.versant.core.jdbc.metadata 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.common.Debug;
0014:        import com.versant.core.common.*;
0015:        import com.versant.core.metadata.*;
0016:        import com.versant.core.metadata.parser.JdoElement;
0017:        import com.versant.core.metadata.parser.JdoExtension;
0018:        import com.versant.core.metadata.parser.JdoExtensionKeys;
0019:        import com.versant.core.jdo.query.*;
0020:        import com.versant.core.server.StateContainer;
0021:        import com.versant.core.server.PersistGraph;
0022:        import com.versant.core.jdbc.*;
0023:        import com.versant.core.jdbc.query.JdbcJDOQLCompiler;
0024:        import com.versant.core.jdbc.sql.JdbcNameGenerator;
0025:        import com.versant.core.jdbc.sql.SqlDriver;
0026:        import com.versant.core.jdbc.sql.exp.*;
0027:        import com.versant.core.util.CharBuf;
0028:
0029:        import java.io.PrintStream;
0030:        import java.sql.Connection;
0031:        import java.sql.PreparedStatement;
0032:        import java.sql.ResultSet;
0033:        import java.sql.SQLException;
0034:        import java.util.ArrayList;
0035:        import java.util.HashSet;
0036:        import java.util.List;
0037:        import java.lang.reflect.Array;
0038:
0039:        /**
0040:         * A field that is a Collection, Map or array stored in a link table.
0041:         */
0042:        public class JdbcLinkCollectionField extends JdbcCollectionField {
0043:
0044:            /**
0045:             * If this field is in a many-to-many relationship then this is the
0046:             * other side.
0047:             */
0048:            public JdbcLinkCollectionField inverse;
0049:            /**
0050:             * Is this the read-only half of a many-to-many?
0051:             */
0052:            public boolean readOnly;
0053:            /**
0054:             * The link table.
0055:             */
0056:            public JdbcTable linkTable;
0057:            /**
0058:             * The column(s) holding the values. This array will have length 1
0059:             * unless the values are of a PC class with a composite primary key.
0060:             */
0061:            public JdbcColumn[] valueColumns;
0062:            /**
0063:             * Are the values OID's?
0064:             */
0065:            public boolean valuesAreOIDs;
0066:
0067:            private transient boolean createValueConstraint;
0068:            private transient String valueConstraintName;
0069:            private transient boolean doNotCreateTable;
0070:
0071:            // Cache for SQL to delete a value from the collection.
0072:            private transient String deleteRowSql;
0073:            // Cache for SQL to delete all values from the collection.
0074:            private transient String deleteAllRowsSql;
0075:            // Cache for SQL to insert a value into the collection.
0076:            private transient String insertRowSql;
0077:
0078:            // Size of the moving window used to calculate avgRowCount.
0079:            private static final int WINDOW_SIZE = 20;
0080:            // The initial array size is avgRowCount multiplied by this.
0081:            private static final float FUDGE_FACTOR = 1.5f;
0082:            // This is the minimum initial array size.
0083:            private static final int MIN_LEN = 4;
0084:
0085:            // Total number of fetches done so far.
0086:            protected transient int fetchCount;
0087:            // Average number of rows retrieved with each fetch.
0088:            protected transient float avgRowCount;
0089:            // Total number of times the values array for a fetch has had to be
0090:            // expanded (i.e. we guessed the size incorrectly. This is the number
0091:            // of extra objects and array copies we have had to do.
0092:            protected transient int expansionCount;
0093:
0094:            /**
0095:             * Add all tables that belong to this field to the set.
0096:             */
0097:            public void getTables(HashSet tables) {
0098:                if (!readOnly && !doNotCreateTable && linkTable != null) {
0099:                    tables.add(linkTable);
0100:                }
0101:            }
0102:
0103:            public void dump(PrintStream out, String indent) {
0104:                super .dump(out, indent);
0105:                String is = indent + "  ";
0106:                out.println(is + "inverse " + inverse);
0107:                out.println(is + "readOnly " + readOnly);
0108:                out.println(is + "valuesAreOIDs " + valuesAreOIDs);
0109:                out.println(is + "linkTable " + linkTable);
0110:                if (valueColumns == null) {
0111:                    out.println(is + "valueColumns null");
0112:                } else {
0113:                    for (int i = 0; i < valueColumns.length; i++) {
0114:                        out.println(is + "valueColumns[" + i + "] "
0115:                                + valueColumns[i]);
0116:                    }
0117:                }
0118:            }
0119:
0120:            /**
0121:             * Complete the meta data for this collection. This must use info
0122:             * already supplied in the .jdo file and add anything else needed.
0123:             */
0124:            public void processMetaData(JdoElement context,
0125:                    JdbcMetaDataBuilder mdb, boolean quiet) {
0126:                super .processMetaData(context, mdb, quiet);
0127:
0128:                JdoExtension[] extensions = getExtensions();
0129:
0130:                // see if this is the inverse side of a many-to-many
0131:                JdoExtension ext = JdoExtension.find(JdoExtensionKeys.INVERSE,
0132:                        extensions);
0133:                if (ext != null) {
0134:                    processInverse(mdb, ext);
0135:                    return;
0136:                }
0137:
0138:                valuesAreOIDs = fmd.elementTypeMetaData != null;
0139:                if (valuesAreOIDs) {
0140:                    if (fmd.ordered || allowNulls()) {
0141:                        useJoin = JdbcField.USE_JOIN_OUTER;
0142:                    } else {
0143:                        useJoin = JdbcField.USE_JOIN_INNER;
0144:                    }
0145:                } else {
0146:                    useJoin = JdbcField.USE_JOIN_NO;
0147:                }
0148:
0149:                ext = JdoExtension.find(JdoExtensionKeys.MANAGED, extensions);
0150:                if (ext != null) {
0151:                    if (fmd.category == MDStatics.CATEGORY_ARRAY
0152:                            && ext.getBoolean()) {
0153:                        throw BindingSupportImpl.getInstance()
0154:                                .invalidOperation(
0155:                                        "The managed option is not supported for arrays: "
0156:                                                + fmd.name);
0157:                    }
0158:                    fmd.managed = ext.getBoolean();
0159:                } else {
0160:                    if (fmd.category != MDStatics.CATEGORY_ARRAY) {
0161:                        fmd.managed = mdb.getJdbcConfig().managedManyToMany;
0162:                    } else {
0163:                        fmd.managed = false;
0164:                    }
0165:                }
0166:
0167:                ClassMetaData cmd = fmd.classMetaData;
0168:                JdbcClass jdbcClass = (JdbcClass) cmd.storeClass;
0169:                ArrayList cols = new ArrayList();
0170:                JdoExtension link = JdoExtension.find(
0171:                        JdoExtensionKeys.JDBC_LINK_TABLE, extensions);
0172:                JdoExtension[] linkNested = link == null ? null : link.nested;
0173:
0174:                // create our pk columns
0175:                ext = JdoExtension.find(JdoExtensionKeys.JDBC_OWNER_REF,
0176:                        linkNested);
0177:                JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(cmd,
0178:                        mdb, fmd.classMetaData, context,
0179:                        JdbcMetaDataBuilder.OWNER_REF_FIELDNAME,
0180:                        ext == null ? null : ext.nested, quiet);
0181:                ourPkColumns = rdb.getCols();
0182:                cols.addAll(rdb.getColsList());
0183:                boolean pkConstraint = !rdb.isDoNotCreateConstraint();
0184:                String pkConstraintName = rdb.getConstraintName();
0185:
0186:                // create the sequence column if required
0187:                if (fmd.ordered) {
0188:                    ext = JdoExtension.find(JdoExtensionKeys.JDBC_SEQUENCE,
0189:                            linkNested);
0190:                    sequenceColumn = mdb.createColumn(ext == null ? null
0191:                            : ext.nested,
0192:                            JdbcMetaDataBuilder.SEQUENCE_FIELDNAME,
0193:                            Integer.TYPE);
0194:                    cols.add(sequenceColumn);
0195:                }
0196:
0197:                completeKeyAndValueColumnMetaData(jdbcClass, cols, context,
0198:                        linkNested, mdb, quiet);
0199:
0200:                // create the link table
0201:                linkTable = new JdbcTable();
0202:                linkTable.comment = fmd.getTypeQName();
0203:                createLinkTablePK();
0204:                linkTable.sqlDriver = mdb.getSqlDriver();
0205:                linkTable.cols = new JdbcColumn[cols.size()];
0206:                cols.toArray(linkTable.cols);
0207:                linkTable.setTableOnCols();
0208:
0209:                // Create a constraint for the main table pk columns and for the value
0210:                // (and key for map) columns if the value (or key) is an OID
0211:                List constraints = createConstraints(pkConstraint,
0212:                        pkConstraintName);
0213:                linkTable.constraints = new JdbcConstraint[constraints.size()];
0214:                constraints.toArray(linkTable.constraints);
0215:
0216:                // see if the link table must be left out of the schema or not
0217:                ext = JdoExtension.find(
0218:                        JdoExtensionKeys.JDBC_DO_NOT_CREATE_TABLE, linkNested);
0219:                doNotCreateTable = ext != null && ext.getBoolean();
0220:                String linkTableNameForNamegen = null;
0221:
0222:                // Make sure the link table has a name. A dummy name is used for
0223:                // name generation purposes if the table is being left out of the
0224:                // schema and there is already a table with the same name so that
0225:                // any generated column names will match those of the table included
0226:                // in the schema (if any).
0227:                JdbcNameGenerator namegen = mdb.getNameGenerator();
0228:                ext = JdoExtension.find(JdoExtensionKeys.JDBC_TABLE_NAME,
0229:                        linkNested);
0230:                if (ext == null) {
0231:                    nameLinkTable(namegen, jdbcClass);
0232:                } else {
0233:                    try {
0234:                        namegen.addTableName(linkTable.name = ext.getString());
0235:                    } catch (IllegalArgumentException e) {
0236:                        if (!doNotCreateTable) {
0237:                            throw BindingSupportImpl.getInstance().runtime(
0238:                                    e.getMessage() + "\n"
0239:                                            + context.getContext(), e);
0240:                        }
0241:                        // Duplicate names are ok if the table is not being created.
0242:                        // Use a dummy name so generated column names are the same as
0243:                        // the original. This dummy name is removed at the end of this
0244:                        // method.
0245:                        linkTableNameForNamegen = linkTable.name
0246:                                + System.currentTimeMillis();
0247:                        namegen.addTableName(linkTableNameForNamegen);
0248:                    }
0249:                }
0250:                String linkTableName = linkTable.name;
0251:                if (linkTableNameForNamegen == null)
0252:                    linkTableNameForNamegen = linkTableName;
0253:
0254:                // name its pk constraint
0255:                if (!doNotCreateTable) {
0256:                    if (linkTable.pkConstraintName == null) {
0257:                        linkTable.pkConstraintName = namegen
0258:                                .generatePkConstraintName(linkTableName);
0259:                    } else {
0260:                        namegen.addPkConstraintName(linkTableName,
0261:                                linkTable.pkConstraintName);
0262:                    }
0263:                }
0264:
0265:                // register the names of all columns that already have names
0266:                for (int i = 0; i < linkTable.cols.length; i++) {
0267:                    try {
0268:                        linkTable.cols[i].addColumnNames(
0269:                                linkTableNameForNamegen, namegen);
0270:                    } catch (IllegalArgumentException e) {
0271:                        if (!doNotCreateTable) {
0272:                            throw BindingSupportImpl.getInstance().runtime(
0273:                                    e.getMessage() + "\n"
0274:                                            + context.getContext(), e);
0275:                        }
0276:                        // duplicates are ok if table is not being created
0277:                    }
0278:                }
0279:
0280:                // name our pk columns
0281:                String[] pkNames = jdbcClass.table.getPkNames();
0282:                String[] ourPkNames = JdbcColumn.getColumnNames(ourPkColumns);
0283:                namegen.generateLinkTableMainRefNames(linkTableNameForNamegen,
0284:                        pkNames, ourPkNames);
0285:                JdbcColumn.setColumnNames(ourPkColumns, ourPkNames);
0286:
0287:                // name the sequence column (if any)
0288:                if (sequenceColumn != null && sequenceColumn.name == null) {
0289:                    sequenceColumn.name = namegen
0290:                            .generateLinkTableSequenceName(linkTableNameForNamegen);
0291:                }
0292:
0293:                // name the key and value columns
0294:                nameKeyAndValueColumns(namegen, linkTableNameForNamegen);
0295:
0296:                // name all the constraints
0297:                if (!doNotCreateTable) {
0298:                    for (int i = 0; i < linkTable.constraints.length; i++) {
0299:                        JdbcConstraint c = linkTable.constraints[i];
0300:                        if (c.name != null) {
0301:                            namegen.addRefConstraintName(linkTableName, c.name);
0302:                        } else {
0303:                            String[] fkNames = JdbcColumn
0304:                                    .getColumnNames(c.srcCols);
0305:                            String[] refPkNames = JdbcColumn
0306:                                    .getColumnNames(c.dest.pk);
0307:                            c.name = namegen.generateRefConstraintName(
0308:                                    linkTableName, c.dest.name, fkNames,
0309:                                    refPkNames);
0310:                        }
0311:                    }
0312:                }
0313:
0314:                // remove the table if it is not going to be in the schema so other
0315:                // fields can be mapped to the same name and get the same generated
0316:                // column names
0317:                if (doNotCreateTable)
0318:                    namegen.removeTableName(linkTableNameForNamegen);
0319:
0320:                // sycn with our inverse (if any)
0321:                syncWithInverse(mdb);
0322:            }
0323:
0324:            /**
0325:             * Create all the constraints for our link table.
0326:             */
0327:            protected List createConstraints(boolean pkConstraint,
0328:                    String pkConstraintName) {
0329:                ArrayList constraints = new ArrayList();
0330:
0331:                if (pkConstraint) {
0332:                    JdbcConstraint mainCon = new JdbcConstraint();
0333:                    mainCon.src = linkTable;
0334:                    mainCon.srcCols = ourPkColumns;
0335:                    mainCon.dest = ((JdbcClass) fmd.classMetaData.storeClass).table;
0336:                    mainCon.name = pkConstraintName;
0337:                    constraints.add(mainCon);
0338:                }
0339:
0340:                if (createValueConstraint && valuesAreOIDs
0341:                        && fmd.elementTypeMetaData.storeClass != null) {
0342:                    JdbcConstraint valueCon = new JdbcConstraint();
0343:                    valueCon.src = linkTable;
0344:                    valueCon.srcCols = valueColumns;
0345:                    valueCon.dest = ((JdbcClass) fmd.elementTypeMetaData.storeClass).table;
0346:                    valueCon.name = valueConstraintName;
0347:                    constraints.add(valueCon);
0348:                }
0349:
0350:                return constraints;
0351:            }
0352:
0353:            /**
0354:             * Get our extensions or null if none.
0355:             */
0356:            private JdoExtension[] getExtensions() {
0357:                switch (fmd.category) {
0358:                case MDStatics.CATEGORY_ARRAY:
0359:                    if (fmd.jdoArray != null)
0360:                        return fmd.jdoArray.extensions;
0361:                    return null;
0362:                case MDStatics.CATEGORY_COLLECTION:
0363:                    if (fmd.jdoCollection != null)
0364:                        return fmd.jdoCollection.extensions;
0365:                    return null;
0366:                case MDStatics.CATEGORY_MAP:
0367:                    if (fmd.jdoMap != null)
0368:                        return fmd.jdoMap.extensions;
0369:                    return null;
0370:                }
0371:                throw BindingSupportImpl.getInstance().internal(
0372:                        "invalid category: " + fmd.category);
0373:            }
0374:
0375:            /**
0376:             * Set the PK of the link table.
0377:             */
0378:            protected void createLinkTablePK() {
0379:                if (sequenceColumn != null) {
0380:                    linkTable.setPk(JdbcColumn.concat(ourPkColumns,
0381:                            sequenceColumn));
0382:                } else {
0383:                    linkTable.setPk(JdbcColumn.concat(ourPkColumns,
0384:                            valueColumns));
0385:                }
0386:            }
0387:
0388:            /**
0389:             * Name the key and value columns.
0390:             */
0391:            protected void nameKeyAndValueColumns(JdbcNameGenerator namegen,
0392:                    String linkTableNameForNamegen) {
0393:                // name the value column(s)
0394:                if (valuesAreOIDs) {
0395:                    String[] valuePkNames = JdbcColumn
0396:                            .getColumnNames(((JdbcClass) fmd.elementTypeMetaData.storeClass).table.pk);
0397:                    String[] linkValueRefNames = JdbcColumn
0398:                            .getColumnNames(valueColumns);
0399:                    namegen
0400:                            .generateLinkTableValueRefNames(
0401:                                    linkTableNameForNamegen, valuePkNames,
0402:                                    fmd.elementType.getName(),
0403:                                    linkValueRefNames, false);
0404:                    JdbcColumn.setColumnNames(valueColumns, linkValueRefNames);
0405:                } else {
0406:                    JdbcColumn c = valueColumns[0];
0407:                    if (c.name == null) {
0408:                        c.name = namegen
0409:                                .generateLinkTableValueName(
0410:                                        linkTableNameForNamegen,
0411:                                        fmd.elementType, false);
0412:                    }
0413:                }
0414:            }
0415:
0416:            /**
0417:             * Complete the key and value column related meta data.
0418:             */
0419:            protected void completeKeyAndValueColumnMetaData(
0420:                    JdbcClass jdbcClass, ArrayList cols, JdoElement context,
0421:                    JdoExtension[] linkNested, JdbcMetaDataBuilder mdb,
0422:                    boolean quiet) {
0423:
0424:                // create the value column(s)
0425:                JdoExtension ext = JdoExtension.find(
0426:                        JdoExtensionKeys.JDBC_VALUE, linkNested);
0427:                if (fmd.elementTypeMetaData != null) { // values are OIDs
0428:                    JdbcRefMetaDataBuilder rdb = new JdbcRefMetaDataBuilder(
0429:                            fmd.classMetaData, mdb, fmd.elementTypeMetaData,
0430:                            context, JdbcMetaDataBuilder.VALUE_FIELDNAME,
0431:                            ext == null ? null : ext.nested, quiet);
0432:                    createValueConstraint = !rdb.isDoNotCreateConstraint();
0433:                    valueConstraintName = rdb.getConstraintName();
0434:                    valueColumns = rdb.getCols();
0435:                    cols.addAll(rdb.getColsList());
0436:                } else {
0437:                    if (fmd.elementType == Object.class) {
0438:                        if (fmd.classMetaData.jmd.testing) {
0439:                            fmd.setElementType(String.class); // fudge so things work
0440:                        } else {
0441:                            throw BindingSupportImpl
0442:                                    .getInstance()
0443:                                    .runtime(
0444:                                            "You must specify the element-type (or value-type for maps) "
0445:                                                    + "for collections (and maps)\n"
0446:                                                    + fmd + "\n"
0447:                                                    + context.getContext());
0448:                        }
0449:                    }
0450:
0451:                    JdbcColumn vc = null;
0452:                    if (fmd.category == MDStatics.CATEGORY_COLLECTION) {
0453:                        vc = mdb.createColumn(ext == null ? null : ext.nested,
0454:                                JdbcMetaDataBuilder.VALUE_FIELDNAME,
0455:                                fmd.elementType);
0456:                    } else if (fmd.category == MDStatics.CATEGORY_ARRAY) {
0457:                        vc = mdb.createColumn(ext == null ? null : ext.nested,
0458:                                JdbcMetaDataBuilder.VALUE_FIELDNAME,
0459:                                fmd.elementType);
0460:                        if (Debug.DEBUG) {
0461:                            if (fmd.componentType != fmd.elementType) {
0462:                                throw new RuntimeException();
0463:                            }
0464:                        }
0465:                    } else if (fmd.category == MDStatics.CATEGORY_MAP) {
0466:                        vc = mdb.createColumn(ext == null ? null : ext.nested,
0467:                                JdbcMetaDataBuilder.VALUE_FIELDNAME,
0468:                                fmd.elementType);
0469:                    } else {
0470:                        throw BindingSupportImpl.getInstance().internal("");
0471:                    }
0472:
0473:                    valueColumns = new JdbcColumn[] { vc };
0474:                    cols.add(vc);
0475:                }
0476:
0477:                //update allowNulls
0478:                boolean nulls = allowNulls();
0479:                for (int i = 0; i < valueColumns.length; i++) {
0480:                    JdbcColumn valueColumn = valueColumns[i];
0481:                    valueColumn.setNulls(nulls);
0482:                }
0483:            }
0484:
0485:            /**
0486:             * Name our linkTable.
0487:             */
0488:            protected void nameLinkTable(JdbcNameGenerator namegen,
0489:                    JdbcClass jdbcClass) {
0490:                JdbcClass valueTarget = null;
0491:                if (valuesAreOIDs)
0492:                    valueTarget = (JdbcClass) fmd.elementTypeMetaData.storeClass;
0493:                linkTable.name = namegen.generateLinkTableName(
0494:                        jdbcClass.table.name, fmd.name,
0495:                        valueTarget == null ? null : valueTarget.table.name);
0496:            }
0497:
0498:            /**
0499:             * Persist pass 2 field for a block of graph entries all with
0500:             * the same class. The same ps'es can be used for all entries in the block.
0501:             */
0502:            public void persistPass2Block(PersistGraph graph, int blockStart,
0503:                    int blockEnd, CharBuf s, Connection con,
0504:                    boolean batchInserts, boolean batchUpdates)
0505:                    throws SQLException {
0506:                if (Debug.DEBUG) {
0507:                    if (readOnly) {
0508:                        for (int pos = blockStart; pos < blockEnd; pos++) {
0509:                            State ns = graph.getNewState(pos);
0510:                            if (ns.getInternalObjectField(stateFieldNo) != null) {
0511:                                throw BindingSupportImpl.getInstance()
0512:                                        .internal("readOnly field in ns");
0513:                            }
0514:                        }
0515:                    }
0516:                }
0517:                if (readOnly)
0518:                    return;
0519:                if (fmd.ordered) {
0520:                    persistPass2BlockOrdered(graph, blockStart, blockEnd, s,
0521:                            con, batchInserts, batchUpdates);
0522:                } else {
0523:                    persistPass2BlockUnordered(graph, blockStart, blockEnd, s,
0524:                            con, batchInserts, batchUpdates);
0525:                }
0526:            }
0527:
0528:            private void persistPass2BlockOrdered(PersistGraph graph,
0529:                    int blockStart, int blockEnd, CharBuf s, Connection con,
0530:                    boolean batchInserts, boolean batchUpdates)
0531:                    throws SQLException {
0532:                PreparedStatement psdel = null;
0533:                PreparedStatement psdelAll = null;
0534:                PreparedStatement psins = null;
0535:                int delCount = 0;
0536:                try {
0537:                    String psdelSql = null;
0538:                    String psdelAllSql = null;
0539:                    String psinsSql = null;
0540:                    for (int pos = blockStart; pos < blockEnd; pos++) {
0541:                        State ns = graph.getNewState(pos);
0542:                        if (!ns.containsField(stateFieldNo))
0543:                            continue;
0544:
0545:                        OID oid = graph.getOID(pos);
0546:                        if (fmd.category == MDStatics.CATEGORY_ARRAY) {
0547:                            if (!oid.isNew()) {
0548:                                //delete the current entries
0549:                                if (psdelAll == null) {
0550:                                    psdelAllSql = getDeleteAllLinkTableRowsSql(s);
0551:                                    psdelAll = con
0552:                                            .prepareStatement(psdelAllSql);
0553:                                }
0554:                                ((JdbcOID) oid).setParams(psdelAll, 1);
0555:                                if (batchUpdates) {
0556:                                    psdelAll.addBatch();
0557:                                } else {
0558:                                    try {
0559:                                        psdelAll.execute();
0560:                                    } catch (Exception e) {
0561:                                        throw mapException(
0562:                                                e,
0563:                                                "Delete all link table rows failed: "
0564:                                                        + JdbcUtils.toString(e)
0565:                                                        + "\n"
0566:                                                        + "Field: "
0567:                                                        + fmd.getTypeQName()
0568:                                                        + "\n"
0569:                                                        + "Instance: "
0570:                                                        + oid.toSString()
0571:                                                        + "\n"
0572:                                                        + JdbcUtils
0573:                                                                .getPreparedStatementInfo(
0574:                                                                        psdelAllSql,
0575:                                                                        psdelAll));
0576:                                    }
0577:                                }
0578:                            }
0579:
0580:                            Object toInsert = ns
0581:                                    .getInternalObjectField(stateFieldNo);
0582:                            if (toInsert != null) {
0583:                                if (psins == null) {
0584:                                    psinsSql = getInsertLinkTableRowSql(s);
0585:                                    psins = con.prepareStatement(psinsSql);
0586:                                }
0587:
0588:                                if (fmd.componentType.isPrimitive()) {
0589:                                    //throw not supported
0590:                                    throw BindingSupportImpl.getInstance()
0591:                                            .unsupported();
0592:                                } else {
0593:                                    insertOrderedLinkTableRows(oid, null,
0594:                                            toInsert, psins, batchInserts,
0595:                                            psinsSql);
0596:                                }
0597:                            }
0598:
0599:                        } else {
0600:                            OrderedCollectionDiff diff = (OrderedCollectionDiff) ns
0601:                                    .getInternalObjectField(stateFieldNo);
0602:                            if (diff == null
0603:                                    || diff.status == CollectionDiff.STATUS_NEW) {
0604:                                if (!oid.isNew()) {
0605:                                    if (psdelAll == null) {
0606:                                        psdelAllSql = getDeleteAllLinkTableRowsSql(s);
0607:                                        psdelAll = con
0608:                                                .prepareStatement(psdelAllSql);
0609:                                    }
0610:                                    ((JdbcOID) oid).setParams(psdelAll, 1);
0611:                                    if (batchUpdates) {
0612:                                        psdelAll.addBatch();
0613:                                    } else {
0614:                                        try {
0615:                                            psdelAll.execute();
0616:                                        } catch (Exception e) {
0617:                                            throw mapException(
0618:                                                    e,
0619:                                                    "Delete all link table rows failed: "
0620:                                                            + JdbcUtils
0621:                                                                    .toString(e)
0622:                                                            + "\n"
0623:                                                            + "Field: "
0624:                                                            + fmd
0625:                                                                    .getTypeQName()
0626:                                                            + "\n"
0627:                                                            + "Instance: "
0628:                                                            + oid.toSString()
0629:                                                            + "\n"
0630:                                                            + JdbcUtils
0631:                                                                    .getPreparedStatementInfo(
0632:                                                                            psdelAllSql,
0633:                                                                            psdelAll));
0634:                                        }
0635:                                    }
0636:                                }
0637:                            } else {
0638:                                int[] deleted = diff.deletedIndexes;
0639:                                if (deleted != null && deleted.length > 0) {
0640:                                    if (psdel == null) {
0641:                                        psdelSql = getDeleteLinkTableRowSql(s);
0642:                                        psdel = con.prepareStatement(psdelSql);
0643:                                    }
0644:                                    deletedOrderedLinkTableRows(oid, deleted,
0645:                                            psdel, batchUpdates, psdelSql);
0646:                                    delCount += deleted.length;
0647:                                }
0648:                            }
0649:
0650:                            if (diff != null) {
0651:                                Object[] insertedValues = diff.insertedValues;
0652:                                if (insertedValues != null
0653:                                        && insertedValues.length > 0) {
0654:                                    if (psins == null) {
0655:                                        psinsSql = getInsertLinkTableRowSql(s);
0656:                                        psins = con.prepareStatement(psinsSql);
0657:                                    }
0658:                                    insertOrderedLinkTableRows(oid,
0659:                                            diff.insertedIndexes,
0660:                                            insertedValues, psins,
0661:                                            batchInserts, psinsSql);
0662:                                }
0663:                            }
0664:                        }
0665:                    }
0666:                    if (batchUpdates) {
0667:                        execLinkTableBatchDeletes(delCount, psdel, psdelSql,
0668:                                psdelAll, psdelAllSql);
0669:                    }
0670:                    if (batchInserts && psins != null) {
0671:                        execLinkTableBatchInserts(psins, psinsSql);
0672:                    }
0673:                } finally {
0674:                    cleanup(psdel);
0675:                    cleanup(psdelAll);
0676:                    cleanup(psins);
0677:                }
0678:            }
0679:
0680:            protected void execLinkTableBatchInserts(PreparedStatement psins,
0681:                    String psinsSql) {
0682:                try {
0683:                    psins.executeBatch();
0684:                } catch (SQLException e) {
0685:                    throw mapException(e, "Link table batch insert failed: "
0686:                            + JdbcUtils.toString(e)
0687:                            + "\n"
0688:                            + "Field: "
0689:                            + fmd.getTypeQName()
0690:                            + "\n"
0691:                            + JdbcUtils.getPreparedStatementInfo(psinsSql,
0692:                                    psins));
0693:                }
0694:            }
0695:
0696:            protected void execLinkTableBatchDeletes(int delCount,
0697:                    PreparedStatement psdel, String psdelSql,
0698:                    PreparedStatement psdelAll, String psdelAllSql) {
0699:                if (delCount > 0) {
0700:                    int[] a;
0701:                    try {
0702:                        a = psdel.executeBatch();
0703:                    } catch (Exception e) {
0704:                        throw mapException(e,
0705:                                "Link table batch delete failed: "
0706:                                        + JdbcUtils.toString(e)
0707:                                        + "\n"
0708:                                        + "Field: "
0709:                                        + fmd.getTypeQName()
0710:                                        + "\n"
0711:                                        + JdbcUtils.getPreparedStatementInfo(
0712:                                                psdelSql, psdel));
0713:                    }
0714:                    for (int i = 0; i < delCount; i++) {
0715:                        int c = a[i];
0716:                        if (c <= 0) {
0717:                            String psi = JdbcUtils.getPreparedStatementInfo(
0718:                                    psdelSql, psdel, i);
0719:                            if (c == 0) {
0720:                                throw BindingSupportImpl.getInstance()
0721:                                        .concurrentUpdate(
0722:                                                "Link table row not found on batch delete: "
0723:                                                        + "Field: "
0724:                                                        + fmd.getTypeQName()
0725:                                                        + "\n" + psi, null);
0726:                            }
0727:                            throw BindingSupportImpl.getInstance().datastore(
0728:                                    "Unexpected update count for link table row batch delete: "
0729:                                            + c + "\nField: "
0730:                                            + fmd.getTypeQName() + "\n" + psi);
0731:                        }
0732:                    }
0733:                }
0734:                if (psdelAll != null) {
0735:                    try {
0736:                        psdelAll.executeBatch();
0737:                    } catch (Exception e) {
0738:                        throw mapException(e,
0739:                                "Link table batch delete all failed: "
0740:                                        + JdbcUtils.toString(e)
0741:                                        + "\n"
0742:                                        + "Field: "
0743:                                        + fmd.getTypeQName()
0744:                                        + "\n"
0745:                                        + JdbcUtils.getPreparedStatementInfo(
0746:                                                psdelAllSql, psdelAll));
0747:                    }
0748:                }
0749:            }
0750:
0751:            /**
0752:             * Delete rows from an ordered link table.
0753:             */
0754:            private void deletedOrderedLinkTableRows(OID oid, int[] deleted,
0755:                    PreparedStatement psdel, boolean batch, String sql)
0756:                    throws SQLException {
0757:                JdbcColumn sc = sequenceColumn;
0758:                for (int j = deleted.length - 1; j >= 0; j--) {
0759:                    int pp = ((JdbcOID) oid).setParams(psdel, 1);
0760:                    sc.set(psdel, pp, deleted[j]);
0761:                    if (batch) {
0762:                        psdel.addBatch();
0763:                    } else {
0764:                        int uc;
0765:                        try {
0766:                            uc = psdel.executeUpdate();
0767:                        } catch (Exception e) {
0768:                            throw mapException(e,
0769:                                    "Delete link table row failed: "
0770:                                            + JdbcUtils.toString(e)
0771:                                            + "\n"
0772:                                            + "Field: "
0773:                                            + fmd.getTypeQName()
0774:                                            + "\n"
0775:                                            + "Sequence: "
0776:                                            + deleted[j]
0777:                                            + "\n"
0778:                                            + "Instance: "
0779:                                            + oid.toSString()
0780:                                            + "\n"
0781:                                            + JdbcUtils
0782:                                                    .getPreparedStatementInfo(
0783:                                                            sql, psdel));
0784:                        }
0785:                        if (uc == 0) {
0786:                            throw BindingSupportImpl
0787:                                    .getInstance()
0788:                                    .concurrentUpdate(
0789:                                            "Link table row not found: "
0790:                                                    + "Field: "
0791:                                                    + fmd.getTypeQName()
0792:                                                    + "\n"
0793:                                                    + "Sequence: "
0794:                                                    + deleted[j]
0795:                                                    + "\n"
0796:                                                    + "Instance: "
0797:                                                    + oid.toSString()
0798:                                                    + "\n"
0799:                                                    + JdbcUtils
0800:                                                            .getPreparedStatementInfo(
0801:                                                                    sql, psdel),
0802:                                            oid);
0803:                        }
0804:                    }
0805:                }
0806:            }
0807:
0808:            /**
0809:             * Insert values into an ordered link table.
0810:             */
0811:            private void insertOrderedLinkTableRows(OID oid,
0812:                    int[] insertedIndexes, Object _insertedValues,
0813:                    PreparedStatement psins, boolean batch, String sql)
0814:                    throws SQLException {
0815:
0816:                Object[] insertedValues = (Object[]) _insertedValues;
0817:                int ilen = insertedValues.length;
0818:
0819:                if (valuesAreOIDs) {
0820:                    for (int j = 0; j < ilen; j++) {
0821:                        int pp = ((JdbcOID) oid).setParams(psins, 1);
0822:                        sequenceColumn.set(psins, pp++,
0823:                                insertedIndexes == null ? j
0824:                                        : insertedIndexes[j]);
0825:
0826:                        OID _oid = (OID) insertedValues[j];
0827:
0828:                        if (_oid != null) {
0829:                            ((JdbcOID) _oid).setParams(psins, pp);
0830:                        } else {
0831:                            JdbcGenericOID.setNullParams(psins, pp,
0832:                                    fmd.elementTypeMetaData);
0833:                        }
0834:                        if (batch) {
0835:                            psins.addBatch();
0836:                        } else {
0837:                            try {
0838:                                psins.execute();
0839:                            } catch (Exception e) {
0840:                                throw mapException(
0841:                                        e,
0842:                                        "Insert link table row failed: "
0843:                                                + JdbcUtils.toString(e)
0844:                                                + "\n"
0845:                                                + "Field: "
0846:                                                + fmd.getTypeQName()
0847:                                                + "\n"
0848:                                                + "Instance: "
0849:                                                + oid.toSString()
0850:                                                + "\n"
0851:                                                + "Link table value[sequence "
0852:                                                + insertedIndexes[j]
0853:                                                + "]: "
0854:                                                + _oid.toSString()
0855:                                                + "\n"
0856:                                                + JdbcUtils
0857:                                                        .getPreparedStatementInfo(
0858:                                                                sql, psins));
0859:                            }
0860:                        }
0861:                    }
0862:                } else {
0863:                    JdbcColumn vc = valueColumns[0];
0864:                    for (int j = 0; j < ilen; j++) {
0865:                        int pp = ((JdbcOID) oid).setParams(psins, 1);
0866:                        sequenceColumn.set(psins, pp++,
0867:                                insertedIndexes == null ? j
0868:                                        : insertedIndexes[j]);
0869:
0870:                        vc.set(psins, pp, insertedValues[j]);
0871:
0872:                        if (batch) {
0873:                            psins.addBatch();
0874:                        } else {
0875:                            try {
0876:                                psins.execute();
0877:                            } catch (Exception e) {
0878:                                throw mapException(
0879:                                        e,
0880:                                        "Insert link table row failed: "
0881:                                                + JdbcUtils.toString(e)
0882:                                                + "\n"
0883:                                                + "Field: "
0884:                                                + fmd.getTypeQName()
0885:                                                + "\n"
0886:                                                + "Instance: "
0887:                                                + oid.toSString()
0888:                                                + "\n"
0889:                                                + "Link table value[sequence "
0890:                                                + insertedIndexes[j]
0891:                                                + "]: "
0892:                                                +
0893:
0894:                                                Utils
0895:                                                        .toString(insertedValues[j])
0896:                                                + "\n"
0897:                                                +
0898:
0899:                                                JdbcUtils
0900:                                                        .getPreparedStatementInfo(
0901:                                                                sql, psins));
0902:                            }
0903:                        }
0904:                    }
0905:                }
0906:            }
0907:
0908:            private void persistPass2BlockUnordered(PersistGraph graph,
0909:                    int blockStart, int blockEnd, CharBuf s, Connection con,
0910:                    boolean batchInserts, boolean batchUpdates)
0911:                    throws SQLException {
0912:                PreparedStatement psdel = null;
0913:                PreparedStatement psdelAll = null;
0914:                PreparedStatement psins = null;
0915:                int delCount = 0;
0916:                try {
0917:                    String psdelSql = null;
0918:                    String psdelAllSql = null;
0919:                    String psinsSql = null;
0920:                    for (int pos = blockStart; pos < blockEnd; pos++) {
0921:                        State ns = graph.getNewState(pos);
0922:                        if (!ns.containsField(stateFieldNo))
0923:                            continue;
0924:
0925:                        UnorderedCollectionDiff diff = (UnorderedCollectionDiff) ns
0926:                                .getInternalObjectField(stateFieldNo);
0927:
0928:                        OID oid = graph.getOID(pos);
0929:
0930:                        if (diff == null
0931:                                || diff.status == CollectionDiff.STATUS_NEW) {
0932:                            if (!oid.isNew()) {
0933:                                if (psdelAll == null) {
0934:                                    psdelAllSql = getDeleteAllLinkTableRowsSql(s);
0935:                                    psdelAll = con
0936:                                            .prepareStatement(psdelAllSql);
0937:                                }
0938:                                ((JdbcOID) oid).setParams(psdelAll, 1);
0939:                                if (batchUpdates) {
0940:                                    psdelAll.addBatch();
0941:                                } else {
0942:                                    try {
0943:                                        psdelAll.execute();
0944:                                    } catch (Exception e) {
0945:                                        throw mapException(
0946:                                                e,
0947:                                                "Delete all link table rows failed: "
0948:                                                        + JdbcUtils.toString(e)
0949:                                                        + "\n"
0950:                                                        + "Field: "
0951:                                                        + fmd.getTypeQName()
0952:                                                        + "\n"
0953:                                                        + "Instance: "
0954:                                                        + oid.toSString()
0955:                                                        + "\n"
0956:                                                        + JdbcUtils
0957:                                                                .getPreparedStatementInfo(
0958:                                                                        psdelAllSql,
0959:                                                                        psdelAll));
0960:                                    }
0961:                                }
0962:                            }
0963:                        } else {
0964:                            Object[] deleted = diff.deletedValues;
0965:                            if (deleted != null && deleted.length > 0) {
0966:                                if (psdel == null) {
0967:                                    psdelSql = getDeleteLinkTableRowSql(s);
0968:                                    psdel = con.prepareStatement(psdelSql);
0969:                                }
0970:                                deleteUnorderedLinkTableRows(oid, deleted,
0971:                                        psdel, batchUpdates, psdelSql);
0972:                                delCount += deleted.length;
0973:                            }
0974:                        }
0975:
0976:                        if (diff != null) {
0977:                            Object[] inserted = diff.insertedValues;
0978:                            if (inserted != null && inserted.length > 0) {
0979:                                if (psins == null) {
0980:                                    psinsSql = getInsertLinkTableRowSql(s);
0981:                                    psins = con.prepareStatement(psinsSql);
0982:                                }
0983:                                insertUnorderedLinkTableRows(oid, inserted,
0984:                                        psins, batchInserts, psinsSql);
0985:                            }
0986:                        }
0987:                    }
0988:                    if (batchUpdates) {
0989:                        execLinkTableBatchDeletes(delCount, psdel, psdelSql,
0990:                                psdelAll, psdelAllSql);
0991:                    }
0992:                    if (batchInserts && psins != null) {
0993:                        execLinkTableBatchInserts(psins, psinsSql);
0994:                    }
0995:                } finally {
0996:                    cleanup(psdel);
0997:                    cleanup(psdelAll);
0998:                    cleanup(psins);
0999:                }
1000:            }
1001:
1002:            /**
1003:             * Delete values from an unordered link table.
1004:             */
1005:            private void deleteUnorderedLinkTableRows(OID oid,
1006:                    Object[] deleted, PreparedStatement psdel, boolean batch,
1007:                    String sql) throws SQLException {
1008:                if (valuesAreOIDs) {
1009:                    for (int j = deleted.length - 1; j >= 0; j--) {
1010:                        int pp = ((JdbcOID) oid).setParams(psdel, 1);
1011:                        ((JdbcOID) deleted[j]).setParams(psdel, pp);
1012:                        if (batch) {
1013:                            psdel.addBatch();
1014:                        } else {
1015:                            int uc;
1016:                            try {
1017:                                uc = psdel.executeUpdate();
1018:                            } catch (Exception e) {
1019:                                throw mapException(
1020:                                        e,
1021:                                        "Delete link table row failed: "
1022:                                                + JdbcUtils.toString(e)
1023:                                                + "\n"
1024:                                                + "Field: "
1025:                                                + fmd.getTypeQName()
1026:                                                + "\n"
1027:                                                + "Value: "
1028:                                                + ((OID) deleted[j])
1029:                                                        .toSString()
1030:                                                + "\n"
1031:                                                + "Instance: "
1032:                                                + oid.toSString()
1033:                                                + "\n"
1034:                                                + JdbcUtils
1035:                                                        .getPreparedStatementInfo(
1036:                                                                sql, psdel));
1037:                            }
1038:                            if (uc == 0) {
1039:                                throw BindingSupportImpl
1040:                                        .getInstance()
1041:                                        .concurrentUpdate(
1042:                                                "Link table row not found: "
1043:                                                        + "Field: "
1044:                                                        + fmd.getTypeQName()
1045:                                                        + "\n"
1046:                                                        + "Value: "
1047:                                                        + ((OID) deleted[j])
1048:                                                                .toSString()
1049:                                                        + "\n"
1050:                                                        + "Instance: "
1051:                                                        + oid.toSString()
1052:                                                        + "\n"
1053:                                                        + JdbcUtils
1054:                                                                .getPreparedStatementInfo(
1055:                                                                        sql,
1056:                                                                        psdel),
1057:                                                deleted[j]);
1058:                            }
1059:                        }
1060:                    }
1061:                } else {
1062:                    JdbcColumn vc = valueColumns[0];
1063:                    for (int j = deleted.length - 1; j >= 0; j--) {
1064:                        int pp = ((JdbcOID) oid).setParams(psdel, 1);
1065:                        vc.set(psdel, pp, deleted[j]);
1066:                        if (batch) {
1067:                            psdel.addBatch();
1068:                        } else {
1069:                            int uc;
1070:                            try {
1071:                                uc = psdel.executeUpdate();
1072:                            } catch (Exception e) {
1073:                                throw mapException(
1074:                                        e,
1075:                                        "Delete link table row failed: "
1076:                                                + JdbcUtils.toString(e)
1077:                                                + "\n"
1078:                                                + "Field: "
1079:                                                + fmd.getTypeQName()
1080:                                                + "\n"
1081:                                                + "Value: "
1082:                                                + Utils.toString(deleted[j])
1083:                                                + "\n"
1084:                                                + "Instance: "
1085:                                                + oid.toSString()
1086:                                                + "\n"
1087:                                                + JdbcUtils
1088:                                                        .getPreparedStatementInfo(
1089:                                                                sql, psdel));
1090:                            }
1091:                            if (uc == 0) {
1092:                                throw BindingSupportImpl
1093:                                        .getInstance()
1094:                                        .concurrentUpdate(
1095:                                                "Link table row not found: "
1096:                                                        + "Field: "
1097:                                                        + fmd.getTypeQName()
1098:                                                        + "\n"
1099:                                                        + "Value: "
1100:                                                        + Utils
1101:                                                                .toString(deleted[j])
1102:                                                        + "\n"
1103:                                                        + "Instance: "
1104:                                                        + oid.toSString()
1105:                                                        + "\n"
1106:                                                        + JdbcUtils
1107:                                                                .getPreparedStatementInfo(
1108:                                                                        sql,
1109:                                                                        psdel),
1110:                                                oid);
1111:                            }
1112:                        }
1113:                    }
1114:                }
1115:            }
1116:
1117:            /**
1118:             * Insert values into an unordered link table.
1119:             */
1120:            private void insertUnorderedLinkTableRows(OID oid,
1121:                    Object[] inserted, PreparedStatement psins, boolean batch,
1122:                    String sql) throws SQLException {
1123:                int ilen = inserted.length;
1124:                if (valuesAreOIDs) {
1125:                    for (int j = 0; j < ilen; j++) {
1126:                        int pp = ((JdbcOID) oid).setParams(psins, 1);
1127:                        ((JdbcOID) inserted[j]).setParams(psins, pp);
1128:                        if (batch) {
1129:                            psins.addBatch();
1130:                        } else {
1131:                            try {
1132:                                psins.execute();
1133:                            } catch (Exception e) {
1134:                                throw mapException(
1135:                                        e,
1136:                                        "Insert link table row failed: "
1137:                                                + JdbcUtils.toString(e)
1138:                                                + "\n"
1139:                                                + "Field: "
1140:                                                + fmd.getTypeQName()
1141:                                                + "\n"
1142:                                                + "Instance: "
1143:                                                + oid.toSString()
1144:                                                + "\n"
1145:                                                + "Value: "
1146:                                                + ((OID) inserted[j])
1147:                                                        .toSString()
1148:                                                + "\n"
1149:                                                + JdbcUtils
1150:                                                        .getPreparedStatementInfo(
1151:                                                                sql, psins));
1152:                            }
1153:                        }
1154:                    }
1155:                } else {
1156:                    JdbcColumn vc = valueColumns[0];
1157:                    for (int j = 0; j < ilen; j++) {
1158:                        int pp = ((JdbcOID) oid).setParams(psins, 1);
1159:                        vc.set(psins, pp, inserted[j]);
1160:                        if (batch) {
1161:                            psins.addBatch();
1162:                        } else {
1163:                            try {
1164:                                psins.execute();
1165:                            } catch (Exception e) {
1166:                                throw mapException(
1167:                                        e,
1168:                                        "Insert link table row failed: "
1169:                                                + JdbcUtils.toString(e)
1170:                                                + "\n"
1171:                                                + "Field: "
1172:                                                + fmd.getTypeQName()
1173:                                                + "\n"
1174:                                                + "Instance: "
1175:                                                + oid.toSString()
1176:                                                + "\n"
1177:                                                + "Value: "
1178:                                                + Utils.toString(inserted[j])
1179:                                                + "\n"
1180:                                                + JdbcUtils
1181:                                                        .getPreparedStatementInfo(
1182:                                                                sql, psins));
1183:                            }
1184:                        }
1185:                    }
1186:                }
1187:            }
1188:
1189:            /**
1190:             * Get SQL to delete a row from our link table.
1191:             */
1192:            protected String getDeleteLinkTableRowSql(CharBuf s) {
1193:                if (deleteRowSql == null) {
1194:                    s.clear();
1195:                    s.append("delete from ");
1196:                    s.append(linkTable.name);
1197:                    s.append(" where ");
1198:                    linkTable.appendWherePK(s);
1199:                    deleteRowSql = s.toString();
1200:                }
1201:                return deleteRowSql;
1202:            }
1203:
1204:            /**
1205:             * Get SQL to delete all rows from our link table.
1206:             */
1207:            protected String getDeleteAllLinkTableRowsSql(CharBuf s) {
1208:                if (deleteAllRowsSql == null) {
1209:                    s.clear();
1210:                    s.append("DELETE FROM ");
1211:                    s.append(linkTable.name);
1212:                    s.append(" WHERE ");
1213:                    SqlDriver driver = linkTable.sqlDriver;
1214:                    int nc = ourPkColumns.length;
1215:                    JdbcColumn sc = ourPkColumns[0];
1216:                    s.append(sc.name);
1217:                    s.append(' ');
1218:                    s.append('=');
1219:                    s.append(' ');
1220:                    driver.appendWhereParam(s, sc);
1221:                    for (int i = 1; i < nc; i++) {
1222:                        s.append(" AND ");
1223:                        sc = ourPkColumns[i];
1224:                        s.append(sc.name);
1225:                        s.append(' ');
1226:                        s.append('=');
1227:                        s.append(' ');
1228:                        driver.appendWhereParam(s, sc);
1229:                    }
1230:                    deleteAllRowsSql = s.toString();
1231:                }
1232:                return deleteAllRowsSql;
1233:            }
1234:
1235:            /**
1236:             * Get SQL to delete all rows from our link table with a 'IN' List. This is only
1237:             * supported if there is a single pk column.
1238:             */
1239:            protected void getDeleteAllLinkTableRowsSqlWithInList(CharBuf s) {
1240:                s.clear();
1241:                s.append("delete from ");
1242:                s.append(linkTable.name);
1243:                s.append(" where ");
1244:                JdbcColumn sc = ourPkColumns[0];
1245:                s.append(sc.name);
1246:                s.append(" IN (");
1247:            }
1248:
1249:            /**
1250:             * Get SQL to insert a row into our link table.
1251:             */
1252:            public String getInsertLinkTableRowSql(CharBuf s) {
1253:                if (insertRowSql == null) {
1254:                    s.clear();
1255:                    s.append("INSERT INTO ");
1256:                    s.append(linkTable.name);
1257:                    s.append('(');
1258:                    linkTable.appendInsertColumnList(s);
1259:                    s.append(") VALUES (");
1260:                    linkTable.appendInsertValueList(s);
1261:                    s.append(')');
1262:                    insertRowSql = s.toString();
1263:                }
1264:                return insertRowSql;
1265:            }
1266:
1267:            /**
1268:             * if null is allowed by default for this collection.
1269:             */
1270:            private boolean allowNulls() {
1271:                return fmd.ordered || fmd.category == MDStatics.CATEGORY_MAP;
1272:            }
1273:
1274:            /**
1275:             * Get a SelectExp to select all the rows in this collection using the
1276:             * supplied fetch group field to control joins and so on.
1277:             */
1278:            protected SelectExp getSelectExp(JdbcStorageManager sm,
1279:                    FetchGroupField field, FgDs[] fgDses) {
1280:                SelectExp root = new SelectExp();
1281:                root.table = linkTable;
1282:                root.selectList = JdbcColumn.toSqlExp(valueColumns, root);
1283:                root.whereExp = JdbcColumn.createEqualsParamExp(ourPkColumns,
1284:                        root);
1285:
1286:                if (valuesAreOIDs) {
1287:                    if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO
1288:                            || fmd.ordering != null) {
1289:                        SelectExp se = new SelectExp();
1290:                        JdbcClass valueJdbcClass = (JdbcClass) fmd.elementTypeMetaData.storeClass;
1291:                        se.table = valueJdbcClass.table;
1292:                        se.outer = field.jdbcUseJoin != JdbcField.USE_JOIN_INNER;
1293:
1294:                        root.addJoin(valueColumns, se.table.pk, se);
1295:                        sm
1296:                                .addSelectFetchGroup(
1297:                                        se,
1298:                                        field.nextFetchGroup,
1299:                                        true,
1300:                                        fgDses[0] = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
1301:                                                .getFgDs(
1302:                                                        true,
1303:                                                        field.jdbcUseJoin != JdbcField.USE_JOIN_INNER),
1304:                                        root, valueColumns, this );
1305:
1306:                        if (fmd.ordering != null) {
1307:                            se.addOrderBy(fmd.ordering, false);
1308:                            root.orderByList = se.orderByList;
1309:                            se.orderByList = null;
1310:                        }
1311:                    }
1312:                } else {
1313:                    if (fmd.ordering != null) {
1314:                        // the ordering can only be 'this ascending' or 'this descending'
1315:                        boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING;
1316:                        root.orderByList = new OrderExp(valueColumns[0]
1317:                                .toSqlExp(root), desc);
1318:                        // there will be only one entry in valueColumns as this is
1319:                        // not a collection of PC instances
1320:                    }
1321:                }
1322:                if (fmd.ordered) {
1323:                    if (fmd.ordering != null) {
1324:                        throw BindingSupportImpl.getInstance().internal(
1325:                                "ordered == true && ordering != null, "
1326:                                        + fmd.getTypeQName());
1327:                    }
1328:                    root.orderByList = linkTable.createOrderByPKList(root);
1329:                }
1330:                return root;
1331:            }
1332:
1333:            public SelectExp getSelectExpFrom(JdbcStorageManager sm,
1334:                    SelectExp joinToExp, FetchGroupField field, FgDs owningFgDs) {
1335:                SelectExp root = getSelectExpFromImp(joinToExp, field, sm,
1336:                        owningFgDs);
1337:                root.selectList = JdbcColumn.toSqlExp(ourPkColumns, root,
1338:                        root.selectList);
1339:                return root;
1340:            }
1341:
1342:            public SelectExp getSelectExpFromImp(SelectExp joinToExp,
1343:                    FetchGroupField field, JdbcStorageManager sm,
1344:                    FgDs owningFgDs) {
1345:                SelectExp root = new SelectExp();
1346:                root.table = linkTable;
1347:                root.selectList = JdbcColumn.toSqlExp(valueColumns, root);
1348:
1349:                if (valuesAreOIDs) {
1350:                    if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO
1351:                            || fmd.ordering != null) {
1352:                        SelectExp se = new SelectExp();
1353:                        JdbcClass valueJdbcClass = (JdbcClass) fmd.elementTypeMetaData.storeClass;
1354:                        se.table = valueJdbcClass.table;
1355:                        se.outer = true;
1356:
1357:                        root.addJoin(valueColumns, se.table.pk, se);
1358:                        FgDs fgDs = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
1359:                                .getFgDs(true, se.outer);
1360:                        sm.addSelectFetchGroup(se, field.nextFetchGroup, true,
1361:                                fgDs, root, valueColumns, this );
1362:                        owningFgDs.valueJs = fgDs.getJoinStruct();
1363:
1364:                        if (fmd.ordering != null) {
1365:                            se.addOrderBy(fmd.ordering, false);
1366:                            root.orderByList = se.orderByList;
1367:                            se.orderByList = null;
1368:                        }
1369:                    }
1370:                } else {
1371:                    if (fmd.ordering != null) {
1372:                        // the ordering can only be 'this ascending' or 'this descending'
1373:                        boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING;
1374:                        root.orderByList = new OrderExp(valueColumns[0]
1375:                                .toSqlExp(root), desc);
1376:                        // there will be only one entry in valueColumns as this is
1377:                        // not a collection of PC instances
1378:                    }
1379:                }
1380:                if (fmd.ordered) {
1381:                    if (fmd.ordering != null) {
1382:                        throw BindingSupportImpl.getInstance().internal(
1383:                                "ordered == true && ordering != null, "
1384:                                        + fmd.getTypeQName());
1385:                    }
1386:                    root.orderByList = linkTable.createOrderByPKList(root);
1387:                }
1388:
1389:                root.outer = true;
1390:                joinToExp.addJoin(joinToExp.table.pk, ourPkColumns, root);
1391:                joinToExp.appendOrderByExp(root.orderByList);
1392:                root.orderByList = null;
1393:                return root;
1394:            }
1395:
1396:            /**
1397:             * Get a SelectExp to select all the rows in this collection using the
1398:             * supplied fetch group field to control joins and so on.
1399:             */
1400:            public SelectExp getSelectFilterExp(JdbcStorageManager sm,
1401:                    FetchGroupField field, ColFieldHolder colFHolder) {
1402:                SelectExp root = new SelectExp();
1403:                root.table = linkTable;
1404:                root.selectList = JdbcColumn.toSqlExp(valueColumns, root);
1405:
1406:                // prepend our pk columns to the select list
1407:                SqlExp e = JdbcColumn.toSqlExp(ourPkColumns, root,
1408:                        root.selectList);
1409:                root.selectList = e;
1410:                root.appendOrderByForColumns(ourPkColumns);
1411:
1412:                if (valuesAreOIDs) {
1413:                    if (field.jdbcUseJoin != JdbcField.USE_JOIN_NO
1414:                            || fmd.ordering != null) {
1415:                        SelectExp se = new SelectExp();
1416:                        JdbcClass valueJdbcClass = (JdbcClass) fmd.elementTypeMetaData.storeClass;
1417:                        se.table = valueJdbcClass.table;
1418:                        se.outer = field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER;
1419:
1420:                        FgDs fgDs = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
1421:                                .getFgDs(true, se.outer);
1422:                        sm.addSelectFetchGroup(se, field.nextFetchGroup, true,
1423:                                fgDs, root, valueColumns, this );
1424:                        colFHolder.valueJs = fgDs.getJoinStruct();
1425:
1426:                        root.addJoin(valueColumns, se.table.pk, se);
1427:                        if (fmd.ordering != null) {
1428:                            se.addOrderBy(fmd.ordering, false);
1429:                            root.appendOrderByExp(se.orderByList);
1430:                            se.orderByList = null;
1431:                        }
1432:                    }
1433:                } else {
1434:                    if (fmd.ordering != null) {
1435:                        // the ordering can only be 'this ascending' or 'this descending'
1436:                        boolean desc = fmd.ordering[0].order == OrderNode.ORDER_DESCENDING;
1437:                        root.appendOrderByExp(new OrderExp(valueColumns[0]
1438:                                .toSqlExp(root), desc));
1439:                        // there will be only one entry in valueColumns as this is
1440:                        // not a collection of PC instances
1441:                    }
1442:                }
1443:                if (fmd.ordered) {
1444:                    if (fmd.ordering != null) {
1445:                        throw BindingSupportImpl.getInstance().internal(
1446:                                "ordered == true && ordering != null, "
1447:                                        + fmd.getTypeQName());
1448:                    }
1449:                    root.appendOrderByForColumns(linkTable.pkSimpleCols);
1450:                }
1451:                return root;
1452:            }
1453:
1454:            public SelectExp getSelectFilterJoinExp(boolean value,
1455:                    SelectExp lhSe, SelectExp rootSe, boolean addRootJoin) {
1456:                SelectExp root = new SelectExp();
1457:                root.table = linkTable;
1458:                if (valuesAreOIDs) {
1459:                    SelectExp se = new SelectExp();
1460:                    se.table = ((JdbcClass) fmd.elementTypeMetaData.storeClass).table;
1461:                    root.addJoin(valueColumns, se.table.pk, se);
1462:
1463:                    lhSe.addJoin(lhSe.table.pk, ourPkColumns, root);
1464:
1465:                    return se;
1466:                } else {
1467:                    throw BindingSupportImpl.getInstance().internal(
1468:                            "This must only be called for pc collections");
1469:                }
1470:            }
1471:
1472:            /**
1473:             * Fetch the values for this field using parallel query processing.
1474:             */
1475:            public int fetchWithFilter(JdbcStorageManager sm,
1476:                    StateContainer oidStates, FetchGroupField field,
1477:                    ResultSet rs, boolean forUpdate, OID oidToCheckOn,
1478:                    OID[] lastReadStateOID, ClassMetaData cmd,
1479:                    ColFieldHolder colFHolder) throws SQLException {
1480:
1481:                ClassMetaData valueCmd = fmd.elementTypeMetaData;
1482:                boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO;
1483:                FetchGroup nextFetchGroup = field.nextFetchGroup;
1484:                int valuePkLen = 0;
1485:                int keyPkLen = ((JdbcClass) cmd.storeClass).table.pkSimpleColumnCount;
1486:                if (joined)
1487:                    valuePkLen = ((JdbcClass) valueCmd.storeClass).table.pkSimpleColumnCount;
1488:                int stateOIDPKLen = ((JdbcClass) fmd.classMetaData.storeClass).table.pkSimpleColumnCount;
1489:
1490:                JdbcColumn vc = valueColumns[0];
1491:
1492:                //the oid just read from the rs row
1493:                OID rootOid = cmd.createOID(false);
1494:                //the oid read from the previous rs row
1495:                OID prevRootOid = cmd.createOID(false);
1496:                OID tmpOID = null;
1497:
1498:                OID stateOID = fmd.classMetaData.createOID(false);
1499:                OID prevStateOID = fmd.classMetaData.createOID(false);
1500:                OID tmpStateOID = null;
1501:
1502:                boolean currentRowValid = false;
1503:                boolean prevRowValid = false;
1504:
1505:                Struct struct = new Struct();
1506:                struct.init();
1507:                int returnState = 0;
1508:
1509:                FgDs fgDs = null;
1510:                if (valuesAreOIDs) {
1511:                    fgDs = ((JdbcFetchGroup) nextFetchGroup.storeFetchGroup)
1512:                            .getExistingFgDs(
1513:                                    true,
1514:                                    field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER);
1515:                    if (colFHolder != null) {
1516:                        colFHolder.valueJs = fgDs.getJoinStruct();
1517:                    }
1518:                }
1519:
1520:                if (lastReadStateOID[0] != null) {
1521:                    prevRootOid = lastReadStateOID[0];
1522:                    stateOID = lastReadStateOID[1];
1523:                    currentRowValid = oidStates.containsKey(stateOID);
1524:
1525:                    if (currentRowValid) {
1526:                        returnState |= STATUS_VALID_ROWS;
1527:                        if (valuesAreOIDs) {
1528:                            OID valueOid = valueCmd.createOID(false);
1529:                            boolean isNull = !((JdbcOID) valueOid)
1530:                                    .copyKeyFields(rs, 1 + keyPkLen
1531:                                            + stateOIDPKLen);
1532:
1533:                            if (!isNull) {
1534:                                struct.add(valueOid);
1535:                            } else {
1536:                                struct.add(null);
1537:                            }
1538:
1539:                            if (!isNull
1540:                                    && joined
1541:                                    && oidStates.isStateRequired(valueOid,
1542:                                            nextFetchGroup)) {
1543:                                returnState |= STATUS_DATA_ADDED;
1544:                                State valueState = sm.createStateImp(rs,
1545:                                        valueOid, nextFetchGroup, forUpdate, 1
1546:                                                + valuePkLen + keyPkLen
1547:                                                + valuePkLen, null, true,
1548:                                        oidStates, fgDs, false, false, null);
1549:                                oidStates.addState(valueOid, valueState);
1550:                            }
1551:
1552:                        } else {
1553:                            struct
1554:                                    .add(vc.get(rs, 1 + keyPkLen
1555:                                            + stateOIDPKLen));
1556:                        }
1557:                    }
1558:
1559:                    //preserve the prevRootOid
1560:                    tmpOID = rootOid;
1561:                    rootOid = prevRootOid;
1562:                    prevRootOid = tmpOID;
1563:
1564:                    //preserve the prevStateOID
1565:                    tmpStateOID = stateOID;
1566:                    stateOID = prevStateOID;
1567:                    prevStateOID = tmpStateOID;
1568:
1569:                    prevRowValid = currentRowValid;
1570:                }
1571:
1572:                for (; rs.next();) {
1573:                    int index = 1;
1574:                    ((JdbcOID) rootOid).copyKeyFields(rs, index);
1575:                    index += keyPkLen;
1576:
1577:                    ((JdbcOID) stateOID).copyKeyFields(rs, index);
1578:                    index += stateOIDPKLen;
1579:
1580:                    currentRowValid = oidStates.containsKey(stateOID);
1581:
1582:                    //detected a change in stateOid. Only update if the previous
1583:                    // row was for a valid oid.
1584:                    if (!stateOID.equals(prevStateOID) && prevRowValid) {
1585:                        if (updateStateFilter(struct, oidStates
1586:                                .get(prevStateOID))) {
1587:                            returnState |= STATUS_DATA_ADDED;
1588:                        }
1589:
1590:                        updateStatistics(struct.size);
1591:                        if (oidToCheckOn.equals(prevRootOid)
1592:                                && !oidToCheckOn.equals(rootOid)) {
1593:                            lastReadStateOID[0] = rootOid;
1594:                            lastReadStateOID[1] = stateOID;
1595:                            returnState |= STATUS_VALID_ROWS;
1596:                            return returnState;
1597:                        }
1598:
1599:                        struct.init();
1600:                    }
1601:
1602:                    if (currentRowValid) {
1603:                        returnState |= STATUS_VALID_ROWS;
1604:                        if (valuesAreOIDs) {
1605:                            OID valueOid = valueCmd.createOID(false);
1606:                            boolean isNull = !((JdbcOID) valueOid)
1607:                                    .copyKeyFields(rs, index);
1608:                            index += valuePkLen;
1609:
1610:                            if (!isNull) {
1611:                                struct.add(valueOid);
1612:                            } else {
1613:                                struct.add(null);
1614:                            }
1615:
1616:                            if (!isNull
1617:                                    && joined
1618:                                    && oidStates.isStateRequired(valueOid,
1619:                                            nextFetchGroup)) {
1620:                                State valueState = sm
1621:                                        .createStateImp(
1622:                                                rs,
1623:                                                valueOid,
1624:                                                nextFetchGroup,
1625:                                                forUpdate,
1626:                                                index,
1627:                                                null,
1628:                                                true,
1629:                                                oidStates,
1630:                                                ((JdbcFetchGroup) nextFetchGroup.storeFetchGroup)
1631:                                                        .getFgDs(
1632:                                                                true,
1633:                                                                field.jdbcUseJoin == JdbcField.USE_JOIN_OUTER),
1634:                                                false, false, null);
1635:                                oidStates.addState(valueOid, valueState);
1636:                            }
1637:                        } else {
1638:                            struct.add(vc.get(rs, index));
1639:                        }
1640:                    }
1641:
1642:                    //preserve the prevRootOid
1643:                    tmpOID = rootOid;
1644:                    rootOid = prevRootOid;
1645:                    prevRootOid = tmpOID;
1646:
1647:                    //preserve the prevStateOID
1648:                    tmpStateOID = stateOID;
1649:                    stateOID = prevStateOID;
1650:                    prevStateOID = tmpStateOID;
1651:
1652:                    prevRowValid = currentRowValid;
1653:                }
1654:
1655:                rs.close();
1656:                returnState |= STATUS_CLOSED;
1657:                if ((returnState & STATUS_VALID_ROWS) == STATUS_VALID_ROWS) {
1658:                    if (updateStateFilter(struct, oidStates.get(prevStateOID))) {
1659:                        returnState |= STATUS_DATA_ADDED;
1660:                    }
1661:                }
1662:                return returnState;
1663:            }
1664:
1665:            private boolean updateStateFilter(Struct struct, State state) {
1666:                if (state == null)
1667:                    return false;
1668:                if (struct.values == null)
1669:                    struct.values = EMPTY_OBJECT_ARRAY;
1670:
1671:                if (Debug.DEBUG) {
1672:                    if (!state.containsField(fmd.stateFieldNo)
1673:                            || state.getInternalObjectField(fmd.stateFieldNo) == null) {
1674:                        throw BindingSupportImpl.getInstance().internal("");
1675:                    }
1676:                }
1677:
1678:                if (state.getInternalObjectField(fmd.stateFieldNo) == PRE_GEN_EMPTY_OBJECT_ARRAY) {
1679:                    state.setInternalObjectField(fmd.stateFieldNo, struct
1680:                            .asArray(getStructArrayType()));
1681:                    return true;
1682:                }
1683:                return false;
1684:            }
1685:
1686:            private Class getStructArrayType() {
1687:                if (valuesAreOIDs) {
1688:                    return OID.class;
1689:                } else if (fmd.category == MDStatics.CATEGORY_ARRAY) {
1690:                    return fmd.componentType;
1691:                } else {
1692:                    return Object.class;
1693:                }
1694:            }
1695:
1696:            private class Struct {
1697:
1698:                public int len;
1699:
1700:                public Object[] values;
1701:
1702:                public int size;
1703:
1704:                public void init() {
1705:                    len = (int) (avgRowCount * FUDGE_FACTOR);
1706:                    if (len < MIN_LEN)
1707:                        len = 0;
1708:                    values = len == 0 ? null : (Object[])
1709:
1710:                    Array.newInstance(getStructArrayType(), len);
1711:                    if (Debug.DEBUG) {
1712:                        if (((fetchCount + 1) % 10) == 0) {
1713:                            System.out.println("JdbcLinkCollectionField.fetch"
1714:                                    + " avgRowCount = " + avgRowCount + " "
1715:                                    + " len = " + len + " "
1716:                                    + " expansionCount = " + expansionCount
1717:                                    + " " + " fetchCount = " + fetchCount);
1718:                        }
1719:                    }
1720:                    size = 0;
1721:                }
1722:
1723:                public void add(Object value) {
1724:                    if (!fmd.ordered && value == null) {
1725:                        //ignore null for unordered cols.
1726:                        return;
1727:                    }
1728:                    //grow if nec.
1729:                    if (size == len) {
1730:                        if (len == 0) {
1731:                            values = (Object[])
1732:
1733:                            Array.newInstance(getStructArrayType(),
1734:                                    len = MIN_LEN);
1735:                        } else {
1736:                            len = len * 3 / 2 + 1;
1737:
1738:                            Object[] a = (Object[]) Array.newInstance(
1739:                                    getStructArrayType(), len);
1740:                            System.arraycopy(values, 0, a, 0, size);
1741:
1742:                            values = a;
1743:                            expansionCount++;
1744:                        }
1745:                    }
1746:
1747:                    values[size++] = value;
1748:
1749:                }
1750:
1751:                /**
1752:                 * Return the values as an array of componentType.
1753:                 */
1754:                public Object asArray(Class componentType) {
1755:
1756:                    Object[] a = (Object[]) Array.newInstance(componentType,
1757:                            size);
1758:                    System.arraycopy(values, 0, a, 0, size);
1759:
1760:                    return a;
1761:                }
1762:            }
1763:
1764:            public void fillStateWithEmpty(FetchGroupField field, State state) {
1765:                if (!state.containsField(fmd.stateFieldNo)) {
1766:                    state.setInternalObjectField(fmd.stateFieldNo,
1767:                            PRE_GEN_EMPTY_OBJECT_ARRAY);
1768:                }
1769:            }
1770:
1771:            /**
1772:             * Fetch the values for this field.
1773:             */
1774:            public int fetch(JdbcStorageManager sm, OID oid, State state,
1775:                    FetchGroupField field, boolean forUpdate,
1776:                    StateContainer container, boolean fetchPass2Fields,
1777:                    ColFieldHolder colFHolder) throws SQLException {
1778:                String sql = forUpdate ? field.jdbcSelectSqlForUpdate
1779:                        : field.jdbcSelectSql;
1780:
1781:                FgDs[] fgDses = new FgDs[1];
1782:
1783:                if (sql == null) {
1784:                    SelectExp se = getSelectExp(sm, field, fgDses);
1785:
1786:                    CharBuf s = sm.generateSql(se);
1787:                    sql = s.toString();
1788:                    if (forUpdate) {
1789:                        field.jdbcSelectSqlForUpdate = sql;
1790:                    } else {
1791:                        field.jdbcSelectSql = sql;
1792:                    }
1793:                }
1794:
1795:                if (valuesAreOIDs) {
1796:                    fgDses[0] = ((JdbcFetchGroup) field.nextFetchGroup.storeFetchGroup)
1797:                            .getExistingFgDs(
1798:                                    true,
1799:                                    field.jdbcUseJoin != JdbcField.USE_JOIN_INNER);
1800:                    if (colFHolder != null) {
1801:                        colFHolder.valueJs = fgDses[0].getJoinStruct();
1802:                    }
1803:                }
1804:
1805:                final Struct struct = new Struct();
1806:
1807:                PreparedStatement ps = null;
1808:                ResultSet rs = null;
1809:                try {
1810:                    ps = sm.con().prepareStatement(sql);
1811:                    ((JdbcOID) oid).setParams(ps, 1);
1812:                    try {
1813:                        rs = ps.executeQuery();
1814:                    } catch (Exception e) {
1815:                        throw mapException(e, "Fetch link table rows failed: "
1816:                                + JdbcUtils.toString(e) + "\n" + "Field: "
1817:                                + fmd.getTypeQName() + "\n" + "Instance: "
1818:                                + oid.toSString() + "\n"
1819:                                + JdbcUtils.getPreparedStatementInfo(sql, ps));
1820:                    }
1821:
1822:                    if (valuesAreOIDs) {
1823:                        if (colFHolder != null)
1824:                            colFHolder.valueJs = fgDses[0].getJoinStruct();
1825:                        final boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO
1826:                                || fmd.ordering != null;
1827:                        final int startIndex = 1 + ((JdbcClass) fmd.elementTypeMetaData.storeClass).table.pkSimpleColumnCount;
1828:
1829:                        for (; rs.next();) {
1830:                            OID valueOid = fmd.elementTypeMetaData
1831:                                    .createOID(false);
1832:                            if (((JdbcOID) valueOid).copyKeyFields(rs, 1)) {
1833:                                struct.add(valueOid);
1834:                                if (joined
1835:                                        && container.isStateRequired(valueOid,
1836:                                                field.nextFetchGroup)) {
1837:                                    container.addState(valueOid, sm
1838:                                            .createStateImp(rs, valueOid,
1839:                                                    field.nextFetchGroup,
1840:                                                    forUpdate, startIndex,
1841:                                                    null, true, container,
1842:                                                    fgDses[0],
1843:                                                    fetchPass2Fields, false,
1844:                                                    null));
1845:                                }
1846:                            } else {
1847:                                struct.add(null);
1848:                            }
1849:                        }
1850:                    } else {
1851:                        for (; rs.next();) {
1852:                            struct.add(valueColumns[0].get(rs, 1));
1853:                        }
1854:                    }
1855:
1856:                    // this can come out when the bugs are removed from the rest
1857:                    // of the code
1858:                    Object data;
1859:                    if (struct.values == null) {
1860:
1861:                        data = EMPTY_OBJECT_ARRAY;
1862:                    } else {
1863:                        data = struct.asArray(getStructArrayType());
1864:                    }
1865:                    state.setInternalObjectField(fmd.stateFieldNo, data);
1866:                    updateStatistics(struct.size);
1867:                    return struct.size;
1868:                } finally {
1869:                    cleanup(rs);
1870:                    cleanup(ps);
1871:                }
1872:            }
1873:
1874:            /**
1875:             * Fetch the values for this field.
1876:             */
1877:            public int fetchFrom(ResultSet rs, OID oid, State state,
1878:                    FetchGroupField field, boolean forUpdate,
1879:                    StateContainer container, boolean fetchPass2Fields,
1880:                    int colIndex, FetchInfo fetchInfo, JdbcStorageManager sm)
1881:                    throws SQLException {
1882:                final Struct struct = new Struct();
1883:                if (valuesAreOIDs) {
1884:                    ClassMetaData valueCmd = fmd.elementTypeMetaData;
1885:                    boolean joined = field.jdbcUseJoin != JdbcField.USE_JOIN_NO;
1886:                    FetchGroup nextFetchGroup = field.nextFetchGroup;
1887:                    int valuePkLen = 0;
1888:                    if (joined)
1889:                        valuePkLen = ((JdbcClass) valueCmd.storeClass).table.pkSimpleColumnCount;
1890:                    boolean first = true;
1891:                    for (;;) {
1892:                        boolean mustBreak = false;
1893:                        if (first) {
1894:                            first = false;
1895:                            mustBreak = updateForFirstRow(fetchInfo, mustBreak,
1896:                                    rs, colIndex, oid);
1897:                        } else {
1898:                            if (!rs.next()) {
1899:                                fetchInfo.onNextRow = false;
1900:                                fetchInfo.finished = true;
1901:                                mustBreak = true;
1902:                            } else {
1903:                                fetchInfo.onNextRow = true;
1904:                                mustBreak = checkKeyOid(rs, colIndex,
1905:                                        fetchInfo, mustBreak, oid);
1906:                            }
1907:                        }
1908:                        if (mustBreak)
1909:                            break;
1910:
1911:                        OID valueOid = valueCmd.createOID(false);
1912:                        if (((JdbcOID) valueOid).copyKeyFields(rs, colIndex
1913:                                + ourPkColumns.length)) {
1914:                            struct.add(valueOid);
1915:                            if (joined
1916:                                    && container.isStateRequired(valueOid,
1917:                                            nextFetchGroup)) {
1918:                                State valueState = sm
1919:                                        .createStateImp(
1920:                                                rs,
1921:                                                valueOid,
1922:                                                nextFetchGroup,
1923:                                                forUpdate,
1924:                                                colIndex + valuePkLen
1925:                                                        + ourPkColumns.length,
1926:                                                null,
1927:                                                true,
1928:                                                container,
1929:                                                ((JdbcFetchGroup) nextFetchGroup.storeFetchGroup)
1930:                                                        .getFgDs(true, true),
1931:                                                fetchPass2Fields, false, null);
1932:                                container.addState(valueOid, valueState);
1933:                            }
1934:                        } else {
1935:                            struct.add(null);
1936:                        }
1937:                    }
1938:                } else {
1939:                    boolean mustBreak = false;
1940:                    boolean first = true;
1941:                    for (;;) {
1942:                        if (first) {
1943:                            first = false;
1944:                            mustBreak = updateForFirstRow(fetchInfo, mustBreak,
1945:                                    rs, colIndex, oid);
1946:                        } else {
1947:                            if (!rs.next())
1948:                                break;
1949:                            fetchInfo.onNextRow = true;
1950:                            mustBreak = checkKeyOid(rs, colIndex, fetchInfo,
1951:                                    mustBreak, oid);
1952:                        }
1953:                        if (mustBreak)
1954:                            break;
1955:                        struct.add(valueColumns[0].get(rs, colIndex
1956:                                + ourPkColumns.length));
1957:                    }
1958:                }
1959:                // this can come out when the bugs are removed from the rest
1960:                // of the code
1961:                Object data;
1962:                if (struct.values == null) {
1963:
1964:                    data = EMPTY_OBJECT_ARRAY;
1965:                } else {
1966:                    data = struct.asArray(getStructArrayType());
1967:                }
1968:                state.setInternalObjectField(fmd.stateFieldNo, data);
1969:                updateStatistics(struct.size);
1970:                return struct.size;
1971:            }
1972:
1973:            private void updateStatistics(int size) {
1974:                // Update statistics. This is not thread safe but it is not a
1975:                // problem if the avgRowCount is a bit out sometimes.
1976:                int fc = ++fetchCount;
1977:                if (fc > WINDOW_SIZE) {
1978:                    fc = WINDOW_SIZE;
1979:                } else if (fc == 1) {
1980:                    avgRowCount = size;
1981:                } else if (fc < 0) {
1982:                    fc = fetchCount = WINDOW_SIZE;
1983:                } else {
1984:                    avgRowCount = (avgRowCount * (fc - 1) + size) / fc;
1985:                }
1986:            }
1987:
1988:            /**
1989:             * Delete a pass 2 field for a block of graph entries all with
1990:             * the same class. The same ps'es can be used for all entries in the block.
1991:             */
1992:            public void deletePass2Block(DeletePacket graph, int blockStart,
1993:                    int blockEnd, CharBuf s, Connection con, boolean batch)
1994:                    throws SQLException {
1995:                if (readOnly)
1996:                    return;
1997:                PreparedStatement ps = null;
1998:                try {
1999:                    final int count = blockEnd - blockStart;
2000:                    boolean useInList = (ourPkColumns.length == 1)
2001:                            && (count > 1);
2002:                    if (!batch && !useInList) {
2003:                        //delete one-by-one
2004:                        ps = deleteOneByOne(s, con, ps, blockStart, blockEnd,
2005:                                graph);
2006:                    } else {
2007:                        if (useInList) {
2008:                            ps = deleteWithInList(s, count, con, ps,
2009:                                    blockStart, blockEnd, graph);
2010:                        } else if (batch) {
2011:                            ps = deleteWithBatch(s, con, ps, blockStart,
2012:                                    blockEnd, graph);
2013:                        }
2014:                    }
2015:                } finally {
2016:                    cleanup(ps);
2017:                }
2018:            }
2019:
2020:            private PreparedStatement deleteWithBatch(CharBuf s,
2021:                    Connection con, PreparedStatement ps, int blockStart,
2022:                    int blockEnd, DeletePacket graph) throws SQLException {
2023:                String sql = getDeleteAllLinkTableRowsSql(s);
2024:                ps = con.prepareStatement(sql);
2025:                for (int pos = blockStart; pos < blockEnd; pos++) {
2026:                    ((JdbcOID) graph.oids[pos]).setParams(ps, 1);
2027:                    ps.addBatch();
2028:                }
2029:                try {
2030:                    ps.executeBatch();
2031:                } catch (Exception e) {
2032:                    throw mapException(e,
2033:                            "Batch delete link table rows failed: "
2034:                                    + JdbcUtils.toString(e)
2035:                                    + "\n"
2036:                                    + "Field: "
2037:                                    + fmd.getTypeQName()
2038:                                    + "\n"
2039:                                    + JdbcUtils.getPreparedStatementInfo(sql,
2040:                                            ps));
2041:                }
2042:                return ps;
2043:            }
2044:
2045:            private PreparedStatement deleteWithInList(CharBuf s, int count,
2046:                    Connection con, PreparedStatement ps, int blockStart,
2047:                    int blockEnd, DeletePacket graph) throws SQLException {
2048:                SqlDriver driver = getSqlDriver();
2049:
2050:                if (count > driver.getMaxInOperands()) {
2051:                    //must break it up
2052:                    final int maxInOps = driver.getMaxInOperands();
2053:                    int amountOfFullRuns = count / driver.getMaxInOperands();
2054:
2055:                    final int amountLeft = count % driver.getMaxInOperands();
2056:                    ;
2057:                    String sql = null;
2058:                    int pos = blockStart;
2059:                    final String param = driver
2060:                            .getSqlParamString(ourPkColumns[0].jdbcType);
2061:                    getDeleteAllLinkTableRowsSqlWithInList(s);
2062:                    if (amountLeft > 0) {
2063:                        for (int i = 0; i < amountLeft; i++) {
2064:                            if (i != 0)
2065:                                s.append(",");
2066:                            s.append(param);
2067:                        }
2068:                        s.append(")");
2069:
2070:                        sql = s.toString();
2071:                        ps = con.prepareStatement(sql);
2072:                        for (int curIndex = 0; curIndex < amountLeft; curIndex++, pos++) {
2073:                            ((JdbcOID) graph.oids[pos]).setParams(ps,
2074:                                    curIndex + 1);
2075:                        }
2076:                        try {
2077:                            ps.execute();
2078:                        } catch (Exception e) {
2079:                            throw mapException(e,
2080:                                    "Batch delete link table rows failed: "
2081:                                            + JdbcUtils.toString(e)
2082:                                            + "\n"
2083:                                            + "Field: "
2084:                                            + fmd.getTypeQName()
2085:                                            + "\n"
2086:                                            + JdbcUtils
2087:                                                    .getPreparedStatementInfo(
2088:                                                            sql, ps));
2089:                        }
2090:                        s.set(s.size() - 1, ',');
2091:                    }
2092:
2093:                    for (int i = 0; i < maxInOps - amountLeft; i++) {
2094:                        if (i != 0)
2095:                            s.append(",");
2096:                        s.append(param);
2097:                    }
2098:                    s.append(")");
2099:
2100:                    sql = s.toString();
2101:                    ps = con.prepareStatement(sql);
2102:                    for (int i = 0; i < amountOfFullRuns; i++) {
2103:                        for (int curIndex = 0; curIndex < maxInOps; curIndex++, pos++) {
2104:                            ((JdbcOID) graph.oids[pos]).setParams(ps,
2105:                                    curIndex + 1);
2106:                        }
2107:                        try {
2108:                            ps.execute();
2109:                        } catch (Exception e) {
2110:                            throw mapException(e,
2111:                                    "Batch delete link table rows failed: "
2112:                                            + JdbcUtils.toString(e)
2113:                                            + "\n"
2114:                                            + "Field: "
2115:                                            + fmd.getTypeQName()
2116:                                            + "\n"
2117:                                            + JdbcUtils
2118:                                                    .getPreparedStatementInfo(
2119:                                                            sql, ps));
2120:                        }
2121:                    }
2122:                } else {
2123:                    getDeleteAllLinkTableRowsSqlWithInList(s);
2124:                    for (int i = 0; i < count; i++) {
2125:                        if (i != 0)
2126:                            s.append(",");
2127:                        driver.appendWhereParam(s, ourPkColumns[0]);
2128:                    }
2129:                    s.append(")");
2130:                    String sql = s.toString();
2131:                    ps = con.prepareStatement(sql);
2132:
2133:                    int index = 1;
2134:                    for (int pos = blockStart; pos < blockEnd; pos++) {
2135:                        ((JdbcOID) graph.oids[pos]).setParams(ps, index++);
2136:                    }
2137:                    try {
2138:                        ps.execute();
2139:                    } catch (Exception e) {
2140:                        throw mapException(e,
2141:                                "Batch delete link table rows failed: "
2142:                                        + JdbcUtils.toString(e)
2143:                                        + "\n"
2144:                                        + "Field: "
2145:                                        + fmd.getTypeQName()
2146:                                        + "\n"
2147:                                        + JdbcUtils.getPreparedStatementInfo(
2148:                                                sql, ps));
2149:                    }
2150:                }
2151:                return ps;
2152:            }
2153:
2154:            private PreparedStatement deleteOneByOne(CharBuf s, Connection con,
2155:                    PreparedStatement ps, int blockStart, int blockEnd,
2156:                    DeletePacket graph) throws SQLException {
2157:                String sql = getDeleteAllLinkTableRowsSql(s);
2158:                ps = con.prepareStatement(sql);
2159:                for (int pos = blockStart; pos < blockEnd; pos++) {
2160:                    ((JdbcOID) graph.oids[pos]).setParams(ps, 1);
2161:                    try {
2162:                        ps.execute();
2163:                    } catch (Exception e) {
2164:                        throw mapException(e, "Delete link table rows failed: "
2165:                                + JdbcUtils.toString(e) + "\n" + "Field: "
2166:                                + fmd.getTypeQName() + "\n" + "Instance: "
2167:                                + graph.oids[pos].toSString() + "\n"
2168:                                + JdbcUtils.getPreparedStatementInfo(sql, ps));
2169:                    }
2170:                }
2171:                return ps;
2172:            }
2173:
2174:            /**
2175:             * Convert this field into an isEmpty expression.
2176:             */
2177:            public SqlExp toIsEmptySqlExp(JdbcJDOQLCompiler comp, SelectExp root) {
2178:                SelectExp se = new SelectExp();
2179:                se.table = linkTable;
2180:                se.jdbcField = this ;
2181:                se.subSelectJoinExp = root.createJoinExp(root.table.pk,
2182:                        ourPkColumns, se);
2183:                return new UnaryOpExp(new ExistsExp(se, true),
2184:                        UnaryOpExp.OP_NOT);
2185:            }
2186:
2187:            /**
2188:             * Convert this field into a contains expression.
2189:             */
2190:            public SqlExp toContainsSqlExp(JdbcJDOQLCompiler comp,
2191:                    SelectExp root, Node args) {
2192:                return toContainsSqlExp(valueColumns, fmd.elementTypeMetaData,
2193:                        comp, root, args);
2194:            }
2195:
2196:            protected SqlExp toContainsSqlExp(JdbcColumn[] cols,
2197:                    ClassMetaData colsCmd, JdbcJDOQLCompiler comp,
2198:                    SelectExp root, Node args) {
2199:                SelectExp se = new SelectExp();
2200:                se.table = linkTable;
2201:                se.jdbcField = this ;
2202:                se.subSelectJoinExp = root.createJoinExp(root.table.pk,
2203:                        ourPkColumns, se);
2204:
2205:                if (args instanceof  VarNodeIF) {
2206:                    VarNode v = ((VarNodeIF) args).getVarNode();
2207:                    if (v.getCmd() == null) {
2208:                        SelectExp storeExtent = new SelectExp();
2209:                        storeExtent.table = linkTable;
2210:                        storeExtent.var = v;
2211:                        v.setStoreExtent(storeExtent);
2212:                        v.setFieldExtent(se);
2213:                        v.setFmd(fmd);
2214:                        se.var = v;
2215:                    } else {
2216:                        SelectExp vse = (SelectExp) v.getStoreExtent();
2217:                        se.addJoin(cols, vse.table.pk, vse);
2218:                        se.var = v;
2219:                    }
2220:                } else {
2221:                    SqlExp left = JdbcColumn.toSqlExp(cols, se);
2222:                    if (colsCmd != null) {
2223:                        for (SqlExp e = left; e != null; e = e.next) {
2224:                            ((ColumnExp) e).cmd = colsCmd;
2225:                        }
2226:                    }
2227:                    SqlExp right = comp.getVisitor().toSqlExp(args, root, left,
2228:                            0, null);
2229:                    se.whereExp = SqlExp.createBinaryOpExp(left,
2230:                            BinaryOpExp.EQUAL, right);
2231:                }
2232:                return new ExistsExp(se, true,
2233:                        (args instanceof  VarNodeIF ? (VarNodeIF) args : null));
2234:            }
2235:
2236:            /**
2237:             * Process meta data for an inverse many-to-many collection.
2238:             */
2239:            private void processInverse(JdbcMetaDataBuilder mdb, JdoExtension e) {
2240:                ClassMetaData ecmd = fmd.elementTypeMetaData;
2241:                if (ecmd.storeClass == null) {
2242:                    throw BindingSupportImpl
2243:                            .getInstance()
2244:                            .runtime(
2245:                                    "The inverse extension may only be used for "
2246:                                            + "collections of PC instances stored by JDBC\n"
2247:                                            + e.getContext());
2248:                }
2249:                String fname = e.getString();
2250:                FieldMetaData f = ecmd.getFieldMetaData(fname);
2251:                if (f.storeField == null) {
2252:                    throw BindingSupportImpl.getInstance().runtime(
2253:                            "Field '" + fname + "' is not persistent\n"
2254:                                    + e.getContext());
2255:                }
2256:                if (!(f.storeField instanceof  JdbcLinkCollectionField)) {
2257:                    throw BindingSupportImpl.getInstance().runtime(
2258:                            "Field '" + fname
2259:                                    + "' is not a collection or array mapped "
2260:                                    + "using a link table\n" + e.getContext());
2261:                }
2262:                inverse = (JdbcLinkCollectionField) f.storeField;
2263:                if (f.elementTypeMetaData != fmd.classMetaData) {
2264:                    throw BindingSupportImpl.getInstance().runtime(
2265:                            "Field '" + fname + "' contains "
2266:                                    + f.elementTypeMetaData
2267:                                    + " and not our class\n" + e.getContext());
2268:                }
2269:                if (inverse == this ) {
2270:                    throw BindingSupportImpl
2271:                            .getInstance()
2272:                            .runtime(
2273:                                    "Field '"
2274:                                            + fname
2275:                                            + "' may not be in a many-to-many with itself\n"
2276:                                            + e.getContext());
2277:                }
2278:                inverse.inverse = this ;
2279:                readOnly = true;
2280:                valuesAreOIDs = true;
2281:                fmd.ordered = false;
2282:                fmd.isManyToMany = true;
2283:                fmd.isReadOnly = true;
2284:                fmd.inverseFieldMetaData = inverse.fmd;
2285:                inverse.fmd.isManyToMany = true;
2286:                inverse.fmd.inverseFieldMetaData = fmd;
2287:                syncWithInverse(mdb);
2288:            }
2289:
2290:            /**
2291:             * Sync our mapping info with our inverse. This will get called twice:
2292:             * once for each side of the many-to-many.
2293:             * @param mdb
2294:             */
2295:            private void syncWithInverse(JdbcMetaDataBuilder mdb) {
2296:                if (inverse == null)
2297:                    return; // not inverse or inverse side not done
2298:                if (readOnly) {
2299:                    linkTable = inverse.linkTable;
2300:                    if (linkTable != null) { // main side has been done
2301:                        valueColumns = inverse.ourPkColumns;
2302:                        ourPkColumns = inverse.valueColumns;
2303:                        sequenceColumn = inverse.sequenceColumn;
2304:                        createInverseIndex(mdb);
2305:                    }
2306:                    fmd.managed = inverse.fmd.managed;
2307:                } else {
2308:                    inverse.syncWithInverse(mdb);
2309:                }
2310:            }
2311:
2312:            /**
2313:             * For inverse collections create an index on our primary key fields
2314:             * in the link table of the main collection  unless this has been disabled.
2315:             * @param mdb
2316:             */
2317:            private void createInverseIndex(JdbcMetaDataBuilder mdb) {
2318:                JdoExtension ext = JdoExtension.find(JdoExtensionKeys.INVERSE,
2319:                        getExtensions());
2320:                JdoExtension[] nested = ext.nested;
2321:
2322:                JdbcIndex idx = null;
2323:                boolean doNotCreateIndex = false;
2324:
2325:                int n = nested == null ? 0 : nested.length;
2326:                for (int i = 0; i < n; i++) {
2327:                    JdoExtension e = nested[i];
2328:                    switch (e.key) {
2329:                    case JdoExtensionKeys.JDBC_INDEX:
2330:                        if (idx != null) {
2331:                            throw BindingSupportImpl.getInstance().runtime(
2332:                                    "Only one jdbc-index extension is allowed here\n"
2333:                                            + e.getContext());
2334:                        }
2335:                        if (e.isNoValue()) {
2336:                            doNotCreateIndex = true;
2337:                            break;
2338:                        }
2339:                        idx = new JdbcIndex();
2340:                        idx.name = e.value;
2341:                        break;
2342:                    default:
2343:                        if (e.isJdbc()) {
2344:                            MetaDataBuilder.throwUnexpectedExtension(e);
2345:                        }
2346:                    }
2347:                }
2348:
2349:                if (doNotCreateIndex)
2350:                    return;
2351:                if (idx == null)
2352:                    idx = new JdbcIndex();
2353:                idx.setCols(ourPkColumns);
2354:
2355:                // register the name of the index if one was specified otherwise one
2356:                // will be generated later along with user specified indexes
2357:                if (idx.name != null) {
2358:                    try {
2359:                        mdb.getNameGenerator().addIndexName(linkTable.name,
2360:                                idx.name);
2361:                    } catch (IllegalArgumentException x) {
2362:                        throw BindingSupportImpl.getInstance().runtime(
2363:                                x.getMessage(), x);
2364:                    }
2365:                }
2366:
2367:                if (linkTable.indexes != null) {
2368:                    throw BindingSupportImpl.getInstance().internal(
2369:                            "Link table already has index: " + linkTable + ", "
2370:                                    + fmd.getTypeQName());
2371:                }
2372:                linkTable.indexes = new JdbcIndex[] { idx };
2373:            }
2374:
2375:            /**
2376:             * Make sure all the indexes on our link tables (if any) have names,
2377:             */
2378:            public void nameLinkTableIndexes(JdbcNameGenerator namegen) {
2379:                if (readOnly)
2380:                    return;
2381:                int n = linkTable == null ? 0 : linkTable.indexes == null ? 0
2382:                        : linkTable.indexes.length;
2383:                for (int i = 0; i < n; i++) {
2384:                    JdbcIndex idx = linkTable.indexes[i];
2385:                    if (idx.name == null) {
2386:                        JdbcMetaDataBuilder.generateNameForIndex(namegen,
2387:                                linkTable.name, idx);
2388:                    }
2389:                }
2390:            }
2391:
2392:            /**
2393:             * Return SQL that will fetch all the rows in the link table.
2394:             * This is used when bulk copying one database to another. The OID of
2395:             * the owning table must be first followed by the other columns in the
2396:             * order expected by readRow.
2397:             *
2398:             * @see #readRow
2399:             */
2400:            public String getFetchAllRowsSql(JdbcStorageManager sm)
2401:                    throws SQLException {
2402:                SelectExp root = new SelectExp();
2403:                root.table = linkTable;
2404:                SqlExp e = root.selectList = JdbcColumn.toSqlExp(ourPkColumns,
2405:                        root);
2406:                for (; e.next != null; e = e.next)
2407:                    ;
2408:                if (fmd.ordered)
2409:                    e = e.next = sequenceColumn.toSqlExp(root);
2410:                e = e.next = JdbcColumn.toSqlExp(valueColumns, root);
2411:                addFetchAllRowsKey(e, root);
2412:                return sm.generateSql(root).toString();
2413:            }
2414:
2415:            /**
2416:             * Hook for JdbcMapField to add its key columns to the row. The returned
2417:             * SqlExp must be the last one in the list.
2418:             */
2419:            protected void addFetchAllRowsKey(SqlExp e, SelectExp se) {
2420:            }
2421:
2422:            /**
2423:             * Fetch a row of values for this field. This is used when bulk copying
2424:             * one database to another to read all the rows in a given link table.
2425:             * Return the index of the last column read + 1.
2426:             */
2427:            public int readRow(ResultSet rs, LinkRow row) throws SQLException {
2428:                row.owner = (JdbcGenericOID) fmd.classMetaData.createOID(false);
2429:                row.owner.copyKeyFields(rs, 1);
2430:                int pos = ourPkColumns.length + 1;
2431:                if (fmd.ordered) {
2432:                    row.seq = ((Integer) sequenceColumn.get(rs, pos++))
2433:                            .intValue();
2434:                }
2435:                if (valuesAreOIDs) {
2436:                    OID valueOid = fmd.elementTypeMetaData.createOID(false);
2437:                    ((JdbcOID) valueOid).copyKeyFields(rs, pos);
2438:                    row.value = valueOid;
2439:                    pos += valueColumns.length;
2440:                } else {
2441:                    row.value = valueColumns[0].get(rs, pos++);
2442:                }
2443:                return pos;
2444:            }
2445:
2446:            /**
2447:             * Set a row of values for this field on a PreparedStatement.
2448:             * This is used when bulk copying one database to another.
2449:             */
2450:            public void writeRow(PreparedStatement ps, LinkRow row)
2451:                    throws SQLException {
2452:                row.owner.setCmd(fmd.classMetaData);
2453:                int pos = row.owner.setParams(ps, 1);
2454:                if (fmd.ordered)
2455:                    sequenceColumn.set(ps, pos++, row.seq);
2456:                if (valuesAreOIDs) {
2457:                    JdbcGenericOID v = (JdbcGenericOID) row.value;
2458:                    v.setCmd(fmd.classMetaData);
2459:                    v.setParams(ps, pos);
2460:                } else {
2461:                    valueColumns[0].set(ps, pos, row.value);
2462:                }
2463:            }
2464:
2465:            /**
2466:             * A row from our link table. This is used by the bulk database copying
2467:             * operations.
2468:             */
2469:            public static class LinkRow {
2470:
2471:                public JdbcGenericOID owner;
2472:                public int seq;
2473:                public Object key;
2474:                public Object value;
2475:            }
2476:
2477:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.