Source Code Cross Referenced for CachedRowSetWriter.java in  » 6.0-JDK-Modules-com.sun » rowset » com » sun » rowset » internal » 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 » 6.0 JDK Modules com.sun » rowset » com.sun.rowset.internal 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
0003:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004:         *
0005:         * This code is free software; you can redistribute it and/or modify it
0006:         * under the terms of the GNU General Public License version 2 only, as
0007:         * published by the Free Software Foundation.  Sun designates this
0008:         * particular file as subject to the "Classpath" exception as provided
0009:         * by Sun in the LICENSE file that accompanied this code.
0010:         *
0011:         * This code is distributed in the hope that it will be useful, but WITHOUT
0012:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013:         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0014:         * version 2 for more details (a copy is included in the LICENSE file that
0015:         * accompanied this code).
0016:         *
0017:         * You should have received a copy of the GNU General Public License version
0018:         * 2 along with this work; if not, write to the Free Software Foundation,
0019:         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020:         *
0021:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022:         * CA 95054 USA or visit www.sun.com if you need additional information or
0023:         * have any questions.
0024:         */
0025:
0026:        package com.sun.rowset.internal;
0027:
0028:        import java.sql.*;
0029:        import javax.sql.*;
0030:        import java.util.*;
0031:        import java.io.*;
0032:
0033:        import com.sun.rowset.*;
0034:        import javax.sql.rowset.*;
0035:        import javax.sql.rowset.spi.*;
0036:
0037:        /**
0038:         * The facility called on internally by the <code>RIOptimisticProvider</code> implementation to
0039:         * propagate changes back to the data source from which the rowset got its data.
0040:         * <P>
0041:         * A <code>CachedRowSetWriter</code> object, called a writer, has the public
0042:         * method <code>writeData</code> for writing modified data to the underlying data source.
0043:         * This method is invoked by the rowset internally and is never invoked directly by an application.
0044:         * A writer also has public methods for setting and getting
0045:         * the <code>CachedRowSetReader</code> object, called a reader, that is associated
0046:         * with the writer. The remainder of the methods in this class are private and
0047:         * are invoked internally, either directly or indirectly, by the method
0048:         * <code>writeData</code>.
0049:         * <P>
0050:         * Typically the <code>SyncFactory</code> manages the <code>RowSetReader</code> and
0051:         * the <code>RowSetWriter</code> implementations using <code>SyncProvider</code> objects.
0052:         * Standard JDBC RowSet implementations provide an object instance of this
0053:         * writer by invoking the <code>SyncProvider.getRowSetWriter()</code> method.
0054:         *
0055:         * @version 0.2
0056:         * @author Jonathan Bruce
0057:         * @see javax.sql.rowset.spi.SyncProvider
0058:         * @see javax.sql.rowset.spi.SyncFactory
0059:         * @see javax.sql.rowset.spi.SyncFactoryException
0060:         */
0061:        public class CachedRowSetWriter implements  TransactionalWriter,
0062:                Serializable {
0063:
0064:            /**
0065:             * The <code>Connection</code> object that this writer will use to make a
0066:             * connection to the data source to which it will write data.
0067:             *
0068:             */
0069:            private transient Connection con;
0070:
0071:            /**
0072:             * The SQL <code>SELECT</code> command that this writer will call
0073:             * internally. The method <code>initSQLStatements</code> builds this
0074:             * command by supplying the words "SELECT" and "FROM," and using
0075:             * metadata to get the table name and column names .
0076:             *
0077:             * @serial
0078:             */
0079:            private String selectCmd;
0080:
0081:            /**
0082:             * The SQL <code>UPDATE</code> command that this writer will call
0083:             * internally to write data to the rowset's underlying data source.
0084:             * The method <code>initSQLStatements</code> builds this <code>String</code>
0085:             * object.
0086:             *
0087:             * @serial
0088:             */
0089:            private String updateCmd;
0090:
0091:            /**
0092:             * The SQL <code>WHERE</code> clause the writer will use for update
0093:             * statements in the <code>PreparedStatement</code> object
0094:             * it sends to the underlying data source.
0095:             *
0096:             * @serial
0097:             */
0098:            private String updateWhere;
0099:
0100:            /**
0101:             * The SQL <code>DELETE</code> command that this writer will call
0102:             * internally to delete a row in the rowset's underlying data source.
0103:             *
0104:             * @serial
0105:             */
0106:            private String deleteCmd;
0107:
0108:            /**
0109:             * The SQL <code>WHERE</code> clause the writer will use for delete
0110:             * statements in the <code>PreparedStatement</code> object
0111:             * it sends to the underlying data source.
0112:             *
0113:             * @serial
0114:             */
0115:            private String deleteWhere;
0116:
0117:            /**
0118:             * The SQL <code>INSERT INTO</code> command that this writer will internally use
0119:             * to insert data into the rowset's underlying data source.  The method
0120:             * <code>initSQLStatements</code> builds this command with a question
0121:             * mark parameter placeholder for each column in the rowset.
0122:             *
0123:             * @serial
0124:             */
0125:            private String insertCmd;
0126:
0127:            /**
0128:             * An array containing the column numbers of the columns that are
0129:             * needed to uniquely identify a row in the <code>CachedRowSet</code> object
0130:             * for which this <code>CachedRowSetWriter</code> object is the writer.
0131:             *
0132:             * @serial
0133:             */
0134:            private int[] keyCols;
0135:
0136:            /**
0137:             * An array of the parameters that should be used to set the parameter
0138:             * placeholders in a <code>PreparedStatement</code> object that this
0139:             * writer will execute.
0140:             *
0141:             * @serial
0142:             */
0143:            private Object[] params;
0144:
0145:            /**
0146:             * The <code>CachedRowSetReader</code> object that has been
0147:             * set as the reader for the <code>CachedRowSet</code> object
0148:             * for which this <code>CachedRowSetWriter</code> object is the writer.
0149:             *
0150:             * @serial
0151:             */
0152:            private CachedRowSetReader reader;
0153:
0154:            /**
0155:             * The <code>ResultSetMetaData</code> object that contains information
0156:             * about the columns in the <code>CachedRowSet</code> object
0157:             * for which this <code>CachedRowSetWriter</code> object is the writer.
0158:             *
0159:             * @serial
0160:             */
0161:            private ResultSetMetaData callerMd;
0162:
0163:            /**
0164:             * The number of columns in the <code>CachedRowSet</code> object
0165:             * for which this <code>CachedRowSetWriter</code> object is the writer.
0166:             *
0167:             * @serial
0168:             */
0169:            private int callerColumnCount;
0170:
0171:            /**
0172:             * This <code>CachedRowSet<code> will hold the conflicting values
0173:             *  retrieved from the db and hold it.
0174:             */
0175:            private CachedRowSetImpl crsResolve;
0176:
0177:            /**
0178:             * This <code>ArrayList<code> will hold the values of SyncResolver.*
0179:             */
0180:            private ArrayList status;
0181:
0182:            /**
0183:             * This will check whether the same field value has changed both
0184:             * in database and CachedRowSet.
0185:             */
0186:            private int iChangedValsInDbAndCRS;
0187:
0188:            /**
0189:             * This will hold the number of cols for which the values have
0190:             * changed only in database.
0191:             */
0192:            private int iChangedValsinDbOnly;
0193:
0194:            private JdbcRowSetResourceBundle resBundle;
0195:
0196:            public CachedRowSetWriter() {
0197:                try {
0198:                    resBundle = JdbcRowSetResourceBundle
0199:                            .getJdbcRowSetResourceBundle();
0200:                } catch (IOException ioe) {
0201:                    throw new RuntimeException(ioe);
0202:                }
0203:            }
0204:
0205:            /**
0206:             * Propagates changes in the given <code>RowSet</code> object
0207:             * back to its underlying data source and returns <code>true</code>
0208:             * if successful. The writer will check to see if
0209:             * the data in the pre-modified rowset (the original values) differ
0210:             * from the data in the underlying data source.  If data in the data
0211:             * source has been modified by someone else, there is a conflict,
0212:             * and in that case, the writer will not write to the data source.
0213:             * In other words, the writer uses an optimistic concurrency algorithm:
0214:             * It checks for conflicts before making changes rather than restricting
0215:             * access for concurrent users.
0216:             * <P>
0217:             * This method is called by the rowset internally when
0218:             * the application invokes the method <code>acceptChanges</code>.
0219:             * The <code>writeData</code> method in turn calls private methods that
0220:             * it defines internally.
0221:             * The following is a general summary of what the method
0222:             * <code>writeData</code> does, much of which is accomplished
0223:             * through calls to its own internal methods.
0224:             * <OL>
0225:             * <LI>Creates a <code>CachedRowSet</code> object from the given
0226:             *     <code>RowSet</code> object
0227:             * <LI>Makes a connection with the data source
0228:             *   <UL>
0229:             *      <LI>Disables autocommit mode if it is not already disabled
0230:             *      <LI>Sets the transaction isolation level to that of the rowset
0231:             *   </UL>
0232:             * <LI>Checks to see if the reader has read new data since the writer
0233:             *     was last called and, if so, calls the method
0234:             *    <code>initSQLStatements</code> to initialize new SQL statements
0235:             *   <UL>
0236:             *       <LI>Builds new <code>SELECT</code>, <code>UPDATE</code>,
0237:             *           <code>INSERT</code>, and <code>DELETE</code> statements
0238:             *       <LI>Uses the <code>CachedRowSet</code> object's metadata to
0239:             *           determine the table name, column names, and the columns
0240:             *           that make up the primary key
0241:             *   </UL>
0242:             * <LI>When there is no conflict, propagates changes made to the
0243:             *     <code>CachedRowSet</code> object back to its underlying data source
0244:             *   <UL>
0245:             *      <LI>Iterates through each row of the <code>CachedRowSet</code> object
0246:             *          to determine whether it has been updated, inserted, or deleted
0247:             *      <LI>If the corresponding row in the data source has not been changed
0248:             *          since the rowset last read its
0249:             *          values, the writer will use the appropriate command to update,
0250:             *          insert, or delete the row
0251:             *      <LI>If any data in the data source does not match the original values
0252:             *          for the <code>CachedRowSet</code> object, the writer will roll
0253:             *          back any changes it has made to the row in the data source.
0254:             *   </UL>
0255:             * </OL>
0256:             *
0257:             * @return <code>true</code> if changes to the rowset were successfully
0258:             *         written to the rowset's underlying data source;
0259:             *         <code>false</code> otherwise
0260:             */
0261:            public boolean writeData(RowSetInternal caller) throws SQLException {
0262:                boolean conflict = false;
0263:                boolean showDel = false;
0264:                PreparedStatement pstmtIns = null;
0265:                iChangedValsInDbAndCRS = 0;
0266:                iChangedValsinDbOnly = 0;
0267:
0268:                // We assume caller is a CachedRowSet
0269:                CachedRowSetImpl crs = (CachedRowSetImpl) caller;
0270:                // crsResolve = new CachedRowSetImpl();
0271:                this .crsResolve = new CachedRowSetImpl();
0272:                ;
0273:
0274:                // The reader is registered with the writer at design time.
0275:                // This is not required, in general.  The reader has logic
0276:                // to get a JDBC connection, so call it.
0277:
0278:                con = reader.connect(caller);
0279:
0280:                if (con == null) {
0281:                    throw new SQLException(resBundle.handleGetObject(
0282:                            "crswriter.connect").toString());
0283:                }
0284:
0285:                /*
0286:                 // Fix 6200646.
0287:                 // Don't change the connection or transaction properties. This will fail in a
0288:                 // J2EE container.
0289:                if (con.getAutoCommit() == true)  {
0290:                    con.setAutoCommit(false);
0291:                }
0292:
0293:                con.setTransactionIsolation(crs.getTransactionIsolation());
0294:                 */
0295:
0296:                initSQLStatements(crs);
0297:                int iColCount;
0298:
0299:                RowSetMetaDataImpl rsmdWrite = (RowSetMetaDataImpl) crs
0300:                        .getMetaData();
0301:                RowSetMetaDataImpl rsmdResolv = new RowSetMetaDataImpl();
0302:
0303:                iColCount = rsmdWrite.getColumnCount();
0304:                int sz = crs.size() + 1;
0305:                status = new ArrayList(sz);
0306:
0307:                status.add(0, null);
0308:                rsmdResolv.setColumnCount(iColCount);
0309:
0310:                for (int i = 1; i <= iColCount; i++) {
0311:                    rsmdResolv.setColumnType(i, rsmdWrite.getColumnType(i));
0312:                    rsmdResolv.setColumnName(i, rsmdWrite.getColumnName(i));
0313:                    rsmdResolv.setNullable(i,
0314:                            ResultSetMetaData.columnNullableUnknown);
0315:                }
0316:                this .crsResolve.setMetaData(rsmdResolv);
0317:
0318:                // moved outside the insert inner loop
0319:                //pstmtIns = con.prepareStatement(insertCmd);
0320:
0321:                if (callerColumnCount < 1) {
0322:                    // No data, so return success.
0323:                    if (reader.getCloseConnection() == true)
0324:                        con.close();
0325:                    return true;
0326:                }
0327:                // We need to see rows marked for deletion.
0328:                showDel = crs.getShowDeleted();
0329:                crs.setShowDeleted(true);
0330:
0331:                // Look at all the rows.
0332:                crs.beforeFirst();
0333:
0334:                int rows = 1;
0335:                while (crs.next()) {
0336:                    if (crs.rowDeleted()) {
0337:                        // The row has been deleted.
0338:                        if (conflict = (deleteOriginalRow(crs, this .crsResolve)) == true) {
0339:                            status.add(rows, new Integer(
0340:                                    SyncResolver.DELETE_ROW_CONFLICT));
0341:                        } else {
0342:                            // delete happened without any occurrence of conflicts
0343:                            // so update status accordingly
0344:                            status.add(rows, new Integer(
0345:                                    SyncResolver.NO_ROW_CONFLICT));
0346:                        }
0347:
0348:                    } else if (crs.rowInserted()) {
0349:                        // The row has been inserted.
0350:
0351:                        pstmtIns = con.prepareStatement(insertCmd);
0352:                        if ((conflict = insertNewRow(crs, pstmtIns,
0353:                                this .crsResolve)) == true) {
0354:                            status.add(rows, new Integer(
0355:                                    SyncResolver.INSERT_ROW_CONFLICT));
0356:                        } else {
0357:                            // insert happened without any occurrence of conflicts
0358:                            // so update status accordingly
0359:                            status.add(rows, new Integer(
0360:                                    SyncResolver.NO_ROW_CONFLICT));
0361:                        }
0362:                    } else if (crs.rowUpdated()) {
0363:                        // The row has been updated.
0364:                        if (conflict = (updateOriginalRow(crs)) == true) {
0365:                            status.add(rows, new Integer(
0366:                                    SyncResolver.UPDATE_ROW_CONFLICT));
0367:                        } else {
0368:                            // update happened without any occurrence of conflicts
0369:                            // so update status accordingly
0370:                            status.add(rows, new Integer(
0371:                                    SyncResolver.NO_ROW_CONFLICT));
0372:                        }
0373:
0374:                    } else {
0375:                        /** The row is neither of inserted, updated or deleted.
0376:                         *  So set nulls in the this.crsResolve for this row,
0377:                         *  as nothing is to be done for such rows.
0378:                         *  Also note that if such a row has been changed in database
0379:                         *  and we have not changed(inserted, updated or deleted)
0380:                         *  that is fine.
0381:                         **/
0382:                        int icolCount = crs.getMetaData().getColumnCount();
0383:                        status.add(rows, new Integer(
0384:                                SyncResolver.NO_ROW_CONFLICT));
0385:
0386:                        this .crsResolve.moveToInsertRow();
0387:                        for (int cols = 0; cols < iColCount; cols++) {
0388:                            this .crsResolve.updateNull(cols + 1);
0389:                        } //end for
0390:
0391:                        this .crsResolve.insertRow();
0392:                        this .crsResolve.moveToCurrentRow();
0393:
0394:                    } //end if
0395:                    rows++;
0396:                } //end while
0397:
0398:                // close the insert statement
0399:                if (pstmtIns != null)
0400:                    pstmtIns.close();
0401:                // reset
0402:                crs.setShowDeleted(showDel);
0403:
0404:                boolean boolConf = false;
0405:                for (int j = 1; j < status.size(); j++) {
0406:                    // ignore status for index = 0 which is set to null          
0407:                    if (!((status.get(j)).equals(new Integer(
0408:                            SyncResolver.NO_ROW_CONFLICT)))) {
0409:                        // there is at least one conflict which needs to be resolved
0410:                        boolConf = true;
0411:                        break;
0412:                    }
0413:                }
0414:
0415:                crs.beforeFirst();
0416:                this .crsResolve.beforeFirst();
0417:
0418:                if (boolConf) {
0419:                    SyncProviderException spe = new SyncProviderException(
0420:                            status.size()
0421:                                    - 1
0422:                                    + resBundle.handleGetObject(
0423:                                            "crswriter.conflictsno").toString());
0424:                    //SyncResolver syncRes = spe.getSyncResolver();
0425:
0426:                    SyncResolverImpl syncResImpl = (SyncResolverImpl) spe
0427:                            .getSyncResolver();
0428:
0429:                    syncResImpl.setCachedRowSet(crs);
0430:                    syncResImpl.setCachedRowSetResolver(this .crsResolve);
0431:
0432:                    syncResImpl.setStatus(status);
0433:                    syncResImpl.setCachedRowSetWriter(this );
0434:
0435:                    throw spe;
0436:                } else {
0437:                    return true;
0438:                }
0439:                /*
0440:                if (conflict == true) {
0441:                     con.rollback();
0442:                     return false;
0443:                 } else {
0444:                     con.commit();            
0445:                     if (reader.getCloseConnection() == true) {
0446:                       con.close();
0447:                     }	
0448:                     return true;
0449:                 }
0450:                 */
0451:
0452:            } //end writeData
0453:
0454:            /**
0455:             * Updates the given <code>CachedRowSet</code> object's underlying data
0456:             * source so that updates to the rowset are reflected in the original
0457:             * data source, and returns <code>false</code> if the update was successful.
0458:             * A return value of <code>true</code> indicates that there is a conflict,
0459:             * meaning that a value updated in the rowset has already been changed by
0460:             * someone else in the underlying data source.  A conflict can also exist
0461:             * if, for example, more than one row in the data source would be affected
0462:             * by the update or if no rows would be affected.  In any case, if there is
0463:             * a conflict, this method does not update the underlying data source.
0464:             * <P>
0465:             * This method is called internally by the method <code>writeData</code>
0466:             * if a row in the <code>CachedRowSet</code> object for which this
0467:             * <code>CachedRowSetWriter</code> object is the writer has been updated.
0468:             *
0469:             * @return <code>false</code> if the update to the underlying data source is
0470:             *         successful; <code>true</code> otherwise
0471:             * @throws SQLException if a database access error occurs
0472:             */
0473:            private boolean updateOriginalRow(CachedRowSet crs)
0474:                    throws SQLException {
0475:                PreparedStatement pstmt;
0476:                int i = 0;
0477:                int idx = 0;
0478:
0479:                // Select the row from the database.
0480:                ResultSet origVals = crs.getOriginalRow();
0481:                origVals.next();
0482:
0483:                try {
0484:                    updateWhere = buildWhereClause(updateWhere, origVals);
0485:
0486:                    /**
0487:                     *  The following block of code is for checking a particular type of
0488:                     *  query where in there is a where clause. Without this block, if a
0489:                     *  SQL statement is built the "where" clause will appear twice hence
0490:                     *  the DB errors out and a SQLException is thrown. This code also 
0491:                     *  considers that the where clause is in the right place as the 
0492:                     *  CachedRowSet object would already have been populated with this
0493:                     *  query before coming to this point.
0494:                     **/
0495:
0496:                    String tempselectCmd = selectCmd.toLowerCase();
0497:
0498:                    int idxWhere = tempselectCmd.indexOf("where");
0499:
0500:                    if (idxWhere != -1) {
0501:                        String tempSelect = selectCmd.substring(0, idxWhere);
0502:                        selectCmd = tempSelect;
0503:                    }
0504:
0505:                    pstmt = con.prepareStatement(selectCmd + updateWhere,
0506:                            ResultSet.TYPE_SCROLL_SENSITIVE,
0507:                            ResultSet.CONCUR_READ_ONLY);
0508:
0509:                    for (i = 0; i < keyCols.length; i++) {
0510:                        if (params[i] != null) {
0511:                            pstmt.setObject(++idx, params[i]);
0512:                        } else {
0513:                            continue;
0514:                        }
0515:                    }
0516:
0517:                    try {
0518:                        pstmt.setMaxRows(crs.getMaxRows());
0519:                        pstmt.setMaxFieldSize(crs.getMaxFieldSize());
0520:                        pstmt.setEscapeProcessing(crs.getEscapeProcessing());
0521:                        pstmt.setQueryTimeout(crs.getQueryTimeout());
0522:                    } catch (Exception ex) {
0523:                        // Older driver don't support these operations.
0524:                    }
0525:
0526:                    ResultSet rs = null;
0527:                    rs = pstmt.executeQuery();
0528:                    if (rs.next() == true) {
0529:
0530:                        if (rs.next()) {
0531:                            /**  More than one row conflict.
0532:                             *  If rs has only one row we are able to
0533:                             *  uniquely identify the row where update
0534:                             *  have to happen else if more than one
0535:                             *  row implies we cannot uniquely identify the row
0536:                             *  where we have to do updates.
0537:                             *  crs.setKeyColumns needs to be set to
0538:                             *  come out of this situation.
0539:                             */
0540:
0541:                            return true;
0542:                        }
0543:
0544:                        // don't close the rs
0545:                        // we require the record in rs to be used.
0546:                        // rs.close();
0547:                        // pstmt.close();
0548:                        rs.first();
0549:
0550:                        // how many fields need to be updated
0551:                        int colsNotChanged = 0;
0552:                        Vector cols = new Vector();
0553:                        String updateExec = new String(updateCmd);
0554:                        Object orig;
0555:                        Object curr;
0556:                        Object rsval;
0557:                        boolean boolNull = true;
0558:                        Object objVal = null;
0559:
0560:                        // There's only one row and the cursor
0561:                        // needs to be on that row.
0562:
0563:                        boolean first = true;
0564:                        boolean flag = true;
0565:
0566:                        this .crsResolve.moveToInsertRow();
0567:
0568:                        for (i = 1; i <= callerColumnCount; i++) {
0569:                            orig = origVals.getObject(i);
0570:                            curr = crs.getObject(i);
0571:                            rsval = rs.getObject(i);
0572:
0573:                            // reset boolNull if it had been set
0574:                            boolNull = true;
0575:
0576:                            /** This addtional checking has been added when the current value
0577:                             *  in the DB is null, but the DB had a different value when the
0578:                             *  data was actaully fetched into the CachedRowSet.
0579:                             **/
0580:
0581:                            if (rsval == null && orig != null) {
0582:                                // value in db has changed
0583:                                // don't proceed with synchronization
0584:                                // get the value in db and pass it to the resolver.
0585:
0586:                                iChangedValsinDbOnly++;
0587:                                // Set the boolNull to false,
0588:                                // in order to set the actual value;
0589:                                boolNull = false;
0590:                                objVal = rsval;
0591:                            }
0592:
0593:                            /** Adding the checking for rsval to be "not" null or else
0594:                             *  it would through a NullPointerException when the values
0595:                             *  are compared.
0596:                             **/
0597:
0598:                            else if (rsval != null && (!rsval.equals(orig))) {
0599:                                // value in db has changed
0600:                                // don't proceed with synchronization
0601:                                // get the value in db and pass it to the resolver.
0602:
0603:                                iChangedValsinDbOnly++;
0604:                                // Set the boolNull to false,
0605:                                // in order to set the actual value;
0606:                                boolNull = false;
0607:                                objVal = rsval;
0608:                            } else if ((orig == null || curr == null)) {
0609:
0610:                                /** Adding the additonal condition of checking for "flag" 
0611:                                 *  boolean variable, which would otherwise result in 
0612:                                 *  building a invalid query, as the comma would not be
0613:                                 *  added to the query string.
0614:                                 **/
0615:
0616:                                if (first == false || flag == false) {
0617:                                    updateExec += ", ";
0618:                                }
0619:                                updateExec += crs.getMetaData()
0620:                                        .getColumnName(i);
0621:                                cols.add(new Integer(i));
0622:                                updateExec += " = ? ";
0623:                                first = false;
0624:
0625:                                /** Adding the extra condition for orig to be "not" null as the 
0626:                                 *  condition for orig to be null is take prior to this, if this
0627:                                 *  is not added it will result in a NullPointerException when 
0628:                                 *  the values are compared.
0629:                                 **/
0630:
0631:                            } else if (orig.equals(curr)) {
0632:                                colsNotChanged++;
0633:                                //nothing to update in this case since values are equal
0634:
0635:                                /** Adding the extra condition for orig to be "not" null as the 
0636:                                 *  condition for orig to be null is take prior to this, if this
0637:                                 *  is not added it will result in a NullPointerException when 
0638:                                 *  the values are compared.
0639:                                 **/
0640:
0641:                            } else if (orig.equals(curr) == false) {
0642:                                // When values from db and values in CachedRowSet are not equal,
0643:                                // if db value is same as before updation for each col in
0644:                                // the row before fetching into CachedRowSet,
0645:                                // only then we go ahead with updation, else we
0646:                                // throw SyncProviderException.
0647:
0648:                                // if value has changed in db after fetching from db
0649:                                // for some cols of the row and at the same time, some other cols
0650:                                // have changed in CachedRowSet, no synchronization happens
0651:
0652:                                // Synchronization happens only when data when fetching is
0653:                                // same or at most has changed in cachedrowset
0654:
0655:                                // check orig value with what is there in crs for a column
0656:                                // before updation in crs.
0657:
0658:                                if (crs.columnUpdated(i)) {
0659:                                    if (rsval.equals(orig)) {
0660:                                        // At this point we are sure that
0661:                                        // the value updated in crs was from
0662:                                        // what is in db now and has not changed
0663:                                        if (flag == false || first == false) {
0664:                                            updateExec += ", ";
0665:                                        }
0666:                                        updateExec += crs.getMetaData()
0667:                                                .getColumnName(i);
0668:                                        cols.add(new Integer(i));
0669:                                        updateExec += " = ? ";
0670:                                        flag = false;
0671:                                    } else {
0672:                                        // Here the value has changed in the db after
0673:                                        // data was fetched
0674:                                        // Plus store this row from CachedRowSet and keep it
0675:                                        // in a new CachedRowSet
0676:                                        boolNull = false;
0677:                                        objVal = rsval;
0678:                                        iChangedValsInDbAndCRS++;
0679:                                    }
0680:                                }
0681:                            }
0682:
0683:                            if (!boolNull) {
0684:                                this .crsResolve.updateObject(i, objVal);
0685:                            } else {
0686:                                this .crsResolve.updateNull(i);
0687:                            }
0688:                        } //end for
0689:
0690:                        this .crsResolve.insertRow();
0691:                        this .crsResolve.moveToCurrentRow();
0692:
0693:                        /**
0694:                         * if nothing has changed return now - this can happen
0695:                         * if column is updated to the same value.
0696:                         * if colsNotChanged == callerColumnCount implies we are updating
0697:                         * the database with ALL COLUMNS HAVING SAME VALUES,
0698:                         * so skip going to database, else do as usual.
0699:                         **/
0700:                        if ((first == false && cols.size() == 0)
0701:                                || colsNotChanged == callerColumnCount) {
0702:                            return false;
0703:                        }
0704:
0705:                        if (iChangedValsInDbAndCRS != 0
0706:                                || iChangedValsinDbOnly != 0) {
0707:                            return true;
0708:                        }
0709:
0710:                        updateExec += updateWhere;
0711:
0712:                        pstmt = con.prepareStatement(updateExec);
0713:
0714:                        // Comments needed here
0715:                        for (i = 0; i < cols.size(); i++) {
0716:                            Object obj = crs.getObject(((Integer) cols.get(i))
0717:                                    .intValue());
0718:                            if (obj != null)
0719:                                pstmt.setObject(i + 1, obj);
0720:                            else
0721:                                pstmt.setNull(i + 1, crs.getMetaData()
0722:                                        .getColumnType(i + 1));
0723:                        }
0724:                        idx = i;
0725:
0726:                        // Comments needed here
0727:                        for (i = 0; i < keyCols.length; i++) {
0728:                            if (params[i] != null) {
0729:                                pstmt.setObject(++idx, params[i]);
0730:                            } else {
0731:                                continue;
0732:                            }
0733:                        }
0734:
0735:                        i = pstmt.executeUpdate();
0736:
0737:                        /**
0738:                         * i should be equal to 1(row count), because we update
0739:                         * one row(returned as row count) at a time, if all goes well.
0740:                         * if 1 != 1, this implies we have not been able to
0741:                         * do updations properly i.e there is a conflict in database
0742:                         * versus what is in CachedRowSet for this particular row.
0743:                         **/
0744:
0745:                        return false;
0746:
0747:                    } else {
0748:                        /**
0749:                         * Cursor will be here, if the ResultSet may not return even a single row
0750:                         * i.e. we can't find the row where to update because it has been deleted
0751:                         * etc. from the db.
0752:                         * Present the whole row as null to user, to force null to be sync'ed
0753:                         * and hence nothing to be synced.
0754:                         *
0755:                         * NOTE:
0756:                         * ------
0757:                         * In the database if a column that is mapped to java.sql.Types.REAL stores  
0758:                         * a Double value and is compared with value got from ResultSet.getFloat() 
0759:                         * no row is retrieved and will throw a SyncProviderException. For details
0760:                         * see bug Id 5053830
0761:                         **/
0762:                        return true;
0763:                    }
0764:                } catch (SQLException ex) {
0765:                    ex.printStackTrace();
0766:                    // if executeUpdate fails it will come here,
0767:                    // update crsResolve with null rows
0768:                    this .crsResolve.moveToInsertRow();
0769:
0770:                    for (i = 1; i <= callerColumnCount; i++) {
0771:                        this .crsResolve.updateNull(i);
0772:                    }
0773:
0774:                    this .crsResolve.insertRow();
0775:                    this .crsResolve.moveToCurrentRow();
0776:
0777:                    return true;
0778:                }
0779:            }
0780:
0781:            /**
0782:             * Inserts a row that has been inserted into the given
0783:             * <code>CachedRowSet</code> object into the data source from which
0784:             * the rowset is derived, returning <code>false</code> if the insertion
0785:             * was successful.
0786:             *
0787:             * @param crs the <code>CachedRowSet</code> object that has had a row inserted
0788:             *            and to whose underlying data source the row will be inserted
0789:             * @param pstmt the <code>PreparedStatement</code> object that will be used
0790:             *              to execute the insertion
0791:             * @return <code>false</code> to indicate that the insertion was successful;
0792:             *         <code>true</code> otherwise
0793:             * @throws SQLException if a database access error occurs
0794:             */
0795:            private boolean insertNewRow(CachedRowSet crs,
0796:                    PreparedStatement pstmt, CachedRowSetImpl crsRes)
0797:                    throws SQLException {
0798:                int i = 0;
0799:                int icolCount = crs.getMetaData().getColumnCount();
0800:
0801:                boolean returnVal = false;
0802:                PreparedStatement pstmtSel = con.prepareStatement(selectCmd,
0803:                        ResultSet.TYPE_SCROLL_SENSITIVE,
0804:                        ResultSet.CONCUR_READ_ONLY);
0805:                ResultSet rs, rs2 = null;
0806:                DatabaseMetaData dbmd = con.getMetaData();
0807:                rs = pstmtSel.executeQuery();
0808:                String table = crs.getTableName();
0809:                rs2 = dbmd.getPrimaryKeys(null, null, table);
0810:                String[] primaryKeys = new String[icolCount];
0811:                int k = 0;
0812:                while (rs2.next()) {
0813:                    String pkcolname = rs2.getString("COLUMN_NAME");
0814:                    primaryKeys[k] = pkcolname;
0815:                    k++;
0816:                }
0817:
0818:                if (rs.next()) {
0819:                    for (int j = 0; j < primaryKeys.length; j++) {
0820:                        if (primaryKeys[j] != null) {
0821:                            if (crs.getObject(primaryKeys[j]) == null) {
0822:                                break;
0823:                            }
0824:                            String crsPK = (crs.getObject(primaryKeys[j]))
0825:                                    .toString();
0826:                            String rsPK = (rs.getObject(primaryKeys[j]))
0827:                                    .toString();
0828:                            if (crsPK.equals(rsPK)) {
0829:                                returnVal = true;
0830:                                this .crsResolve.moveToInsertRow();
0831:                                for (i = 1; i <= icolCount; i++) {
0832:                                    String colname = (rs.getMetaData())
0833:                                            .getColumnName(i);
0834:                                    if (colname.equals(primaryKeys[j]))
0835:                                        this .crsResolve.updateObject(i, rsPK);
0836:                                    else
0837:                                        this .crsResolve.updateNull(i);
0838:                                }
0839:                                this .crsResolve.insertRow();
0840:                                this .crsResolve.moveToCurrentRow();
0841:                            }
0842:                        }
0843:                    }
0844:                }
0845:                if (returnVal)
0846:                    return returnVal;
0847:
0848:                try {
0849:                    for (i = 1; i <= icolCount; i++) {
0850:                        Object obj = crs.getObject(i);
0851:                        if (obj != null) {
0852:                            pstmt.setObject(i, obj);
0853:                        } else {
0854:                            pstmt
0855:                                    .setNull(i, crs.getMetaData()
0856:                                            .getColumnType(i));
0857:                        }
0858:                    }
0859:
0860:                    i = pstmt.executeUpdate();
0861:                    return false;
0862:
0863:                } catch (SQLException ex) {
0864:                    /**
0865:                     * Cursor will come here if executeUpdate fails.
0866:                     * There can be many reasons why the insertion failed,
0867:                     * one can be violation of primary key.
0868:                     * Hence we cannot exactly identify why the insertion failed
0869:                     * Present the current row as a null row to the user.
0870:                     **/
0871:                    this .crsResolve.moveToInsertRow();
0872:
0873:                    for (i = 1; i <= icolCount; i++) {
0874:                        this .crsResolve.updateNull(i);
0875:                    }
0876:
0877:                    this .crsResolve.insertRow();
0878:                    this .crsResolve.moveToCurrentRow();
0879:
0880:                    return true;
0881:                }
0882:            }
0883:
0884:            /**
0885:             * Deletes the row in the underlying data source that corresponds to
0886:             * a row that has been deleted in the given <code> CachedRowSet</code> object
0887:             * and returns <code>false</code> if the deletion was successful.
0888:             * <P>
0889:             * This method is called internally by this writer's <code>writeData</code>
0890:             * method when a row in the rowset has been deleted. The values in the
0891:             * deleted row are the same as those that are stored in the original row
0892:             * of the given <code>CachedRowSet</code> object.  If the values in the
0893:             * original row differ from the row in the underlying data source, the row
0894:             * in the data source is not deleted, and <code>deleteOriginalRow</code>
0895:             * returns <code>true</code> to indicate that there was a conflict.
0896:             *
0897:             *
0898:             * @return <code>false</code> if the deletion was successful, which means that
0899:             *         there was no conflict; <code>true</code> otherwise
0900:             * @throws SQLException if there was a database access error
0901:             */
0902:            private boolean deleteOriginalRow(CachedRowSet crs,
0903:                    CachedRowSetImpl crsRes) throws SQLException {
0904:                PreparedStatement pstmt;
0905:                int i;
0906:                int idx = 0;
0907:                String strSelect;
0908:                // Select the row from the database.
0909:                ResultSet origVals = crs.getOriginalRow();
0910:                origVals.next();
0911:
0912:                deleteWhere = buildWhereClause(deleteWhere, origVals);
0913:                pstmt = con.prepareStatement(selectCmd + deleteWhere,
0914:                        ResultSet.TYPE_SCROLL_SENSITIVE,
0915:                        ResultSet.CONCUR_READ_ONLY);
0916:
0917:                for (i = 0; i < keyCols.length; i++) {
0918:                    if (params[i] != null) {
0919:                        pstmt.setObject(++idx, params[i]);
0920:                    } else {
0921:                        continue;
0922:                    }
0923:                }
0924:
0925:                try {
0926:                    pstmt.setMaxRows(crs.getMaxRows());
0927:                    pstmt.setMaxFieldSize(crs.getMaxFieldSize());
0928:                    pstmt.setEscapeProcessing(crs.getEscapeProcessing());
0929:                    pstmt.setQueryTimeout(crs.getQueryTimeout());
0930:                } catch (Exception ex) {
0931:                    /*
0932:                     * Older driver don't support these operations...
0933:                     */
0934:                    ;
0935:                }
0936:
0937:                ResultSet rs = pstmt.executeQuery();
0938:
0939:                if (rs.next() == true) {
0940:                    if (rs.next()) {
0941:                        // more than one row
0942:                        return true;
0943:                    }
0944:                    rs.first();
0945:
0946:                    // Now check all the values in rs to be same in
0947:                    // db also before actually going ahead with deleting
0948:                    boolean boolChanged = false;
0949:
0950:                    crsRes.moveToInsertRow();
0951:
0952:                    for (i = 1; i <= crs.getMetaData().getColumnCount(); i++) {
0953:
0954:                        Object original = origVals.getObject(i);
0955:                        Object changed = rs.getObject(i);
0956:
0957:                        if (original != null && changed != null) {
0958:                            if (!(original.toString()).equals(changed
0959:                                    .toString())) {
0960:                                boolChanged = true;
0961:                                crsRes.updateObject(i, origVals.getObject(i));
0962:                            }
0963:                        } else {
0964:                            crsRes.updateNull(i);
0965:                        }
0966:                    }
0967:
0968:                    crsRes.insertRow();
0969:                    crsRes.moveToCurrentRow();
0970:
0971:                    if (boolChanged) {
0972:                        // do not delete as values in db have changed
0973:                        // deletion will not happen for this row from db
0974:                        // exit now returning true. i.e. conflict
0975:                        return true;
0976:                    } else {
0977:                        // delete the row.
0978:                        // Go ahead with deleting,
0979:                        // don't do anything here
0980:                    }
0981:
0982:                    String cmd = deleteCmd + deleteWhere;
0983:                    pstmt = con.prepareStatement(cmd);
0984:
0985:                    idx = 0;
0986:                    for (i = 0; i < keyCols.length; i++) {
0987:                        if (params[i] != null) {
0988:                            pstmt.setObject(++idx, params[i]);
0989:                        } else {
0990:                            continue;
0991:                        }
0992:                    }
0993:
0994:                    if (pstmt.executeUpdate() != 1) {
0995:                        return true;
0996:                    }
0997:                    pstmt.close();
0998:                } else {
0999:                    // didn't find the row
1000:                    return true;
1001:                }
1002:
1003:                // no conflict
1004:                return false;
1005:            }
1006:
1007:            /**
1008:             * Sets the reader for this writer to the given reader.
1009:             *
1010:             * @throws SQLException if a database access error occurs
1011:             */
1012:            public void setReader(CachedRowSetReader reader)
1013:                    throws SQLException {
1014:                this .reader = reader;
1015:            }
1016:
1017:            /**
1018:             * Gets the reader for this writer.
1019:             *
1020:             * @throws SQLException if a database access error occurs
1021:             */
1022:            public CachedRowSetReader getReader() throws SQLException {
1023:                return reader;
1024:            }
1025:
1026:            /**
1027:             * Composes a <code>SELECT</code>, <code>UPDATE</code>, <code>INSERT</code>,
1028:             * and <code>DELETE</code> statement that can be used by this writer to
1029:             * write data to the data source backing the given <code>CachedRowSet</code>
1030:             * object.
1031:             *
1032:             * @ param caller a <code>CachedRowSet</code> object for which this
1033:             *                <code>CachedRowSetWriter</code> object is the writer
1034:             * @throws SQLException if a database access error occurs
1035:             */
1036:            private void initSQLStatements(CachedRowSet caller)
1037:                    throws SQLException {
1038:
1039:                int i;
1040:
1041:                callerMd = caller.getMetaData();
1042:                callerColumnCount = callerMd.getColumnCount();
1043:                if (callerColumnCount < 1)
1044:                    // No data, so return.
1045:                    return;
1046:
1047:                /*
1048:                 * If the RowSet has a Table name we should use it.
1049:                 * This is really a hack to get round the fact that
1050:                 * a lot of the jdbc drivers can't provide the tab.
1051:                 */
1052:                String table = caller.getTableName();
1053:                if (table == null) {
1054:                    /*
1055:                     * attempt to build a table name using the info
1056:                     * that the driver gave us for the first column
1057:                     * in the source result set.
1058:                     */
1059:                    table = callerMd.getTableName(1);
1060:                    if (table == null || table.length() == 0) {
1061:                        throw new SQLException(resBundle.handleGetObject(
1062:                                "crswriter.tname").toString());
1063:                    }
1064:                }
1065:                String catalog = callerMd.getCatalogName(1);
1066:                String schema = callerMd.getSchemaName(1);
1067:                DatabaseMetaData dbmd = con.getMetaData();
1068:
1069:                /*
1070:                 * Compose a SELECT statement.  There are three parts.
1071:                 */
1072:
1073:                // Project List
1074:                selectCmd = "SELECT ";
1075:                for (i = 1; i <= callerColumnCount; i++) {
1076:                    selectCmd += callerMd.getColumnName(i);
1077:                    if (i < callerMd.getColumnCount())
1078:                        selectCmd += ", ";
1079:                    else
1080:                        selectCmd += " ";
1081:                }
1082:
1083:                // FROM clause.
1084:                selectCmd += "FROM "
1085:                        + buildTableName(dbmd, catalog, schema, table);
1086:
1087:                /*
1088:                 * Compose an UPDATE statement.
1089:                 */
1090:                updateCmd = "UPDATE "
1091:                        + buildTableName(dbmd, catalog, schema, table);
1092:
1093:                /**
1094:                 *  The following block of code is for checking a particular type of
1095:                 *  query where in there is a where clause. Without this block, if a
1096:                 *  SQL statement is built the "where" clause will appear twice hence
1097:                 *  the DB errors out and a SQLException is thrown. This code also 
1098:                 *  considers that the where clause is in the right place as the 
1099:                 *  CachedRowSet object would already have been populated with this
1100:                 *  query before coming to this point.
1101:                 **/
1102:
1103:                String tempupdCmd = updateCmd.toLowerCase();
1104:
1105:                int idxupWhere = tempupdCmd.indexOf("where");
1106:
1107:                if (idxupWhere != -1) {
1108:                    updateCmd = updateCmd.substring(0, idxupWhere);
1109:                }
1110:                updateCmd += "SET ";
1111:
1112:                /*
1113:                 * Compose an INSERT statement.
1114:                 */
1115:                insertCmd = "INSERT INTO "
1116:                        + buildTableName(dbmd, catalog, schema, table);
1117:                // Column list
1118:                insertCmd += "(";
1119:                for (i = 1; i <= callerColumnCount; i++) {
1120:                    insertCmd += callerMd.getColumnName(i);
1121:                    if (i < callerMd.getColumnCount())
1122:                        insertCmd += ", ";
1123:                    else
1124:                        insertCmd += ") VALUES (";
1125:                }
1126:                for (i = 1; i <= callerColumnCount; i++) {
1127:                    insertCmd += "?";
1128:                    if (i < callerColumnCount)
1129:                        insertCmd += ", ";
1130:                    else
1131:                        insertCmd += ")";
1132:                }
1133:
1134:                /*
1135:                 * Compose a DELETE statement.
1136:                 */
1137:                deleteCmd = "DELETE FROM "
1138:                        + buildTableName(dbmd, catalog, schema, table);
1139:
1140:                /*
1141:                 * set the key desriptors that will be
1142:                 * needed to construct where clauses.
1143:                 */
1144:                buildKeyDesc(caller);
1145:            }
1146:
1147:            /**
1148:             * Returns a fully qualified table name built from the given catalog and
1149:             * table names. The given metadata object is used to get the proper order
1150:             * and separator.
1151:             *
1152:             * @param dbmd a <code>DatabaseMetaData</code> object that contains metadata
1153:             * 		about this writer's <code>CachedRowSet</code> object
1154:             * @param catalog a <code>String</code> object with the rowset's catalog
1155:             * 		name
1156:             * @param table a <code>String</code> object with the name of the table from
1157:             * 		which this writer's rowset was derived
1158:             * @return a <code>String</code> object with the fully qualified name of the
1159:             *		table from which this writer's rowset was derived
1160:             * @throws SQLException if a database access error occurs
1161:             */
1162:            private String buildTableName(DatabaseMetaData dbmd,
1163:                    String catalog, String schema, String table)
1164:                    throws SQLException {
1165:
1166:                // trim all the leading and trailing whitespaces,
1167:                // white spaces can never be catalog, schema or a table name.
1168:
1169:                String cmd = new String();
1170:
1171:                catalog = catalog.trim();
1172:                schema = schema.trim();
1173:                table = table.trim();
1174:
1175:                if (dbmd.isCatalogAtStart() == true) {
1176:                    if (catalog != null && catalog.length() > 0) {
1177:                        cmd += catalog + dbmd.getCatalogSeparator();
1178:                    }
1179:                    if (schema != null && schema.length() > 0) {
1180:                        cmd += schema + ".";
1181:                    }
1182:                    cmd += table;
1183:                } else {
1184:                    if (schema != null && schema.length() > 0) {
1185:                        cmd += schema + ".";
1186:                    }
1187:                    cmd += table;
1188:                    if (catalog != null && catalog.length() > 0) {
1189:                        cmd += dbmd.getCatalogSeparator() + catalog;
1190:                    }
1191:                }
1192:                cmd += " ";
1193:                return cmd;
1194:            }
1195:
1196:            /**
1197:             * Assigns to the given <code>CachedRowSet</code> object's
1198:             * <code>params</code>
1199:             * field an array whose length equals the number of columns needed
1200:             * to uniquely identify a row in the rowset. The array is given
1201:             * values by the method <code>buildWhereClause</code>.
1202:             * <P>
1203:             * If the <code>CachedRowSet</code> object's <code>keyCols</code>
1204:             * field has length <code>0</code> or is <code>null</code>, the array
1205:             * is set with the column number of every column in the rowset.
1206:             * Otherwise, the array in the field <code>keyCols</code> is set with only
1207:             * the column numbers of the columns that are required to form a unique
1208:             * identifier for a row.
1209:             *
1210:             * @param crs the <code>CachedRowSet</code> object for which this
1211:             *     <code>CachedRowSetWriter</code> object is the writer
1212:             *
1213:             * @throws SQLException if a database access error occurs
1214:             */
1215:            private void buildKeyDesc(CachedRowSet crs) throws SQLException {
1216:
1217:                keyCols = crs.getKeyColumns();
1218:                if (keyCols == null || keyCols.length == 0) {
1219:                    keyCols = new int[callerColumnCount];
1220:                    for (int i = 0; i < keyCols.length;) {
1221:                        keyCols[i] = ++i;
1222:                    }
1223:                }
1224:                params = new Object[keyCols.length];
1225:            }
1226:
1227:            /**
1228:             * Constructs an SQL <code>WHERE</code> clause using the given
1229:             * string as a starting point. The resulting clause will contain
1230:             * a column name and " = ?" for each key column, that is, each column
1231:             * that is needed to form a unique identifier for a row in the rowset.
1232:             * This <code>WHERE</code> clause can be added to
1233:             * a <code>PreparedStatement</code> object that updates, inserts, or
1234:             * deletes a row.
1235:             * <P>
1236:             * This method uses the given result set to access values in the
1237:             * <code>CachedRowSet</code> object that called this writer.  These
1238:             * values are used to build the array of parameters that will serve as
1239:             * replacements for the "?" parameter placeholders in the
1240:             * <code>PreparedStatement</code> object that is sent to the
1241:             * <code>CachedRowSet</code> object's underlying data source.
1242:             *
1243:             * @param whereClause a <code>String</code> object that is an empty
1244:             *                    string ("")
1245:             * @param rs a <code>ResultSet</code> object that can be used
1246:             *           to access the <code>CachedRowSet</code> object's data
1247:             * @return a <code>WHERE</code> clause of the form "<code>WHERE</code>
1248:             *         columnName = ? AND columnName = ? AND columnName = ? ..."
1249:             * @throws SQLException if a database access error occurs
1250:             */
1251:            private String buildWhereClause(String whereClause, ResultSet rs)
1252:                    throws SQLException {
1253:                whereClause = "WHERE ";
1254:
1255:                for (int i = 0; i < keyCols.length; i++) {
1256:                    if (i > 0) {
1257:                        whereClause += "AND ";
1258:                    }
1259:                    whereClause += callerMd.getColumnName(keyCols[i]);
1260:                    params[i] = rs.getObject(keyCols[i]);
1261:                    if (rs.wasNull() == true) {
1262:                        whereClause += " IS NULL ";
1263:                    } else {
1264:                        whereClause += " = ? ";
1265:                    }
1266:                }
1267:                return whereClause;
1268:            }
1269:
1270:            void updateResolvedConflictToDB(CachedRowSet crs, Connection con)
1271:                    throws SQLException {
1272:                //String updateExe = ;
1273:                PreparedStatement pStmt;
1274:                String strWhere = "WHERE ";
1275:                String strExec = " ";
1276:                String strUpdate = "UPDATE ";
1277:                int icolCount = crs.getMetaData().getColumnCount();
1278:                int keyColumns[] = crs.getKeyColumns();
1279:                Object param[];
1280:                String strSet = "";
1281:
1282:                strWhere = buildWhereClause(strWhere, crs);
1283:
1284:                if (keyColumns == null || keyColumns.length == 0) {
1285:                    keyColumns = new int[icolCount];
1286:                    for (int i = 0; i < keyColumns.length;) {
1287:                        keyColumns[i] = ++i;
1288:                    }
1289:                }
1290:                param = new Object[keyColumns.length];
1291:
1292:                strUpdate = "UPDATE "
1293:                        + buildTableName(con.getMetaData(), crs.getMetaData()
1294:                                .getCatalogName(1), crs.getMetaData()
1295:                                .getSchemaName(1), crs.getTableName());
1296:
1297:                // changed or updated values will become part of
1298:                // set clause here
1299:                strUpdate += "SET ";
1300:
1301:                boolean first = true;
1302:
1303:                for (int i = 1; i <= icolCount; i++) {
1304:                    if (crs.columnUpdated(i)) {
1305:                        if (first == false) {
1306:                            strSet += ", ";
1307:                        }
1308:                        strSet += crs.getMetaData().getColumnName(i);
1309:                        strSet += " = ? ";
1310:                        first = false;
1311:                    } //end if
1312:                } //end for
1313:
1314:                // keycols will become part of where clause
1315:                strUpdate += strSet;
1316:                strWhere = "WHERE ";
1317:
1318:                for (int i = 0; i < keyColumns.length; i++) {
1319:                    if (i > 0) {
1320:                        strWhere += "AND ";
1321:                    }
1322:                    strWhere += crs.getMetaData().getColumnName(keyColumns[i]);
1323:                    param[i] = crs.getObject(keyColumns[i]);
1324:                    if (crs.wasNull() == true) {
1325:                        strWhere += " IS NULL ";
1326:                    } else {
1327:                        strWhere += " = ? ";
1328:                    }
1329:                }
1330:                strUpdate += strWhere;
1331:
1332:                pStmt = con.prepareStatement(strUpdate);
1333:
1334:                int idx = 0;
1335:                for (int i = 0; i < icolCount; i++) {
1336:                    if (crs.columnUpdated(i + 1)) {
1337:                        Object obj = crs.getObject(i + 1);
1338:                        if (obj != null) {
1339:                            pStmt.setObject(++idx, obj);
1340:                        } else {
1341:                            pStmt.setNull(i + 1, crs.getMetaData()
1342:                                    .getColumnType(i + 1));
1343:                        } //end if ..else
1344:                    } //end if crs.column...
1345:                } //end for
1346:
1347:                // Set the key cols for after WHERE =? clause
1348:                for (int i = 0; i < keyColumns.length; i++) {
1349:                    if (param[i] != null) {
1350:                        pStmt.setObject(++idx, param[i]);
1351:                    }
1352:                }
1353:
1354:                int id = pStmt.executeUpdate();
1355:            }
1356:
1357:            /**
1358:             *
1359:             */
1360:            public void commit() throws SQLException {
1361:                con.commit();
1362:                if (reader.getCloseConnection() == true) {
1363:                    con.close();
1364:                }
1365:            }
1366:
1367:            public void commit(CachedRowSetImpl crs, boolean updateRowset)
1368:                    throws SQLException {
1369:                con.commit();
1370:                if (updateRowset) {
1371:                    if (crs.getCommand() != null)
1372:                        crs.execute(con);
1373:                }
1374:
1375:                if (reader.getCloseConnection() == true) {
1376:                    con.close();
1377:                }
1378:            }
1379:
1380:            /**
1381:             *
1382:             */
1383:            public void rollback() throws SQLException {
1384:                con.rollback();
1385:                if (reader.getCloseConnection() == true) {
1386:                    con.close();
1387:                }
1388:            }
1389:
1390:            /**
1391:             *
1392:             */
1393:            public void rollback(Savepoint s) throws SQLException {
1394:                con.rollback(s);
1395:                if (reader.getCloseConnection() == true) {
1396:                    con.close();
1397:                }
1398:            }
1399:
1400:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.