Source Code Cross Referenced for AbstractJdbc2ResultSet.java in  » Database-JDBC-Connection-Pool » postgresql » org » postgresql » jdbc2 » 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 » Database JDBC Connection Pool » postgresql » org.postgresql.jdbc2 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*-------------------------------------------------------------------------
0002:         *
0003:         * Copyright (c) 2003-2005, PostgreSQL Global Development Group
0004:         *
0005:         * IDENTIFICATION
0006:         *   $PostgreSQL: pgjdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java,v 1.98 2007/07/27 22:55:28 jurka Exp $
0007:         *
0008:         *-------------------------------------------------------------------------
0009:         */
0010:        package org.postgresql.jdbc2;
0011:
0012:        import java.io.CharArrayReader;
0013:        import java.io.InputStream;
0014:        import java.io.IOException;
0015:        import java.io.InputStreamReader;
0016:        import java.io.UnsupportedEncodingException;
0017:        import java.io.ByteArrayInputStream;
0018:        import java.math.BigDecimal;
0019:        import java.math.BigInteger;
0020:        import java.sql.*;
0021:        import java.util.HashMap;
0022:        import java.util.Iterator;
0023:        import java.util.StringTokenizer;
0024:        import java.util.Vector;
0025:        import java.util.Calendar;
0026:        import org.postgresql.core.*;
0027:        import org.postgresql.largeobject.*;
0028:        import org.postgresql.util.PGobject;
0029:        import org.postgresql.util.PGbytea;
0030:        import org.postgresql.util.PGtokenizer;
0031:        import org.postgresql.util.PSQLException;
0032:        import org.postgresql.util.PSQLState;
0033:        import org.postgresql.util.GT;
0034:
0035:        public abstract class AbstractJdbc2ResultSet implements  BaseResultSet,
0036:                org.postgresql.PGRefCursorResultSet {
0037:
0038:            //needed for updateable result set support
0039:            private boolean updateable = false;
0040:            private boolean doingUpdates = false;
0041:            private HashMap updateValues = null;
0042:            private boolean usingOID = false; // are we using the OID for the primary key?
0043:            private Vector primaryKeys; // list of primary keys
0044:            private boolean singleTable = false;
0045:            private String tableName = null;
0046:            private PreparedStatement updateStatement = null;
0047:            private PreparedStatement insertStatement = null;
0048:            private PreparedStatement deleteStatement = null;
0049:            private PreparedStatement selectStatement = null;
0050:            private int resultsettype;
0051:            private int resultsetconcurrency;
0052:            private int fetchdirection = ResultSet.FETCH_UNKNOWN;
0053:            protected final BaseConnection connection; // the connection we belong to
0054:            protected final BaseStatement statement; // the statement we belong to
0055:            protected final Field fields[]; // Field metadata for this resultset.
0056:            protected final Query originalQuery; // Query we originated from
0057:
0058:            protected final int maxRows; // Maximum rows in this resultset (might be 0).
0059:            protected final int maxFieldSize; // Maximum field size in this resultset (might be 0).
0060:
0061:            protected Vector rows; // Current page of results.
0062:            protected int current_row = -1; // Index into 'rows' of our currrent row (0-based)
0063:            protected int row_offset; // Offset of row 0 in the actual resultset
0064:            protected byte[][] this _row; // copy of the current result row
0065:            protected SQLWarning warnings = null; // The warning chain
0066:            /**
0067:             * True if the last obtained column value was SQL NULL as specified by
0068:             * {@link #wasNull}. The value is always updated by the
0069:             * {@link #checkResultSet} method.
0070:             */
0071:            protected boolean wasNullFlag = false;
0072:            protected boolean onInsertRow = false; // are we on the insert row (for JDBC2 updatable resultsets)?
0073:
0074:            public byte[][] rowBuffer = null; // updateable rowbuffer
0075:
0076:            protected int fetchSize; // Current fetch size (might be 0).
0077:            protected ResultCursor cursor; // Cursor for fetching additional data.
0078:
0079:            private HashMap columnNameIndexMap; // Speed up findColumn by caching lookups
0080:
0081:            public abstract ResultSetMetaData getMetaData() throws SQLException;
0082:
0083:            public AbstractJdbc2ResultSet(Query originalQuery,
0084:                    BaseStatement statement, Field[] fields, Vector tuples,
0085:                    ResultCursor cursor, int maxRows, int maxFieldSize,
0086:                    int rsType, int rsConcurrency) throws SQLException {
0087:                this .originalQuery = originalQuery;
0088:                this .connection = (BaseConnection) statement.getConnection();
0089:                this .statement = statement;
0090:                this .fields = fields;
0091:                this .rows = tuples;
0092:                this .cursor = cursor;
0093:                this .maxRows = maxRows;
0094:                this .maxFieldSize = maxFieldSize;
0095:                this .resultsettype = rsType;
0096:                this .resultsetconcurrency = rsConcurrency;
0097:            }
0098:
0099:            public java.net.URL getURL(int columnIndex) throws SQLException {
0100:                checkClosed();
0101:                throw org.postgresql.Driver.notImplemented(this .getClass(),
0102:                        "getURL(int)");
0103:            }
0104:
0105:            public java.net.URL getURL(String columnName) throws SQLException {
0106:                return getURL(findColumn(columnName));
0107:            }
0108:
0109:            protected Object internalGetObject(int columnIndex, Field field)
0110:                    throws SQLException {
0111:                switch (getSQLType(columnIndex)) {
0112:                case Types.BIT:
0113:                    // Also Types.BOOLEAN in JDBC3
0114:                    return getBoolean(columnIndex) ? Boolean.TRUE
0115:                            : Boolean.FALSE;
0116:                case Types.TINYINT:
0117:                case Types.SMALLINT:
0118:                case Types.INTEGER:
0119:                    return new Integer(getInt(columnIndex));
0120:                case Types.BIGINT:
0121:                    return new Long(getLong(columnIndex));
0122:                case Types.NUMERIC:
0123:                case Types.DECIMAL:
0124:                    return getBigDecimal(columnIndex,
0125:                            (field.getMod() == -1) ? -1
0126:                                    : ((field.getMod() - 4) & 0xffff));
0127:                case Types.REAL:
0128:                    return new Float(getFloat(columnIndex));
0129:                case Types.FLOAT:
0130:                case Types.DOUBLE:
0131:                    return new Double(getDouble(columnIndex));
0132:                case Types.CHAR:
0133:                case Types.VARCHAR:
0134:                case Types.LONGVARCHAR:
0135:                    return getString(columnIndex);
0136:                case Types.DATE:
0137:                    return getDate(columnIndex);
0138:                case Types.TIME:
0139:                    return getTime(columnIndex);
0140:                case Types.TIMESTAMP:
0141:                    return getTimestamp(columnIndex, null);
0142:                case Types.BINARY:
0143:                case Types.VARBINARY:
0144:                case Types.LONGVARBINARY:
0145:                    return getBytes(columnIndex);
0146:                case Types.ARRAY:
0147:                    return getArray(columnIndex);
0148:                case Types.CLOB:
0149:                    return getClob(columnIndex);
0150:                case Types.BLOB:
0151:                    return getBlob(columnIndex);
0152:
0153:                default:
0154:                    String type = getPGType(columnIndex);
0155:
0156:                    // if the backend doesn't know the type then coerce to String
0157:                    if (type.equals("unknown"))
0158:                        return getString(columnIndex);
0159:
0160:                    // Specialized support for ref cursors is neater.
0161:                    if (type.equals("refcursor")) {
0162:                        // Fetch all results.
0163:                        String cursorName = getString(columnIndex);
0164:
0165:                        StringBuffer sb = new StringBuffer("FETCH ALL IN ");
0166:                        Utils.appendEscapedIdentifier(sb, cursorName);
0167:
0168:                        // nb: no BEGIN triggered here. This is fine. If someone
0169:                        // committed, and the cursor was not holdable (closing the
0170:                        // cursor), we avoid starting a new xact and promptly causing
0171:                        // it to fail. If the cursor *was* holdable, we don't want a
0172:                        // new xact anyway since holdable cursor state isn't affected
0173:                        // by xact boundaries. If our caller didn't commit at all, or
0174:                        // autocommit was on, then we wouldn't issue a BEGIN anyway.
0175:                        //
0176:                        // We take the scrollability from the statement, but until
0177:                        // we have updatable cursors it must be readonly.
0178:                        ResultSet rs = connection.execSQLQuery(sb.toString(),
0179:                                resultsettype, ResultSet.CONCUR_READ_ONLY);
0180:                        //
0181:                        // In long running transactions these backend cursors take up memory space
0182:                        // we could close in rs.close(), but if the transaction is closed before the result set, then
0183:                        // the cursor no longer exists
0184:
0185:                        sb.setLength(0);
0186:                        sb.append("CLOSE ");
0187:                        Utils.appendEscapedIdentifier(sb, cursorName);
0188:                        connection.execSQLUpdate(sb.toString());
0189:                        ((AbstractJdbc2ResultSet) rs).setRefCursor(cursorName);
0190:                        return rs;
0191:                    }
0192:
0193:                    // Caller determines what to do (JDBC3 overrides in this case)
0194:                    return null;
0195:                }
0196:            }
0197:
0198:            private void checkScrollable() throws SQLException {
0199:                checkClosed();
0200:                if (resultsettype == ResultSet.TYPE_FORWARD_ONLY)
0201:                    throw new PSQLException(
0202:                            GT
0203:                                    .tr("Operation requires a scrollable ResultSet, but this ResultSet is FORWARD_ONLY."),
0204:                            PSQLState.INVALID_CURSOR_STATE);
0205:            }
0206:
0207:            public boolean absolute(int index) throws SQLException {
0208:                checkScrollable();
0209:
0210:                // index is 1-based, but internally we use 0-based indices
0211:                int internalIndex;
0212:
0213:                if (index == 0) {
0214:                    beforeFirst();
0215:                    return false;
0216:                }
0217:
0218:                final int rows_size = rows.size();
0219:
0220:                //if index<0, count from the end of the result set, but check
0221:                //to be sure that it is not beyond the first index
0222:                if (index < 0) {
0223:                    if (index >= -rows_size)
0224:                        internalIndex = rows_size + index;
0225:                    else {
0226:                        beforeFirst();
0227:                        return false;
0228:                    }
0229:                } else {
0230:                    //must be the case that index>0,
0231:                    //find the correct place, assuming that
0232:                    //the index is not too large
0233:                    if (index <= rows_size)
0234:                        internalIndex = index - 1;
0235:                    else {
0236:                        afterLast();
0237:                        return false;
0238:                    }
0239:                }
0240:
0241:                current_row = internalIndex;
0242:                this _row = (byte[][]) rows.elementAt(internalIndex);
0243:
0244:                rowBuffer = new byte[this _row.length][];
0245:                System.arraycopy(this _row, 0, rowBuffer, 0, this _row.length);
0246:                onInsertRow = false;
0247:
0248:                return true;
0249:            }
0250:
0251:            public void afterLast() throws SQLException {
0252:                checkScrollable();
0253:
0254:                final int rows_size = rows.size();
0255:                if (rows_size > 0)
0256:                    current_row = rows_size;
0257:
0258:                onInsertRow = false;
0259:                this _row = null;
0260:                rowBuffer = null;
0261:            }
0262:
0263:            public void beforeFirst() throws SQLException {
0264:                checkScrollable();
0265:
0266:                if (rows.size() > 0)
0267:                    current_row = -1;
0268:
0269:                onInsertRow = false;
0270:                this _row = null;
0271:                rowBuffer = null;
0272:            }
0273:
0274:            public boolean first() throws SQLException {
0275:                checkScrollable();
0276:
0277:                if (rows.size() <= 0)
0278:                    return false;
0279:
0280:                current_row = 0;
0281:                this _row = (byte[][]) rows.elementAt(current_row);
0282:
0283:                rowBuffer = new byte[this _row.length][];
0284:                System.arraycopy(this _row, 0, rowBuffer, 0, this _row.length);
0285:                onInsertRow = false;
0286:
0287:                return true;
0288:            }
0289:
0290:            public java.sql.Array getArray(String colName) throws SQLException {
0291:                return getArray(findColumn(colName));
0292:            }
0293:
0294:            public java.sql.Array getArray(int i) throws SQLException {
0295:                checkResultSet(i);
0296:                if (wasNullFlag)
0297:                    return null;
0298:
0299:                return createArray(i);
0300:            }
0301:
0302:            public java.math.BigDecimal getBigDecimal(int columnIndex)
0303:                    throws SQLException {
0304:                return getBigDecimal(columnIndex, -1);
0305:            }
0306:
0307:            public java.math.BigDecimal getBigDecimal(String columnName)
0308:                    throws SQLException {
0309:                return getBigDecimal(findColumn(columnName));
0310:            }
0311:
0312:            public Blob getBlob(String columnName) throws SQLException {
0313:                return getBlob(findColumn(columnName));
0314:            }
0315:
0316:            public abstract Blob getBlob(int i) throws SQLException;
0317:
0318:            public java.io.Reader getCharacterStream(String columnName)
0319:                    throws SQLException {
0320:                return getCharacterStream(findColumn(columnName));
0321:            }
0322:
0323:            public java.io.Reader getCharacterStream(int i) throws SQLException {
0324:                checkResultSet(i);
0325:                if (wasNullFlag)
0326:                    return null;
0327:
0328:                if (((AbstractJdbc2Connection) connection)
0329:                        .haveMinimumCompatibleVersion("7.2")) {
0330:                    //Version 7.2 supports AsciiStream for all the PG text types
0331:                    //As the spec/javadoc for this method indicate this is to be used for
0332:                    //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
0333:                    //long string datatype, but with toast the text datatype is capable of
0334:                    //handling very large values.  Thus the implementation ends up calling
0335:                    //getString() since there is no current way to stream the value from the server
0336:                    return new CharArrayReader(getString(i).toCharArray());
0337:                } else {
0338:                    // In 7.1 Handle as BLOBS so return the LargeObject input stream
0339:                    Encoding encoding = connection.getEncoding();
0340:                    InputStream input = getBinaryStream(i);
0341:
0342:                    try {
0343:                        return encoding.getDecodingReader(input);
0344:                    } catch (IOException ioe) {
0345:                        throw new PSQLException(
0346:                                GT
0347:                                        .tr("Unexpected error while decoding character data from a large object."),
0348:                                PSQLState.UNEXPECTED_ERROR, ioe);
0349:                    }
0350:                }
0351:            }
0352:
0353:            public Clob getClob(String columnName) throws SQLException {
0354:                return getClob(findColumn(columnName));
0355:            }
0356:
0357:            public abstract Clob getClob(int i) throws SQLException;
0358:
0359:            public int getConcurrency() throws SQLException {
0360:                checkClosed();
0361:                return resultsetconcurrency;
0362:            }
0363:
0364:            public java.sql.Date getDate(int i, java.util.Calendar cal)
0365:                    throws SQLException {
0366:                checkResultSet(i);
0367:                if (wasNullFlag)
0368:                    return null;
0369:
0370:                if (cal != null)
0371:                    cal = (Calendar) cal.clone();
0372:
0373:                return connection.getTimestampUtils().toDate(cal, getString(i));
0374:            }
0375:
0376:            public Time getTime(int i, java.util.Calendar cal)
0377:                    throws SQLException {
0378:                checkResultSet(i);
0379:                if (wasNullFlag)
0380:                    return null;
0381:
0382:                if (cal != null)
0383:                    cal = (Calendar) cal.clone();
0384:
0385:                return connection.getTimestampUtils().toTime(cal, getString(i));
0386:            }
0387:
0388:            public Timestamp getTimestamp(int i, java.util.Calendar cal)
0389:                    throws SQLException {
0390:                checkResultSet(i);
0391:                if (wasNullFlag)
0392:                    return null;
0393:
0394:                if (cal != null)
0395:                    cal = (Calendar) cal.clone();
0396:
0397:                // If this is actually a timestamptz, the server-provided timezone will override
0398:                // the one we pass in, which is the desired behaviour. Otherwise, we'll
0399:                // interpret the timezone-less value in the provided timezone.
0400:                return connection.getTimestampUtils().toTimestamp(cal,
0401:                        getString(i));
0402:            }
0403:
0404:            public java.sql.Date getDate(String c, java.util.Calendar cal)
0405:                    throws SQLException {
0406:                return getDate(findColumn(c), cal);
0407:            }
0408:
0409:            public Time getTime(String c, java.util.Calendar cal)
0410:                    throws SQLException {
0411:                return getTime(findColumn(c), cal);
0412:            }
0413:
0414:            public Timestamp getTimestamp(String c, java.util.Calendar cal)
0415:                    throws SQLException {
0416:                return getTimestamp(findColumn(c), cal);
0417:            }
0418:
0419:            public int getFetchDirection() throws SQLException {
0420:                checkClosed();
0421:                return fetchdirection;
0422:            }
0423:
0424:            public Object getObjectImpl(String columnName, java.util.Map map)
0425:                    throws SQLException {
0426:                return getObjectImpl(findColumn(columnName), map);
0427:            }
0428:
0429:            /*
0430:             * This checks against map for the type of column i, and if found returns
0431:             * an object based on that mapping. The class must implement the SQLData
0432:             * interface.
0433:             */
0434:            public Object getObjectImpl(int i, java.util.Map map)
0435:                    throws SQLException {
0436:                checkClosed();
0437:                if (map == null || map.isEmpty()) {
0438:                    return getObject(i);
0439:                }
0440:                throw org.postgresql.Driver.notImplemented(this .getClass(),
0441:                        "getObjectImpl(int,Map)");
0442:            }
0443:
0444:            public Ref getRef(String columnName) throws SQLException {
0445:                return getRef(findColumn(columnName));
0446:            }
0447:
0448:            public Ref getRef(int i) throws SQLException {
0449:                checkClosed();
0450:                //The backend doesn't yet have SQL3 REF types
0451:                throw org.postgresql.Driver.notImplemented(this .getClass(),
0452:                        "getRef(int)");
0453:            }
0454:
0455:            public int getRow() throws SQLException {
0456:                checkClosed();
0457:
0458:                if (onInsertRow)
0459:                    return 0;
0460:
0461:                final int rows_size = rows.size();
0462:
0463:                if (current_row < 0 || current_row >= rows_size)
0464:                    return 0;
0465:
0466:                return row_offset + current_row + 1;
0467:            }
0468:
0469:            // This one needs some thought, as not all ResultSets come from a statement
0470:            public Statement getStatement() throws SQLException {
0471:                checkClosed();
0472:                return (Statement) statement;
0473:            }
0474:
0475:            public int getType() throws SQLException {
0476:                checkClosed();
0477:                return resultsettype;
0478:            }
0479:
0480:            public boolean isAfterLast() throws SQLException {
0481:                checkClosed();
0482:                if (onInsertRow)
0483:                    return false;
0484:
0485:                final int rows_size = rows.size();
0486:                return (current_row >= rows_size && rows_size > 0);
0487:            }
0488:
0489:            public boolean isBeforeFirst() throws SQLException {
0490:                checkClosed();
0491:                if (onInsertRow)
0492:                    return false;
0493:
0494:                return ((row_offset + current_row) < 0 && rows.size() > 0);
0495:            }
0496:
0497:            public boolean isFirst() throws SQLException {
0498:                checkClosed();
0499:                if (onInsertRow)
0500:                    return false;
0501:
0502:                return ((row_offset + current_row) == 0);
0503:            }
0504:
0505:            public boolean isLast() throws SQLException {
0506:                checkClosed();
0507:                if (onInsertRow)
0508:                    return false;
0509:
0510:                final int rows_size = rows.size();
0511:
0512:                if (rows_size == 0)
0513:                    return false; // No rows.
0514:
0515:                if (current_row != (rows_size - 1))
0516:                    return false; // Not on the last row of this block.
0517:
0518:                // We are on the last row of the current block.
0519:
0520:                if (cursor == null) {
0521:                    // This is the last block and therefore the last row.
0522:                    return true;
0523:                }
0524:
0525:                if (maxRows > 0 && row_offset + current_row == maxRows) {
0526:                    // We are implicitly limited by maxRows.
0527:                    return true;
0528:                }
0529:
0530:                // Now the more painful case begins.
0531:                // We are on the last row of the current block, but we don't know if the
0532:                // current block is the last block; we must try to fetch some more data to
0533:                // find out.
0534:
0535:                // We do a fetch of the next block, then prepend the current row to that
0536:                // block (so current_row == 0). This works as the current row
0537:                // must be the last row of the current block if we got this far.
0538:
0539:                row_offset += rows_size - 1; // Discarding all but one row.
0540:
0541:                // Work out how many rows maxRows will let us fetch.
0542:                int fetchRows = fetchSize;
0543:                if (maxRows != 0) {
0544:                    if (fetchRows == 0 || row_offset + fetchRows > maxRows) // Fetch would exceed maxRows, limit it.
0545:                        fetchRows = maxRows - row_offset;
0546:                }
0547:
0548:                // Do the actual fetch.
0549:                connection.getQueryExecutor().fetch(cursor,
0550:                        new CursorResultHandler(), fetchRows);
0551:
0552:                // Now prepend our one saved row and move to it.
0553:                rows.insertElementAt(this _row, 0);
0554:                current_row = 0;
0555:
0556:                // Finally, now we can tell if we're the last row or not.
0557:                return (rows.size() == 1);
0558:            }
0559:
0560:            public boolean last() throws SQLException {
0561:                checkScrollable();
0562:
0563:                final int rows_size = rows.size();
0564:                if (rows_size <= 0)
0565:                    return false;
0566:
0567:                current_row = rows_size - 1;
0568:                this _row = (byte[][]) rows.elementAt(current_row);
0569:
0570:                rowBuffer = new byte[this _row.length][];
0571:                System.arraycopy(this _row, 0, rowBuffer, 0, this _row.length);
0572:                onInsertRow = false;
0573:
0574:                return true;
0575:            }
0576:
0577:            public boolean previous() throws SQLException {
0578:                checkScrollable();
0579:
0580:                if (onInsertRow)
0581:                    throw new PSQLException(
0582:                            GT
0583:                                    .tr("Can''t use relative move methods while on the insert row."),
0584:                            PSQLState.INVALID_CURSOR_STATE);
0585:
0586:                if (current_row - 1 < 0) {
0587:                    current_row = -1;
0588:                    this _row = null;
0589:                    rowBuffer = null;
0590:                    return false;
0591:                } else {
0592:                    current_row--;
0593:                }
0594:                this _row = (byte[][]) rows.elementAt(current_row);
0595:                rowBuffer = new byte[this _row.length][];
0596:                System.arraycopy(this _row, 0, rowBuffer, 0, this _row.length);
0597:                return true;
0598:            }
0599:
0600:            public boolean relative(int rows) throws SQLException {
0601:                checkScrollable();
0602:
0603:                if (onInsertRow)
0604:                    throw new PSQLException(
0605:                            GT
0606:                                    .tr("Can''t use relative move methods while on the insert row."),
0607:                            PSQLState.INVALID_CURSOR_STATE);
0608:
0609:                //have to add 1 since absolute expects a 1-based index
0610:                return absolute(current_row + 1 + rows);
0611:            }
0612:
0613:            public void setFetchDirection(int direction) throws SQLException {
0614:                checkClosed();
0615:                switch (direction) {
0616:                case ResultSet.FETCH_FORWARD:
0617:                    break;
0618:                case ResultSet.FETCH_REVERSE:
0619:                case ResultSet.FETCH_UNKNOWN:
0620:                    checkScrollable();
0621:                    break;
0622:                default:
0623:                    throw new PSQLException(GT.tr(
0624:                            "Invalid fetch direction constant: {0}.",
0625:                            new Integer(direction)),
0626:                            PSQLState.INVALID_PARAMETER_VALUE);
0627:                }
0628:
0629:                this .fetchdirection = direction;
0630:            }
0631:
0632:            public synchronized void cancelRowUpdates() throws SQLException {
0633:                checkClosed();
0634:                if (onInsertRow) {
0635:                    throw new PSQLException(
0636:                            GT
0637:                                    .tr("Cannot call cancelRowUpdates() when on the insert row."),
0638:                            PSQLState.INVALID_CURSOR_STATE);
0639:                }
0640:
0641:                if (doingUpdates) {
0642:                    doingUpdates = false;
0643:
0644:                    clearRowBuffer(true);
0645:                }
0646:            }
0647:
0648:            public synchronized void deleteRow() throws SQLException {
0649:                checkUpdateable();
0650:
0651:                if (onInsertRow) {
0652:                    throw new PSQLException(
0653:                            GT
0654:                                    .tr("Cannot call deleteRow() when on the insert row."),
0655:                            PSQLState.INVALID_CURSOR_STATE);
0656:                }
0657:
0658:                if (isBeforeFirst()) {
0659:                    throw new PSQLException(
0660:                            GT
0661:                                    .tr("Currently positioned before the start of the ResultSet.  You cannot call deleteRow() here."),
0662:                            PSQLState.INVALID_CURSOR_STATE);
0663:                }
0664:                if (isAfterLast()) {
0665:                    throw new PSQLException(
0666:                            GT
0667:                                    .tr("Currently positioned after the end of the ResultSet.  You cannot call deleteRow() here."),
0668:                            PSQLState.INVALID_CURSOR_STATE);
0669:                }
0670:                if (rows.size() == 0) {
0671:                    throw new PSQLException(GT
0672:                            .tr("There are no rows in this ResultSet."),
0673:                            PSQLState.INVALID_CURSOR_STATE);
0674:                }
0675:
0676:                int numKeys = primaryKeys.size();
0677:                if (deleteStatement == null) {
0678:
0679:                    StringBuffer deleteSQL = new StringBuffer("DELETE FROM ")
0680:                            .append(tableName).append(" where ");
0681:
0682:                    for (int i = 0; i < numKeys; i++) {
0683:                        Utils.appendEscapedIdentifier(deleteSQL,
0684:                                ((PrimaryKey) primaryKeys.get(i)).name);
0685:                        deleteSQL.append(" = ?");
0686:                        if (i < numKeys - 1) {
0687:                            deleteSQL.append(" and ");
0688:                        }
0689:                    }
0690:
0691:                    deleteStatement = ((java.sql.Connection) connection)
0692:                            .prepareStatement(deleteSQL.toString());
0693:                }
0694:                deleteStatement.clearParameters();
0695:
0696:                for (int i = 0; i < numKeys; i++) {
0697:                    deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys
0698:                            .get(i)).getValue());
0699:                }
0700:
0701:                deleteStatement.executeUpdate();
0702:
0703:                rows.removeElementAt(current_row);
0704:                current_row--;
0705:                moveToCurrentRow();
0706:            }
0707:
0708:            public synchronized void insertRow() throws SQLException {
0709:                checkUpdateable();
0710:
0711:                if (!onInsertRow) {
0712:                    throw new PSQLException(GT.tr("Not on the insert row."),
0713:                            PSQLState.INVALID_CURSOR_STATE);
0714:                } else if (updateValues.size() == 0) {
0715:                    throw new PSQLException(
0716:                            GT
0717:                                    .tr("You must specify at least one column value to insert a row."),
0718:                            PSQLState.INVALID_PARAMETER_VALUE);
0719:                } else {
0720:
0721:                    // loop through the keys in the insertTable and create the sql statement
0722:                    // we have to create the sql every time since the user could insert different
0723:                    // columns each time
0724:
0725:                    StringBuffer insertSQL = new StringBuffer("INSERT INTO ")
0726:                            .append(tableName).append(" (");
0727:                    StringBuffer paramSQL = new StringBuffer(") values (");
0728:
0729:                    Iterator columnNames = updateValues.keySet().iterator();
0730:                    int numColumns = updateValues.size();
0731:
0732:                    for (int i = 0; columnNames.hasNext(); i++) {
0733:                        String columnName = (String) columnNames.next();
0734:
0735:                        Utils.appendEscapedIdentifier(insertSQL, columnName);
0736:                        if (i < numColumns - 1) {
0737:                            insertSQL.append(", ");
0738:                            paramSQL.append("?,");
0739:                        } else {
0740:                            paramSQL.append("?)");
0741:                        }
0742:
0743:                    }
0744:
0745:                    insertSQL.append(paramSQL.toString());
0746:                    insertStatement = ((java.sql.Connection) connection)
0747:                            .prepareStatement(insertSQL.toString());
0748:
0749:                    Iterator keys = updateValues.keySet().iterator();
0750:
0751:                    for (int i = 1; keys.hasNext(); i++) {
0752:                        String key = (String) keys.next();
0753:                        Object o = updateValues.get(key);
0754:                        insertStatement.setObject(i, o);
0755:                    }
0756:
0757:                    insertStatement.executeUpdate();
0758:
0759:                    if (usingOID) {
0760:                        // we have to get the last inserted OID and put it in the resultset
0761:
0762:                        long insertedOID = ((AbstractJdbc2Statement) insertStatement)
0763:                                .getLastOID();
0764:
0765:                        updateValues.put("oid", new Long(insertedOID));
0766:
0767:                    }
0768:
0769:                    // update the underlying row to the new inserted data
0770:                    updateRowBuffer();
0771:
0772:                    rows.addElement(rowBuffer);
0773:
0774:                    // we should now reflect the current data in this_row
0775:                    // that way getXXX will get the newly inserted data
0776:                    this _row = rowBuffer;
0777:
0778:                    // need to clear this in case of another insert
0779:                    clearRowBuffer(false);
0780:
0781:                }
0782:            }
0783:
0784:            public synchronized void moveToCurrentRow() throws SQLException {
0785:                checkUpdateable();
0786:
0787:                if (current_row < 0 || current_row >= rows.size()) {
0788:                    this _row = null;
0789:                    rowBuffer = null;
0790:                } else {
0791:                    this _row = (byte[][]) rows.elementAt(current_row);
0792:
0793:                    rowBuffer = new byte[this _row.length][];
0794:                    System
0795:                            .arraycopy(this _row, 0, rowBuffer, 0,
0796:                                    this _row.length);
0797:                }
0798:
0799:                onInsertRow = false;
0800:                doingUpdates = false;
0801:            }
0802:
0803:            public synchronized void moveToInsertRow() throws SQLException {
0804:                checkUpdateable();
0805:
0806:                if (insertStatement != null) {
0807:                    insertStatement = null;
0808:                }
0809:
0810:                // make sure the underlying data is null
0811:                clearRowBuffer(false);
0812:
0813:                onInsertRow = true;
0814:                doingUpdates = false;
0815:
0816:            }
0817:
0818:            private synchronized void clearRowBuffer(boolean copyCurrentRow)
0819:                    throws SQLException {
0820:                // rowBuffer is the temporary storage for the row
0821:                rowBuffer = new byte[fields.length][];
0822:
0823:                // inserts want an empty array while updates want a copy of the current row
0824:                if (copyCurrentRow) {
0825:                    System
0826:                            .arraycopy(this _row, 0, rowBuffer, 0,
0827:                                    this _row.length);
0828:                }
0829:
0830:                // clear the updateValues hashTable for the next set of updates
0831:                updateValues.clear();
0832:
0833:            }
0834:
0835:            public boolean rowDeleted() throws SQLException {
0836:                checkClosed();
0837:                return false;
0838:            }
0839:
0840:            public boolean rowInserted() throws SQLException {
0841:                checkClosed();
0842:                return false;
0843:            }
0844:
0845:            public boolean rowUpdated() throws SQLException {
0846:                checkClosed();
0847:                return false;
0848:            }
0849:
0850:            public synchronized void updateAsciiStream(int columnIndex,
0851:                    java.io.InputStream x, int length) throws SQLException {
0852:                if (x == null) {
0853:                    updateNull(columnIndex);
0854:                    return;
0855:                }
0856:
0857:                try {
0858:                    InputStreamReader reader = new InputStreamReader(x, "ASCII");
0859:                    char data[] = new char[length];
0860:                    int numRead = 0;
0861:                    while (true) {
0862:                        int n = reader.read(data, numRead, length - numRead);
0863:                        if (n == -1)
0864:                            break;
0865:
0866:                        numRead += n;
0867:
0868:                        if (numRead == length)
0869:                            break;
0870:                    }
0871:                    updateString(columnIndex, new String(data, 0, numRead));
0872:                } catch (UnsupportedEncodingException uee) {
0873:                    throw new PSQLException(GT.tr(
0874:                            "The JVM claims not to support the encoding: {0}",
0875:                            "ASCII"), PSQLState.UNEXPECTED_ERROR, uee);
0876:                } catch (IOException ie) {
0877:                    throw new PSQLException(GT
0878:                            .tr("Provided InputStream failed."), null, ie);
0879:                }
0880:            }
0881:
0882:            public synchronized void updateBigDecimal(int columnIndex,
0883:                    java.math.BigDecimal x) throws SQLException {
0884:                updateValue(columnIndex, x);
0885:            }
0886:
0887:            public synchronized void updateBinaryStream(int columnIndex,
0888:                    java.io.InputStream x, int length) throws SQLException {
0889:                if (x == null) {
0890:                    updateNull(columnIndex);
0891:                    return;
0892:                }
0893:
0894:                byte data[] = new byte[length];
0895:                int numRead = 0;
0896:                try {
0897:                    while (true) {
0898:                        int n = x.read(data, numRead, length - numRead);
0899:                        if (n == -1)
0900:                            break;
0901:
0902:                        numRead += n;
0903:
0904:                        if (numRead == length)
0905:                            break;
0906:                    }
0907:                } catch (IOException ie) {
0908:                    throw new PSQLException(GT
0909:                            .tr("Provided InputStream failed."), null, ie);
0910:                }
0911:
0912:                if (numRead == length) {
0913:                    updateBytes(columnIndex, data);
0914:                } else {
0915:                    // the stream contained less data than they said
0916:                    // perhaps this is an error?
0917:                    byte data2[] = new byte[numRead];
0918:                    System.arraycopy(data, 0, data2, 0, numRead);
0919:                    updateBytes(columnIndex, data2);
0920:                }
0921:            }
0922:
0923:            public synchronized void updateBoolean(int columnIndex, boolean x)
0924:                    throws SQLException {
0925:                updateValue(columnIndex, new Boolean(x));
0926:            }
0927:
0928:            public synchronized void updateByte(int columnIndex, byte x)
0929:                    throws SQLException {
0930:                updateValue(columnIndex, String.valueOf(x));
0931:            }
0932:
0933:            public synchronized void updateBytes(int columnIndex, byte[] x)
0934:                    throws SQLException {
0935:                updateValue(columnIndex, x);
0936:            }
0937:
0938:            public synchronized void updateCharacterStream(int columnIndex,
0939:                    java.io.Reader x, int length) throws SQLException {
0940:                if (x == null) {
0941:                    updateNull(columnIndex);
0942:                    return;
0943:                }
0944:
0945:                try {
0946:                    char data[] = new char[length];
0947:                    int numRead = 0;
0948:                    while (true) {
0949:                        int n = x.read(data, numRead, length - numRead);
0950:                        if (n == -1)
0951:                            break;
0952:
0953:                        numRead += n;
0954:
0955:                        if (numRead == length)
0956:                            break;
0957:                    }
0958:                    updateString(columnIndex, new String(data, 0, numRead));
0959:                } catch (IOException ie) {
0960:                    throw new PSQLException(GT.tr("Provided Reader failed."),
0961:                            null, ie);
0962:                }
0963:            }
0964:
0965:            public synchronized void updateDate(int columnIndex, java.sql.Date x)
0966:                    throws SQLException {
0967:                updateValue(columnIndex, x);
0968:            }
0969:
0970:            public synchronized void updateDouble(int columnIndex, double x)
0971:                    throws SQLException {
0972:                updateValue(columnIndex, new Double(x));
0973:            }
0974:
0975:            public synchronized void updateFloat(int columnIndex, float x)
0976:                    throws SQLException {
0977:                updateValue(columnIndex, new Float(x));
0978:            }
0979:
0980:            public synchronized void updateInt(int columnIndex, int x)
0981:                    throws SQLException {
0982:                updateValue(columnIndex, new Integer(x));
0983:            }
0984:
0985:            public synchronized void updateLong(int columnIndex, long x)
0986:                    throws SQLException {
0987:                updateValue(columnIndex, new Long(x));
0988:            }
0989:
0990:            public synchronized void updateNull(int columnIndex)
0991:                    throws SQLException {
0992:                checkColumnIndex(columnIndex);
0993:                String columnTypeName = connection
0994:                        .getPGType(fields[columnIndex - 1].getOID());
0995:                updateValue(columnIndex, new NullObject(columnTypeName));
0996:            }
0997:
0998:            public synchronized void updateObject(int columnIndex, Object x)
0999:                    throws SQLException {
1000:                updateValue(columnIndex, x);
1001:            }
1002:
1003:            public synchronized void updateObject(int columnIndex, Object x,
1004:                    int scale) throws SQLException {
1005:                this .updateObject(columnIndex, x);
1006:
1007:            }
1008:
1009:            public void refreshRow() throws SQLException {
1010:                checkUpdateable();
1011:                if (onInsertRow)
1012:                    throw new PSQLException(GT
1013:                            .tr("Can''t refresh the insert row."),
1014:                            PSQLState.INVALID_CURSOR_STATE);
1015:
1016:                if (isBeforeFirst() || isAfterLast() || rows.size() == 0)
1017:                    return;
1018:
1019:                StringBuffer selectSQL = new StringBuffer("select ");
1020:
1021:                final int numColumns = java.lang.reflect.Array
1022:                        .getLength(fields);
1023:
1024:                for (int i = 0; i < numColumns; i++) {
1025:                    selectSQL.append(fields[i].getColumnName(connection));
1026:
1027:                    if (i < numColumns - 1) {
1028:
1029:                        selectSQL.append(", ");
1030:                    }
1031:
1032:                }
1033:                selectSQL.append(" from ").append(tableName).append(" where ");
1034:
1035:                int numKeys = primaryKeys.size();
1036:
1037:                for (int i = 0; i < numKeys; i++) {
1038:
1039:                    PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
1040:                    selectSQL.append(primaryKey.name).append("= ?");
1041:
1042:                    if (i < numKeys - 1) {
1043:                        selectSQL.append(" and ");
1044:                    }
1045:                }
1046:                if (connection.getLogger().logDebug())
1047:                    connection.getLogger().debug(
1048:                            "selecting " + selectSQL.toString());
1049:                selectStatement = ((java.sql.Connection) connection)
1050:                        .prepareStatement(selectSQL.toString());
1051:
1052:                for (int j = 0, i = 1; j < numKeys; j++, i++) {
1053:                    selectStatement.setObject(i, ((PrimaryKey) primaryKeys
1054:                            .get(j)).getValue());
1055:                }
1056:
1057:                AbstractJdbc2ResultSet rs = (AbstractJdbc2ResultSet) selectStatement
1058:                        .executeQuery();
1059:
1060:                if (rs.next()) {
1061:                    rowBuffer = rs.rowBuffer;
1062:                }
1063:
1064:                rows.setElementAt(rowBuffer, current_row);
1065:                this _row = rowBuffer;
1066:
1067:                connection.getLogger().debug("done updates");
1068:
1069:                rs.close();
1070:                selectStatement.close();
1071:                selectStatement = null;
1072:
1073:            }
1074:
1075:            public synchronized void updateRow() throws SQLException {
1076:                checkUpdateable();
1077:
1078:                if (onInsertRow) {
1079:                    throw new PSQLException(
1080:                            GT
1081:                                    .tr("Cannot call updateRow() when on the insert row."),
1082:                            PSQLState.INVALID_CURSOR_STATE);
1083:                }
1084:
1085:                if (isBeforeFirst() || isAfterLast() || rows.size() == 0) {
1086:                    throw new PSQLException(
1087:                            GT
1088:                                    .tr("Cannot update the ResultSet because it is either before the start or after the end of the results."),
1089:                            PSQLState.INVALID_CURSOR_STATE);
1090:                }
1091:
1092:                if (!doingUpdates)
1093:                    return; // No work pending.
1094:
1095:                StringBuffer updateSQL = new StringBuffer("UPDATE " + tableName
1096:                        + " SET  ");
1097:
1098:                int numColumns = updateValues.size();
1099:                Iterator columns = updateValues.keySet().iterator();
1100:
1101:                for (int i = 0; columns.hasNext(); i++) {
1102:                    String column = (String) columns.next();
1103:                    Utils.appendEscapedIdentifier(updateSQL, column);
1104:                    updateSQL.append(" = ?");
1105:
1106:                    if (i < numColumns - 1)
1107:                        updateSQL.append(", ");
1108:                }
1109:
1110:                updateSQL.append(" WHERE ");
1111:
1112:                int numKeys = primaryKeys.size();
1113:
1114:                for (int i = 0; i < numKeys; i++) {
1115:                    PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
1116:                    Utils.appendEscapedIdentifier(updateSQL, primaryKey.name);
1117:                    updateSQL.append(" = ?");
1118:
1119:                    if (i < numKeys - 1)
1120:                        updateSQL.append(" and ");
1121:                }
1122:
1123:                if (connection.getLogger().logDebug())
1124:                    connection.getLogger().debug(
1125:                            "updating " + updateSQL.toString());
1126:                updateStatement = ((java.sql.Connection) connection)
1127:                        .prepareStatement(updateSQL.toString());
1128:
1129:                int i = 0;
1130:                Iterator iterator = updateValues.values().iterator();
1131:                for (; iterator.hasNext(); i++) {
1132:                    Object o = iterator.next();
1133:                    updateStatement.setObject(i + 1, o);
1134:                }
1135:
1136:                for (int j = 0; j < numKeys; j++, i++) {
1137:                    updateStatement.setObject(i + 1, ((PrimaryKey) primaryKeys
1138:                            .get(j)).getValue());
1139:                }
1140:
1141:                updateStatement.executeUpdate();
1142:                updateStatement.close();
1143:                updateStatement = null;
1144:
1145:                updateRowBuffer();
1146:
1147:                connection.getLogger().debug("copying data");
1148:                System.arraycopy(rowBuffer, 0, this _row, 0, rowBuffer.length);
1149:                rows.setElementAt(rowBuffer, current_row);
1150:
1151:                connection.getLogger().debug("done updates");
1152:                updateValues.clear();
1153:                doingUpdates = false;
1154:            }
1155:
1156:            public synchronized void updateShort(int columnIndex, short x)
1157:                    throws SQLException {
1158:                updateValue(columnIndex, new Short(x));
1159:            }
1160:
1161:            public synchronized void updateString(int columnIndex, String x)
1162:                    throws SQLException {
1163:                updateValue(columnIndex, x);
1164:            }
1165:
1166:            public synchronized void updateTime(int columnIndex, Time x)
1167:                    throws SQLException {
1168:                updateValue(columnIndex, x);
1169:            }
1170:
1171:            public synchronized void updateTimestamp(int columnIndex,
1172:                    Timestamp x) throws SQLException {
1173:                updateValue(columnIndex, x);
1174:
1175:            }
1176:
1177:            public synchronized void updateNull(String columnName)
1178:                    throws SQLException {
1179:                updateNull(findColumn(columnName));
1180:            }
1181:
1182:            public synchronized void updateBoolean(String columnName, boolean x)
1183:                    throws SQLException {
1184:                updateBoolean(findColumn(columnName), x);
1185:            }
1186:
1187:            public synchronized void updateByte(String columnName, byte x)
1188:                    throws SQLException {
1189:                updateByte(findColumn(columnName), x);
1190:            }
1191:
1192:            public synchronized void updateShort(String columnName, short x)
1193:                    throws SQLException {
1194:                updateShort(findColumn(columnName), x);
1195:            }
1196:
1197:            public synchronized void updateInt(String columnName, int x)
1198:                    throws SQLException {
1199:                updateInt(findColumn(columnName), x);
1200:            }
1201:
1202:            public synchronized void updateLong(String columnName, long x)
1203:                    throws SQLException {
1204:                updateLong(findColumn(columnName), x);
1205:            }
1206:
1207:            public synchronized void updateFloat(String columnName, float x)
1208:                    throws SQLException {
1209:                updateFloat(findColumn(columnName), x);
1210:            }
1211:
1212:            public synchronized void updateDouble(String columnName, double x)
1213:                    throws SQLException {
1214:                updateDouble(findColumn(columnName), x);
1215:            }
1216:
1217:            public synchronized void updateBigDecimal(String columnName,
1218:                    BigDecimal x) throws SQLException {
1219:                updateBigDecimal(findColumn(columnName), x);
1220:            }
1221:
1222:            public synchronized void updateString(String columnName, String x)
1223:                    throws SQLException {
1224:                updateString(findColumn(columnName), x);
1225:            }
1226:
1227:            public synchronized void updateBytes(String columnName, byte x[])
1228:                    throws SQLException {
1229:                updateBytes(findColumn(columnName), x);
1230:            }
1231:
1232:            public synchronized void updateDate(String columnName,
1233:                    java.sql.Date x) throws SQLException {
1234:                updateDate(findColumn(columnName), x);
1235:            }
1236:
1237:            public synchronized void updateTime(String columnName,
1238:                    java.sql.Time x) throws SQLException {
1239:                updateTime(findColumn(columnName), x);
1240:            }
1241:
1242:            public synchronized void updateTimestamp(String columnName,
1243:                    java.sql.Timestamp x) throws SQLException {
1244:                updateTimestamp(findColumn(columnName), x);
1245:            }
1246:
1247:            public synchronized void updateAsciiStream(String columnName,
1248:                    java.io.InputStream x, int length) throws SQLException {
1249:                updateAsciiStream(findColumn(columnName), x, length);
1250:            }
1251:
1252:            public synchronized void updateBinaryStream(String columnName,
1253:                    java.io.InputStream x, int length) throws SQLException {
1254:                updateBinaryStream(findColumn(columnName), x, length);
1255:            }
1256:
1257:            public synchronized void updateCharacterStream(String columnName,
1258:                    java.io.Reader reader, int length) throws SQLException {
1259:                updateCharacterStream(findColumn(columnName), reader, length);
1260:            }
1261:
1262:            public synchronized void updateObject(String columnName, Object x,
1263:                    int scale) throws SQLException {
1264:                updateObject(findColumn(columnName), x);
1265:            }
1266:
1267:            public synchronized void updateObject(String columnName, Object x)
1268:                    throws SQLException {
1269:                updateObject(findColumn(columnName), x);
1270:            }
1271:
1272:            /**
1273:             * Is this ResultSet updateable?
1274:             */
1275:
1276:            boolean isUpdateable() throws SQLException {
1277:                checkClosed();
1278:
1279:                if (resultsetconcurrency == ResultSet.CONCUR_READ_ONLY)
1280:                    throw new PSQLException(
1281:                            GT
1282:                                    .tr("ResultSets with concurrency CONCUR_READ_ONLY cannot be updated."),
1283:                            PSQLState.INVALID_CURSOR_STATE);
1284:
1285:                if (updateable)
1286:                    return true;
1287:
1288:                connection.getLogger().debug("checking if rs is updateable");
1289:
1290:                parseQuery();
1291:
1292:                if (singleTable == false) {
1293:                    connection.getLogger().debug("not a single table");
1294:                    return false;
1295:                }
1296:
1297:                connection.getLogger().debug("getting primary keys");
1298:
1299:                //
1300:                // Contains the primary key?
1301:                //
1302:
1303:                primaryKeys = new Vector();
1304:
1305:                // this is not stricty jdbc spec, but it will make things much faster if used
1306:                // the user has to select oid, * from table and then we will just use oid
1307:
1308:                usingOID = false;
1309:                int oidIndex = findColumnIndex("oid"); // 0 if not present
1310:
1311:                int i = 0;
1312:
1313:                // if we find the oid then just use it
1314:
1315:                //oidIndex will be >0 if the oid was in the select list
1316:                if (oidIndex > 0) {
1317:                    i++;
1318:                    primaryKeys.add(new PrimaryKey(oidIndex, "oid"));
1319:                    usingOID = true;
1320:                } else {
1321:                    // otherwise go and get the primary keys and create a hashtable of keys
1322:                    String[] s = quotelessTableName(tableName);
1323:                    String quotelessTableName = s[0];
1324:                    String quotelessSchemaName = s[1];
1325:                    java.sql.ResultSet rs = ((java.sql.Connection) connection)
1326:                            .getMetaData().getPrimaryKeys("",
1327:                                    quotelessSchemaName, quotelessTableName);
1328:                    for (; rs.next(); i++) {
1329:                        String columnName = rs.getString(4); // get the columnName
1330:                        int index = findColumn(columnName);
1331:
1332:                        if (index > 0) {
1333:                            primaryKeys.add(new PrimaryKey(index, columnName)); // get the primary key information
1334:                        }
1335:                    }
1336:
1337:                    rs.close();
1338:                }
1339:
1340:                if (connection.getLogger().logDebug())
1341:                    connection.getLogger().debug("no of keys=" + i);
1342:
1343:                if (i < 1) {
1344:                    throw new PSQLException(GT.tr(
1345:                            "No primary key found for table {0}.", tableName),
1346:                            PSQLState.DATA_ERROR);
1347:                }
1348:
1349:                updateable = primaryKeys.size() > 0;
1350:
1351:                if (connection.getLogger().logDebug())
1352:                    connection.getLogger().debug(
1353:                            "checking primary key " + updateable);
1354:
1355:                return updateable;
1356:            }
1357:
1358:            /** Cracks out the table name and schema (if it exists) from a fully
1359:             * qualified table name.
1360:             * @param fullname string that we are trying to crack. Test cases:<pre>
1361:             * Table: table ()
1362:             * "Table": Table ()
1363:             * Schema.Table: table (schema)
1364:             * "Schema"."Table": Table (Schema)
1365:             * "Schema"."Dot.Table": Dot.Table (Schema)
1366:             * Schema."Dot.Table": Dot.Table (schema)
1367:             * </pre>
1368:             * @return String array with element zero always being the tablename and
1369:             * element 1 the schema name which may be a zero length string.
1370:             */
1371:            public static String[] quotelessTableName(String fullname) {
1372:                StringBuffer buf = new StringBuffer(fullname);
1373:                String[] parts = new String[] { null, "" };
1374:                StringBuffer acc = new StringBuffer();
1375:                boolean betweenQuotes = false;
1376:                for (int i = 0; i < buf.length(); i++) {
1377:                    char c = buf.charAt(i);
1378:                    switch (c) {
1379:                    case '"':
1380:                        if ((i < buf.length() - 1)
1381:                                && (buf.charAt(i + 1) == '"')) {
1382:                            // two consecutive quotes - keep one
1383:                            i++;
1384:                            acc.append(c); // keep the quote
1385:                        } else { // Discard it
1386:                            betweenQuotes = !betweenQuotes;
1387:                        }
1388:                        break;
1389:                    case '.':
1390:                        if (betweenQuotes) { // Keep it
1391:                            acc.append(c);
1392:                        } else { // Have schema name
1393:                            parts[1] = acc.toString();
1394:                            acc = new StringBuffer();
1395:                        }
1396:                        break;
1397:                    default:
1398:                        acc.append((betweenQuotes) ? c : Character
1399:                                .toLowerCase(c));
1400:                        break;
1401:                    }
1402:                }
1403:                // Always put table in slot 0
1404:                parts[0] = acc.toString();
1405:                return parts;
1406:            }
1407:
1408:            private void parseQuery() {
1409:                String l_sql = originalQuery.toString(null);
1410:                StringTokenizer st = new StringTokenizer(l_sql, " \r\t\n");
1411:                boolean tableFound = false, tablesChecked = false;
1412:                String name = "";
1413:
1414:                singleTable = true;
1415:
1416:                while (!tableFound && !tablesChecked && st.hasMoreTokens()) {
1417:                    name = st.nextToken();
1418:                    if (!tableFound) {
1419:                        if (name.toLowerCase().equals("from")) {
1420:                            tableName = st.nextToken();
1421:                            tableFound = true;
1422:                        }
1423:                    } else {
1424:                        tablesChecked = true;
1425:                        // if the very next token is , then there are multiple tables
1426:                        singleTable = !name.equalsIgnoreCase(",");
1427:                    }
1428:                }
1429:            }
1430:
1431:            private void updateRowBuffer() throws SQLException {
1432:
1433:                Iterator columns = updateValues.keySet().iterator();
1434:
1435:                while (columns.hasNext()) {
1436:                    String columnName = (String) columns.next();
1437:                    int columnIndex = findColumn(columnName) - 1;
1438:
1439:                    Object valueObject = updateValues.get(columnName);
1440:                    if (valueObject instanceof  NullObject) {
1441:                        rowBuffer[columnIndex] = null;
1442:                    } else {
1443:                        switch (getSQLType(columnIndex + 1)) {
1444:
1445:                        case Types.DECIMAL:
1446:                        case Types.BIGINT:
1447:                        case Types.DOUBLE:
1448:                        case Types.BIT:
1449:                        case Types.VARCHAR:
1450:                        case Types.SMALLINT:
1451:                        case Types.FLOAT:
1452:                        case Types.INTEGER:
1453:                        case Types.CHAR:
1454:                        case Types.NUMERIC:
1455:                        case Types.REAL:
1456:                        case Types.TINYINT:
1457:                        case Types.ARRAY:
1458:                        case Types.OTHER:
1459:                            rowBuffer[columnIndex] = connection
1460:                                    .encodeString(String.valueOf(valueObject));
1461:                            break;
1462:
1463:                        //
1464:                        // toString() isn't enough for date and time types; we must format it correctly
1465:                        // or we won't be able to re-parse it.
1466:                        //
1467:
1468:                        case Types.DATE:
1469:                            rowBuffer[columnIndex] = connection
1470:                                    .encodeString(connection
1471:                                            .getTimestampUtils().toString(null,
1472:                                                    (Date) valueObject));
1473:                            break;
1474:
1475:                        case Types.TIME:
1476:                            rowBuffer[columnIndex] = connection
1477:                                    .encodeString(connection
1478:                                            .getTimestampUtils().toString(null,
1479:                                                    (Time) valueObject));
1480:                            break;
1481:
1482:                        case Types.TIMESTAMP:
1483:                            rowBuffer[columnIndex] = connection
1484:                                    .encodeString(connection
1485:                                            .getTimestampUtils().toString(null,
1486:                                                    (Timestamp) valueObject));
1487:                            break;
1488:
1489:                        case Types.NULL:
1490:                            // Should never happen?
1491:                            break;
1492:
1493:                        case Types.BINARY:
1494:                        case Types.LONGVARBINARY:
1495:                        case Types.VARBINARY:
1496:                            if (fields[columnIndex].getFormat() == Field.BINARY_FORMAT) {
1497:                                rowBuffer[columnIndex] = (byte[]) valueObject;
1498:                            } else {
1499:                                try {
1500:                                    rowBuffer[columnIndex] = PGbytea
1501:                                            .toPGString((byte[]) valueObject)
1502:                                            .getBytes("ISO-8859-1");
1503:                                } catch (UnsupportedEncodingException e) {
1504:                                    throw new PSQLException(
1505:                                            GT
1506:                                                    .tr(
1507:                                                            "The JVM claims not to support the encoding: {0}",
1508:                                                            "ISO-8859-1"),
1509:                                            PSQLState.UNEXPECTED_ERROR, e);
1510:                                }
1511:                            }
1512:                            break;
1513:
1514:                        default:
1515:                            rowBuffer[columnIndex] = (byte[]) valueObject;
1516:                        }
1517:
1518:                    }
1519:                }
1520:            }
1521:
1522:            public class CursorResultHandler implements  ResultHandler {
1523:                private SQLException error;
1524:
1525:                public void handleResultRows(Query fromQuery, Field[] fields,
1526:                        Vector tuples, ResultCursor cursor) {
1527:                    AbstractJdbc2ResultSet.this .rows = tuples;
1528:                    AbstractJdbc2ResultSet.this .cursor = cursor;
1529:                }
1530:
1531:                public void handleCommandStatus(String status, int updateCount,
1532:                        long insertOID) {
1533:                    handleError(new PSQLException(GT.tr(
1534:                            "Unexpected command status: {0}.", status),
1535:                            PSQLState.PROTOCOL_VIOLATION));
1536:                }
1537:
1538:                public void handleWarning(SQLWarning warning) {
1539:                    AbstractJdbc2ResultSet.this .addWarning(warning);
1540:                }
1541:
1542:                public void handleError(SQLException newError) {
1543:                    if (error == null)
1544:                        error = newError;
1545:                    else
1546:                        error.setNextException(newError);
1547:                }
1548:
1549:                public void handleCompletion() throws SQLException {
1550:                    if (error != null)
1551:                        throw error;
1552:                }
1553:            };
1554:
1555:            public BaseStatement getPGStatement() {
1556:                return statement;
1557:            }
1558:
1559:            //
1560:            // Backwards compatibility with PGRefCursorResultSet
1561:            //
1562:
1563:            private String refCursorName;
1564:
1565:            public String getRefCursor() {
1566:                // Can't check this because the PGRefCursorResultSet
1567:                // interface doesn't allow throwing a SQLException
1568:                //
1569:                // checkClosed();
1570:                return refCursorName;
1571:            }
1572:
1573:            private void setRefCursor(String refCursorName) {
1574:                this .refCursorName = refCursorName;
1575:            }
1576:
1577:            public void setFetchSize(int rows) throws SQLException {
1578:                checkClosed();
1579:                if (rows < 0)
1580:                    throw new PSQLException(
1581:                            GT
1582:                                    .tr("Fetch size must be a value greater to or equal to 0."),
1583:                            PSQLState.INVALID_PARAMETER_VALUE);
1584:                fetchSize = rows;
1585:            }
1586:
1587:            public int getFetchSize() throws SQLException {
1588:                checkClosed();
1589:                return fetchSize;
1590:            }
1591:
1592:            public boolean next() throws SQLException {
1593:                checkClosed();
1594:
1595:                if (onInsertRow)
1596:                    throw new PSQLException(
1597:                            GT
1598:                                    .tr("Can''t use relative move methods while on the insert row."),
1599:                            PSQLState.INVALID_CURSOR_STATE);
1600:
1601:                if (current_row + 1 >= rows.size()) {
1602:                    if (cursor == null
1603:                            || (maxRows > 0 && row_offset + rows.size() >= maxRows)) {
1604:                        current_row = rows.size();
1605:                        this _row = null;
1606:                        rowBuffer = null;
1607:                        return false; // End of the resultset.
1608:                    }
1609:
1610:                    // Ask for some more data.
1611:                    row_offset += rows.size(); // We are discarding some data.
1612:
1613:                    int fetchRows = fetchSize;
1614:                    if (maxRows != 0) {
1615:                        if (fetchRows == 0 || row_offset + fetchRows > maxRows) // Fetch would exceed maxRows, limit it.
1616:                            fetchRows = maxRows - row_offset;
1617:                    }
1618:
1619:                    // Execute the fetch and update this resultset.
1620:                    connection.getQueryExecutor().fetch(cursor,
1621:                            new CursorResultHandler(), fetchRows);
1622:
1623:                    current_row = 0;
1624:
1625:                    // Test the new rows array.
1626:                    if (rows.size() == 0) {
1627:                        this _row = null;
1628:                        rowBuffer = null;
1629:                        return false;
1630:                    }
1631:                } else {
1632:                    current_row++;
1633:                }
1634:
1635:                this _row = (byte[][]) rows.elementAt(current_row);
1636:
1637:                rowBuffer = new byte[this _row.length][];
1638:                System.arraycopy(this _row, 0, rowBuffer, 0, this _row.length);
1639:                return true;
1640:            }
1641:
1642:            public void close() throws SQLException {
1643:                //release resources held (memory for tuples)
1644:                rows = null;
1645:                if (cursor != null) {
1646:                    cursor.close();
1647:                    cursor = null;
1648:                }
1649:            }
1650:
1651:            public boolean wasNull() throws SQLException {
1652:                checkClosed();
1653:                return wasNullFlag;
1654:            }
1655:
1656:            public String getString(int columnIndex) throws SQLException {
1657:                checkResultSet(columnIndex);
1658:                if (wasNullFlag)
1659:                    return null;
1660:
1661:                Encoding encoding = connection.getEncoding();
1662:                try {
1663:                    return trimString(columnIndex, encoding
1664:                            .decode(this _row[columnIndex - 1]));
1665:                } catch (IOException ioe) {
1666:                    throw new PSQLException(
1667:                            GT
1668:                                    .tr("Invalid character data was found.  This is most likely caused by stored data containing characters that are invalid for the character set the database was created in.  The most common example of this is storing 8bit data in a SQL_ASCII database."),
1669:                            PSQLState.DATA_ERROR, ioe);
1670:                }
1671:            }
1672:
1673:            public boolean getBoolean(int columnIndex) throws SQLException {
1674:                checkResultSet(columnIndex);
1675:                if (wasNullFlag)
1676:                    return false; // SQL NULL
1677:
1678:                return toBoolean(getString(columnIndex));
1679:            }
1680:
1681:            private static final BigInteger BYTEMAX = new BigInteger(Byte
1682:                    .toString(Byte.MAX_VALUE));
1683:            private static final BigInteger BYTEMIN = new BigInteger(Byte
1684:                    .toString(Byte.MIN_VALUE));
1685:
1686:            public byte getByte(int columnIndex) throws SQLException {
1687:                checkResultSet(columnIndex);
1688:                if (wasNullFlag)
1689:                    return 0; // SQL NULL
1690:
1691:                String s = getString(columnIndex);
1692:
1693:                if (s != null) {
1694:                    s = s.trim();
1695:                    if (s.length() == 0)
1696:                        return 0;
1697:                    try {
1698:                        // try the optimal parse
1699:                        return Byte.parseByte(s);
1700:                    } catch (NumberFormatException e) {
1701:                        // didn't work, assume the column is not a byte
1702:                        try {
1703:                            BigDecimal n = new BigDecimal(s);
1704:                            BigInteger i = n.toBigInteger();
1705:
1706:                            int gt = i.compareTo(BYTEMAX);
1707:                            int lt = i.compareTo(BYTEMIN);
1708:
1709:                            if (gt > 0 || lt < 0) {
1710:                                throw new PSQLException(GT.tr(
1711:                                        "Bad value for type {0} : {1}",
1712:                                        new Object[] { "byte", s }),
1713:                                        PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
1714:                            }
1715:                            return i.byteValue();
1716:                        } catch (NumberFormatException ex) {
1717:                            throw new PSQLException(GT.tr(
1718:                                    "Bad value for type {0} : {1}",
1719:                                    new Object[] { "byte", s }),
1720:                                    PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
1721:                        }
1722:                    }
1723:                }
1724:                return 0; // SQL NULL
1725:            }
1726:
1727:            private static final BigInteger SHORTMAX = new BigInteger(Short
1728:                    .toString(Short.MAX_VALUE));
1729:            private static final BigInteger SHORTMIN = new BigInteger(Short
1730:                    .toString(Short.MIN_VALUE));
1731:
1732:            public short getShort(int columnIndex) throws SQLException {
1733:                checkResultSet(columnIndex);
1734:                if (wasNullFlag)
1735:                    return 0; // SQL NULL
1736:
1737:                String s = getFixedString(columnIndex);
1738:
1739:                if (s != null) {
1740:                    s = s.trim();
1741:                    try {
1742:                        return Short.parseShort(s);
1743:                    } catch (NumberFormatException e) {
1744:                        try {
1745:                            BigDecimal n = new BigDecimal(s);
1746:                            BigInteger i = n.toBigInteger();
1747:                            int gt = i.compareTo(SHORTMAX);
1748:                            int lt = i.compareTo(SHORTMIN);
1749:
1750:                            if (gt > 0 || lt < 0) {
1751:                                throw new PSQLException(GT.tr(
1752:                                        "Bad value for type {0} : {1}",
1753:                                        new Object[] { "short", s }),
1754:                                        PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
1755:                            }
1756:                            return i.shortValue();
1757:
1758:                        } catch (NumberFormatException ne) {
1759:                            throw new PSQLException(GT.tr(
1760:                                    "Bad value for type {0} : {1}",
1761:                                    new Object[] { "short", s }),
1762:                                    PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
1763:                        }
1764:                    }
1765:                }
1766:                return 0; // SQL NULL
1767:            }
1768:
1769:            public int getInt(int columnIndex) throws SQLException {
1770:                checkResultSet(columnIndex);
1771:                if (wasNullFlag)
1772:                    return 0; // SQL NULL
1773:
1774:                Encoding encoding = connection.getEncoding();
1775:                if (encoding.hasAsciiNumbers()) {
1776:                    try {
1777:                        return getFastInt(columnIndex);
1778:                    } catch (NumberFormatException ex) {
1779:                    }
1780:                }
1781:                return toInt(getFixedString(columnIndex));
1782:            }
1783:
1784:            public long getLong(int columnIndex) throws SQLException {
1785:                checkResultSet(columnIndex);
1786:                if (wasNullFlag)
1787:                    return 0; // SQL NULL
1788:
1789:                Encoding encoding = connection.getEncoding();
1790:                if (encoding.hasAsciiNumbers()) {
1791:                    try {
1792:                        return getFastLong(columnIndex);
1793:                    } catch (NumberFormatException ex) {
1794:                    }
1795:                }
1796:                return toLong(getFixedString(columnIndex));
1797:            }
1798:
1799:            /**
1800:             * A dummy exception thrown when fast byte[] to number parsing fails and
1801:             * no value can be returned. The exact stack trace does not matter because
1802:             * the exception is always caught and is not visible to users.
1803:             */
1804:            private static final NumberFormatException FAST_NUMBER_FAILED = new NumberFormatException();
1805:
1806:            /**
1807:             * Optimised byte[] to number parser.  This code does not
1808:             * handle null values, so the caller must do checkResultSet
1809:             * and handle null values prior to calling this function.
1810:             * 
1811:             * @param columnIndex The column to parse.
1812:             * @return The parsed number.
1813:             * @throws SQLException If an error occurs while fetching column.
1814:             * @throws NumberFormatException If the number is invalid or the
1815:             * out of range for fast parsing. The value must then be parsed by
1816:             * {@link #toLong(String)}.
1817:             */
1818:            private long getFastLong(int columnIndex) throws SQLException,
1819:                    NumberFormatException {
1820:
1821:                byte[] bytes = this _row[columnIndex - 1];
1822:
1823:                if (bytes.length == 0) {
1824:                    throw FAST_NUMBER_FAILED;
1825:                }
1826:
1827:                long val = 0;
1828:                int start;
1829:                boolean neg;
1830:                if (bytes[0] == '-') {
1831:                    neg = true;
1832:                    start = 1;
1833:                    if (bytes.length > 19) {
1834:                        throw FAST_NUMBER_FAILED;
1835:                    }
1836:                } else {
1837:                    start = 0;
1838:                    neg = false;
1839:                    if (bytes.length > 18) {
1840:                        throw FAST_NUMBER_FAILED;
1841:                    }
1842:                }
1843:
1844:                while (start < bytes.length) {
1845:                    byte b = bytes[start++];
1846:                    if (b < '0' || b > '9') {
1847:                        throw FAST_NUMBER_FAILED;
1848:                    }
1849:
1850:                    val *= 10;
1851:                    val += b - '0';
1852:                }
1853:
1854:                if (neg) {
1855:                    val = -val;
1856:                }
1857:
1858:                return val;
1859:            }
1860:
1861:            /**
1862:             * Optimised byte[] to number parser.  This code does not
1863:             * handle null values, so the caller must do checkResultSet
1864:             * and handle null values prior to calling this function.
1865:             * 
1866:             * @param columnIndex The column to parse.
1867:             * @return The parsed number.
1868:             * @throws SQLException If an error occurs while fetching column.
1869:             * @throws NumberFormatException If the number is invalid or the
1870:             * out of range for fast parsing. The value must then be parsed by
1871:             * {@link #toInt(String)}.
1872:             */
1873:            private int getFastInt(int columnIndex) throws SQLException,
1874:                    NumberFormatException {
1875:
1876:                byte[] bytes = this _row[columnIndex - 1];
1877:
1878:                if (bytes.length == 0) {
1879:                    throw FAST_NUMBER_FAILED;
1880:                }
1881:
1882:                int val = 0;
1883:                int start;
1884:                boolean neg;
1885:                if (bytes[0] == '-') {
1886:                    neg = true;
1887:                    start = 1;
1888:                    if (bytes.length > 10) {
1889:                        throw FAST_NUMBER_FAILED;
1890:                    }
1891:                } else {
1892:                    start = 0;
1893:                    neg = false;
1894:                    if (bytes.length > 9) {
1895:                        throw FAST_NUMBER_FAILED;
1896:                    }
1897:                }
1898:
1899:                while (start < bytes.length) {
1900:                    byte b = bytes[start++];
1901:                    if (b < '0' || b > '9') {
1902:                        throw FAST_NUMBER_FAILED;
1903:                    }
1904:
1905:                    val *= 10;
1906:                    val += b - '0';
1907:                }
1908:
1909:                if (neg) {
1910:                    val = -val;
1911:                }
1912:
1913:                return val;
1914:            }
1915:
1916:            public float getFloat(int columnIndex) throws SQLException {
1917:                checkResultSet(columnIndex);
1918:                if (wasNullFlag)
1919:                    return 0; // SQL NULL
1920:
1921:                return toFloat(getFixedString(columnIndex));
1922:            }
1923:
1924:            public double getDouble(int columnIndex) throws SQLException {
1925:                checkResultSet(columnIndex);
1926:                if (wasNullFlag)
1927:                    return 0; // SQL NULL
1928:
1929:                return toDouble(getFixedString(columnIndex));
1930:            }
1931:
1932:            public BigDecimal getBigDecimal(int columnIndex, int scale)
1933:                    throws SQLException {
1934:                checkResultSet(columnIndex);
1935:                if (wasNullFlag)
1936:                    return null;
1937:
1938:                return toBigDecimal(getFixedString(columnIndex), scale);
1939:            }
1940:
1941:            /*
1942:             * Get the value of a column in the current row as a Java byte array.
1943:             *
1944:             * <p>In normal use, the bytes represent the raw values returned by the
1945:             * backend. However, if the column is an OID, then it is assumed to
1946:             * refer to a Large Object, and that object is returned as a byte array.
1947:             *
1948:             * <p><b>Be warned</b> If the large object is huge, then you may run out
1949:             * of memory.
1950:             *
1951:             * @param columnIndex the first column is 1, the second is 2, ...
1952:             * @return the column value; if the value is SQL NULL, the result
1953:             * is null
1954:             * @exception SQLException if a database access error occurs
1955:             */
1956:            public byte[] getBytes(int columnIndex) throws SQLException {
1957:                checkResultSet(columnIndex);
1958:                if (wasNullFlag)
1959:                    return null;
1960:
1961:                if (fields[columnIndex - 1].getFormat() == Field.BINARY_FORMAT) {
1962:                    //If the data is already binary then just return it
1963:                    return this _row[columnIndex - 1];
1964:                } else if (connection.haveMinimumCompatibleVersion("7.2")) {
1965:                    //Version 7.2 supports the bytea datatype for byte arrays
1966:                    if (fields[columnIndex - 1].getOID() == Oid.BYTEA) {
1967:                        return trimBytes(columnIndex, PGbytea
1968:                                .toBytes(this _row[columnIndex - 1]));
1969:                    } else {
1970:                        return trimBytes(columnIndex, this _row[columnIndex - 1]);
1971:                    }
1972:                } else {
1973:                    //Version 7.1 and earlier supports LargeObjects for byte arrays
1974:                    // Handle OID's as BLOBS
1975:                    if (fields[columnIndex - 1].getOID() == Oid.OID) {
1976:                        LargeObjectManager lom = connection.getLargeObjectAPI();
1977:                        LargeObject lob = lom.open(getLong(columnIndex));
1978:                        byte buf[] = lob.read(lob.size());
1979:                        lob.close();
1980:                        return trimBytes(columnIndex, buf);
1981:                    } else {
1982:                        return trimBytes(columnIndex, this _row[columnIndex - 1]);
1983:                    }
1984:                }
1985:            }
1986:
1987:            public java.sql.Date getDate(int columnIndex) throws SQLException {
1988:                return getDate(columnIndex, null);
1989:            }
1990:
1991:            public Time getTime(int columnIndex) throws SQLException {
1992:                return getTime(columnIndex, null);
1993:            }
1994:
1995:            public Timestamp getTimestamp(int columnIndex) throws SQLException {
1996:                return getTimestamp(columnIndex, null);
1997:            }
1998:
1999:            public InputStream getAsciiStream(int columnIndex)
2000:                    throws SQLException {
2001:                checkResultSet(columnIndex);
2002:                if (wasNullFlag)
2003:                    return null;
2004:
2005:                if (connection.haveMinimumCompatibleVersion("7.2")) {
2006:                    //Version 7.2 supports AsciiStream for all the PG text types
2007:                    //As the spec/javadoc for this method indicate this is to be used for
2008:                    //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
2009:                    //long string datatype, but with toast the text datatype is capable of
2010:                    //handling very large values.  Thus the implementation ends up calling
2011:                    //getString() since there is no current way to stream the value from the server
2012:                    try {
2013:                        return new ByteArrayInputStream(getString(columnIndex)
2014:                                .getBytes("ASCII"));
2015:                    } catch (UnsupportedEncodingException l_uee) {
2016:                        throw new PSQLException(
2017:                                GT
2018:                                        .tr(
2019:                                                "The JVM claims not to support the encoding: {0}",
2020:                                                "ASCII"),
2021:                                PSQLState.UNEXPECTED_ERROR, l_uee);
2022:                    }
2023:                } else {
2024:                    // In 7.1 Handle as BLOBS so return the LargeObject input stream
2025:                    return getBinaryStream(columnIndex);
2026:                }
2027:            }
2028:
2029:            public InputStream getUnicodeStream(int columnIndex)
2030:                    throws SQLException {
2031:                checkResultSet(columnIndex);
2032:                if (wasNullFlag)
2033:                    return null;
2034:
2035:                if (connection.haveMinimumCompatibleVersion("7.2")) {
2036:                    //Version 7.2 supports AsciiStream for all the PG text types
2037:                    //As the spec/javadoc for this method indicate this is to be used for
2038:                    //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
2039:                    //long string datatype, but with toast the text datatype is capable of
2040:                    //handling very large values.  Thus the implementation ends up calling
2041:                    //getString() since there is no current way to stream the value from the server
2042:                    try {
2043:                        return new ByteArrayInputStream(getString(columnIndex)
2044:                                .getBytes("UTF-8"));
2045:                    } catch (UnsupportedEncodingException l_uee) {
2046:                        throw new PSQLException(
2047:                                GT
2048:                                        .tr(
2049:                                                "The JVM claims not to support the encoding: {0}",
2050:                                                "UTF-8"),
2051:                                PSQLState.UNEXPECTED_ERROR, l_uee);
2052:                    }
2053:                } else {
2054:                    // In 7.1 Handle as BLOBS so return the LargeObject input stream
2055:                    return getBinaryStream(columnIndex);
2056:                }
2057:            }
2058:
2059:            public InputStream getBinaryStream(int columnIndex)
2060:                    throws SQLException {
2061:                checkResultSet(columnIndex);
2062:                if (wasNullFlag)
2063:                    return null;
2064:
2065:                if (connection.haveMinimumCompatibleVersion("7.2")) {
2066:                    //Version 7.2 supports BinaryStream for all PG bytea type
2067:                    //As the spec/javadoc for this method indicate this is to be used for
2068:                    //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
2069:                    //long binary datatype, but with toast the bytea datatype is capable of
2070:                    //handling very large values.  Thus the implementation ends up calling
2071:                    //getBytes() since there is no current way to stream the value from the server
2072:                    byte b[] = getBytes(columnIndex);
2073:                    if (b != null)
2074:                        return new ByteArrayInputStream(b);
2075:                } else {
2076:                    // In 7.1 Handle as BLOBS so return the LargeObject input stream
2077:                    if (fields[columnIndex - 1].getOID() == Oid.OID) {
2078:                        LargeObjectManager lom = connection.getLargeObjectAPI();
2079:                        LargeObject lob = lom.open(getLong(columnIndex));
2080:                        return lob.getInputStream();
2081:                    }
2082:                }
2083:                return null;
2084:            }
2085:
2086:            public String getString(String columnName) throws SQLException {
2087:                return getString(findColumn(columnName));
2088:            }
2089:
2090:            public boolean getBoolean(String columnName) throws SQLException {
2091:                return getBoolean(findColumn(columnName));
2092:            }
2093:
2094:            public byte getByte(String columnName) throws SQLException {
2095:
2096:                return getByte(findColumn(columnName));
2097:            }
2098:
2099:            public short getShort(String columnName) throws SQLException {
2100:                return getShort(findColumn(columnName));
2101:            }
2102:
2103:            public int getInt(String columnName) throws SQLException {
2104:                return getInt(findColumn(columnName));
2105:            }
2106:
2107:            public long getLong(String columnName) throws SQLException {
2108:                return getLong(findColumn(columnName));
2109:            }
2110:
2111:            public float getFloat(String columnName) throws SQLException {
2112:                return getFloat(findColumn(columnName));
2113:            }
2114:
2115:            public double getDouble(String columnName) throws SQLException {
2116:                return getDouble(findColumn(columnName));
2117:            }
2118:
2119:            public BigDecimal getBigDecimal(String columnName, int scale)
2120:                    throws SQLException {
2121:                return getBigDecimal(findColumn(columnName), scale);
2122:            }
2123:
2124:            public byte[] getBytes(String columnName) throws SQLException {
2125:                return getBytes(findColumn(columnName));
2126:            }
2127:
2128:            public java.sql.Date getDate(String columnName) throws SQLException {
2129:                return getDate(findColumn(columnName), null);
2130:            }
2131:
2132:            public Time getTime(String columnName) throws SQLException {
2133:                return getTime(findColumn(columnName), null);
2134:            }
2135:
2136:            public Timestamp getTimestamp(String columnName)
2137:                    throws SQLException {
2138:                return getTimestamp(findColumn(columnName), null);
2139:            }
2140:
2141:            public InputStream getAsciiStream(String columnName)
2142:                    throws SQLException {
2143:                return getAsciiStream(findColumn(columnName));
2144:            }
2145:
2146:            public InputStream getUnicodeStream(String columnName)
2147:                    throws SQLException {
2148:                return getUnicodeStream(findColumn(columnName));
2149:            }
2150:
2151:            public InputStream getBinaryStream(String columnName)
2152:                    throws SQLException {
2153:                return getBinaryStream(findColumn(columnName));
2154:            }
2155:
2156:            public SQLWarning getWarnings() throws SQLException {
2157:                checkClosed();
2158:                return warnings;
2159:            }
2160:
2161:            public void clearWarnings() throws SQLException {
2162:                checkClosed();
2163:                warnings = null;
2164:            }
2165:
2166:            protected void addWarning(SQLWarning warnings) {
2167:                if (this .warnings != null)
2168:                    this .warnings.setNextWarning(warnings);
2169:                else
2170:                    this .warnings = warnings;
2171:            }
2172:
2173:            public String getCursorName() throws SQLException {
2174:                checkClosed();
2175:                return null;
2176:            }
2177:
2178:            /*
2179:             * Get the value of a column in the current row as a Java object
2180:             *
2181:             * <p>This method will return the value of the given column as a
2182:             * Java object.  The type of the Java object will be the default
2183:             * Java Object type corresponding to the column's SQL type, following
2184:             * the mapping specified in the JDBC specification.
2185:             *
2186:             * <p>This method may also be used to read database specific abstract
2187:             * data types.
2188:             *
2189:             * @param columnIndex the first column is 1, the second is 2...
2190:             * @return a Object holding the column value
2191:             * @exception SQLException if a database access error occurs
2192:             */
2193:            public Object getObject(int columnIndex) throws SQLException {
2194:                Field field;
2195:
2196:                checkResultSet(columnIndex);
2197:                if (wasNullFlag)
2198:                    return null;
2199:
2200:                field = fields[columnIndex - 1];
2201:
2202:                // some fields can be null, mainly from those returned by MetaData methods
2203:                if (field == null) {
2204:                    wasNullFlag = true;
2205:                    return null;
2206:                }
2207:
2208:                Object result = internalGetObject(columnIndex, field);
2209:                if (result != null)
2210:                    return result;
2211:
2212:                return connection.getObject(getPGType(columnIndex),
2213:                        getString(columnIndex));
2214:            }
2215:
2216:            public Object getObject(String columnName) throws SQLException {
2217:                return getObject(findColumn(columnName));
2218:            }
2219:
2220:            /*
2221:             * Map a ResultSet column name to a ResultSet column index
2222:             */
2223:            public int findColumn(String columnName) throws SQLException {
2224:                checkClosed();
2225:
2226:                int col = findColumnIndex(columnName);
2227:                if (col == 0)
2228:                    throw new PSQLException(
2229:                            GT
2230:                                    .tr(
2231:                                            "The column name {0} was not found in this ResultSet.",
2232:                                            columnName),
2233:                            PSQLState.UNDEFINED_COLUMN);
2234:                return col;
2235:            }
2236:
2237:            private int findColumnIndex(String columnName) {
2238:                if (columnNameIndexMap == null) {
2239:                    columnNameIndexMap = new HashMap(fields.length * 2);
2240:                    for (int i = 0; i < fields.length; i++) {
2241:                        columnNameIndexMap.put(fields[i].getColumnLabel()
2242:                                .toLowerCase(), new Integer(i + 1));
2243:                    }
2244:                }
2245:
2246:                Integer index = (Integer) columnNameIndexMap.get(columnName);
2247:                if (index != null) {
2248:                    return index.intValue();
2249:                }
2250:
2251:                index = (Integer) columnNameIndexMap.get(columnName
2252:                        .toLowerCase());
2253:                if (index != null) {
2254:                    columnNameIndexMap.put(columnName, index);
2255:                    return index.intValue();
2256:                }
2257:
2258:                return 0;
2259:            }
2260:
2261:            /*
2262:             * returns the OID of a field.<p>
2263:             * It is used internally by the driver.
2264:             */
2265:            public int getColumnOID(int field) {
2266:                return fields[field - 1].getOID();
2267:            }
2268:
2269:            /*
2270:             * This is used to fix get*() methods on Money fields. It should only be
2271:             * used by those methods!
2272:             *
2273:             * It converts ($##.##) to -##.## and $##.## to ##.##
2274:             */
2275:            public String getFixedString(int col) throws SQLException {
2276:                String s = getString(col);
2277:                if (s == null)
2278:                    return null;
2279:
2280:                // if we don't have at least 2 characters it can't be money.
2281:                if (s.length() < 2)
2282:                    return s;
2283:
2284:                // Handle Money
2285:                char ch = s.charAt(0);
2286:
2287:                // optimise for non-money type: return immediately with one check
2288:                // if the first char cannot be '(', '$' or '-'
2289:                if (ch > '-') {
2290:                    return s;
2291:                }
2292:
2293:                if (ch == '(') {
2294:                    s = "-" + PGtokenizer.removePara(s).substring(1);
2295:                } else if (ch == '$') {
2296:                    s = s.substring(1);
2297:                } else if (ch == '-' && s.charAt(1) == '$') {
2298:                    s = "-" + s.substring(2);
2299:                }
2300:
2301:                return s;
2302:            }
2303:
2304:            protected String getPGType(int column) throws SQLException {
2305:                return connection.getPGType(fields[column - 1].getOID());
2306:            }
2307:
2308:            protected int getSQLType(int column) throws SQLException {
2309:                return connection.getSQLType(fields[column - 1].getOID());
2310:            }
2311:
2312:            private void checkUpdateable() throws SQLException {
2313:                checkClosed();
2314:
2315:                if (!isUpdateable())
2316:                    throw new PSQLException(
2317:                            GT
2318:                                    .tr("ResultSet is not updateable.  The query that generated this result set must select only one table, and must select all primary keys from that table. See the JDBC 2.1 API Specification, section 5.6 for more details."),
2319:                            PSQLState.INVALID_CURSOR_STATE);
2320:
2321:                if (updateValues == null) {
2322:                    // allow every column to be updated without a rehash.
2323:                    updateValues = new HashMap((int) (fields.length / 0.75),
2324:                            0.75f);
2325:                }
2326:            }
2327:
2328:            protected void checkClosed() throws SQLException {
2329:                if (rows == null)
2330:                    throw new PSQLException(GT.tr("This ResultSet is closed."),
2331:                            PSQLState.CONNECTION_DOES_NOT_EXIST);
2332:            }
2333:
2334:            protected void checkColumnIndex(int column) throws SQLException {
2335:                if (column < 1 || column > fields.length)
2336:                    throw new PSQLException(
2337:                            GT
2338:                                    .tr(
2339:                                            "The column index is out of range: {0}, number of columns: {1}.",
2340:                                            new Object[] { new Integer(column),
2341:                                                    new Integer(fields.length) }),
2342:                            PSQLState.INVALID_PARAMETER_VALUE);
2343:            }
2344:
2345:            /**
2346:             * Checks that the result set is not closed, it's positioned on a
2347:             * valid row and that the given column number is valid. Also
2348:             * updates the {@link #wasNullFlag} to correct value.
2349:             * 
2350:             * @param column The column number to check. Range starts from 1.
2351:             * @throws SQLException If state or column is invalid.
2352:             */
2353:            protected void checkResultSet(int column) throws SQLException {
2354:                checkClosed();
2355:                if (this _row == null)
2356:                    throw new PSQLException(
2357:                            GT
2358:                                    .tr("ResultSet not positioned properly, perhaps you need to call next."),
2359:                            PSQLState.INVALID_CURSOR_STATE);
2360:                checkColumnIndex(column);
2361:                wasNullFlag = (this _row[column - 1] == null);
2362:            }
2363:
2364:            //----------------- Formatting Methods -------------------
2365:
2366:            public static boolean toBoolean(String s) {
2367:                if (s != null) {
2368:                    s = s.trim();
2369:
2370:                    if (s.equalsIgnoreCase("t") || s.equalsIgnoreCase("true")
2371:                            || s.equals("1"))
2372:                        return true;
2373:
2374:                    if (s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false")
2375:                            || s.equals("0"))
2376:                        return false;
2377:
2378:                    try {
2379:                        if (Double.valueOf(s).doubleValue() == 1)
2380:                            return true;
2381:                    } catch (NumberFormatException e) {
2382:                    }
2383:                }
2384:                return false; // SQL NULL
2385:            }
2386:
2387:            private static final BigInteger INTMAX = new BigInteger(Integer
2388:                    .toString(Integer.MAX_VALUE));
2389:            private static final BigInteger INTMIN = new BigInteger(Integer
2390:                    .toString(Integer.MIN_VALUE));
2391:
2392:            public static int toInt(String s) throws SQLException {
2393:                if (s != null) {
2394:                    try {
2395:                        s = s.trim();
2396:                        return Integer.parseInt(s);
2397:                    } catch (NumberFormatException e) {
2398:                        try {
2399:                            BigDecimal n = new BigDecimal(s);
2400:                            BigInteger i = n.toBigInteger();
2401:
2402:                            int gt = i.compareTo(INTMAX);
2403:                            int lt = i.compareTo(INTMIN);
2404:
2405:                            if (gt > 0 || lt < 0) {
2406:                                throw new PSQLException(GT.tr(
2407:                                        "Bad value for type {0} : {1}",
2408:                                        new Object[] { "int", s }),
2409:                                        PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2410:                            }
2411:                            return i.intValue();
2412:
2413:                        } catch (NumberFormatException ne) {
2414:                            throw new PSQLException(GT.tr(
2415:                                    "Bad value for type {0} : {1}",
2416:                                    new Object[] { "int", s }),
2417:                                    PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2418:                        }
2419:                    }
2420:                }
2421:                return 0; // SQL NULL
2422:            }
2423:
2424:            private final static BigInteger LONGMAX = new BigInteger(Long
2425:                    .toString(Long.MAX_VALUE));
2426:            private final static BigInteger LONGMIN = new BigInteger(Long
2427:                    .toString(Long.MIN_VALUE));
2428:
2429:            public static long toLong(String s) throws SQLException {
2430:                if (s != null) {
2431:                    try {
2432:                        s = s.trim();
2433:                        return Long.parseLong(s);
2434:                    } catch (NumberFormatException e) {
2435:                        try {
2436:                            BigDecimal n = new BigDecimal(s);
2437:                            BigInteger i = n.toBigInteger();
2438:                            int gt = i.compareTo(LONGMAX);
2439:                            int lt = i.compareTo(LONGMIN);
2440:
2441:                            if (gt > 0 || lt < 0) {
2442:                                throw new PSQLException(GT.tr(
2443:                                        "Bad value for type {0} : {1}",
2444:                                        new Object[] { "long", s }),
2445:                                        PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2446:                            }
2447:                            return i.longValue();
2448:                        } catch (NumberFormatException ne) {
2449:                            throw new PSQLException(GT.tr(
2450:                                    "Bad value for type {0} : {1}",
2451:                                    new Object[] { "long", s }),
2452:                                    PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2453:                        }
2454:                    }
2455:                }
2456:                return 0; // SQL NULL
2457:            }
2458:
2459:            public static BigDecimal toBigDecimal(String s, int scale)
2460:                    throws SQLException {
2461:                BigDecimal val;
2462:                if (s != null) {
2463:                    try {
2464:                        s = s.trim();
2465:                        val = new BigDecimal(s);
2466:                    } catch (NumberFormatException e) {
2467:                        throw new PSQLException(GT.tr(
2468:                                "Bad value for type {0} : {1}", new Object[] {
2469:                                        "BigDecimal", s }),
2470:                                PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2471:                    }
2472:                    if (scale == -1)
2473:                        return val;
2474:                    try {
2475:                        return val.setScale(scale);
2476:                    } catch (ArithmeticException e) {
2477:                        throw new PSQLException(GT.tr(
2478:                                "Bad value for type {0} : {1}", new Object[] {
2479:                                        "BigDecimal", s }),
2480:                                PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2481:                    }
2482:                }
2483:                return null; // SQL NULL
2484:            }
2485:
2486:            public static float toFloat(String s) throws SQLException {
2487:                if (s != null) {
2488:                    try {
2489:                        s = s.trim();
2490:                        return Float.parseFloat(s);
2491:                    } catch (NumberFormatException e) {
2492:                        throw new PSQLException(GT.tr(
2493:                                "Bad value for type {0} : {1}", new Object[] {
2494:                                        "float", s }),
2495:                                PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2496:                    }
2497:                }
2498:                return 0; // SQL NULL
2499:            }
2500:
2501:            public static double toDouble(String s) throws SQLException {
2502:                if (s != null) {
2503:                    try {
2504:                        s = s.trim();
2505:                        return Double.parseDouble(s);
2506:                    } catch (NumberFormatException e) {
2507:                        throw new PSQLException(GT.tr(
2508:                                "Bad value for type {0} : {1}", new Object[] {
2509:                                        "double", s }),
2510:                                PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
2511:                    }
2512:                }
2513:                return 0; // SQL NULL
2514:            }
2515:
2516:            private boolean isColumnTrimmable(int columnIndex)
2517:                    throws SQLException {
2518:                switch (getSQLType(columnIndex)) {
2519:                case Types.CHAR:
2520:                case Types.VARCHAR:
2521:                case Types.LONGVARCHAR:
2522:                case Types.BINARY:
2523:                case Types.VARBINARY:
2524:                case Types.LONGVARBINARY:
2525:                    return true;
2526:                }
2527:                return false;
2528:            }
2529:
2530:            private byte[] trimBytes(int p_columnIndex, byte[] p_bytes)
2531:                    throws SQLException {
2532:                //we need to trim if maxsize is set and the length is greater than maxsize and the
2533:                //type of this column is a candidate for trimming
2534:                if (maxFieldSize > 0 && p_bytes.length > maxFieldSize
2535:                        && isColumnTrimmable(p_columnIndex)) {
2536:                    byte[] l_bytes = new byte[maxFieldSize];
2537:                    System.arraycopy(p_bytes, 0, l_bytes, 0, maxFieldSize);
2538:                    return l_bytes;
2539:                } else {
2540:                    return p_bytes;
2541:                }
2542:            }
2543:
2544:            private String trimString(int p_columnIndex, String p_string)
2545:                    throws SQLException {
2546:                //we need to trim if maxsize is set and the length is greater than maxsize and the
2547:                //type of this column is a candidate for trimming
2548:                if (maxFieldSize > 0 && p_string.length() > maxFieldSize
2549:                        && isColumnTrimmable(p_columnIndex)) {
2550:                    return p_string.substring(0, maxFieldSize);
2551:                } else {
2552:                    return p_string;
2553:                }
2554:            }
2555:
2556:            protected void updateValue(int columnIndex, Object value)
2557:                    throws SQLException {
2558:                checkUpdateable();
2559:
2560:                if (!onInsertRow
2561:                        && (isBeforeFirst() || isAfterLast() || rows.size() == 0)) {
2562:                    throw new PSQLException(
2563:                            GT
2564:                                    .tr("Cannot update the ResultSet because it is either before the start or after the end of the results."),
2565:                            PSQLState.INVALID_CURSOR_STATE);
2566:                }
2567:
2568:                checkColumnIndex(columnIndex);
2569:
2570:                doingUpdates = !onInsertRow;
2571:                if (value == null)
2572:                    updateNull(columnIndex);
2573:                else
2574:                    updateValues.put(fields[columnIndex - 1]
2575:                            .getColumnName(connection), value);
2576:            }
2577:
2578:            private class PrimaryKey {
2579:                int index; // where in the result set is this primaryKey
2580:                String name; // what is the columnName of this primary Key
2581:
2582:                PrimaryKey(int index, String name) {
2583:                    this .index = index;
2584:                    this .name = name;
2585:                }
2586:
2587:                Object getValue() throws SQLException {
2588:                    return getObject(index);
2589:                }
2590:            };
2591:
2592:            //
2593:            // We need to specify the type of NULL when updating a column to NULL, so
2594:            // NullObject is a simple extension of PGobject that always returns null
2595:            // values but retains column type info.
2596:            //
2597:
2598:            static class NullObject extends PGobject {
2599:                NullObject(String type) {
2600:                    setType(type);
2601:                }
2602:
2603:                public String getValue() {
2604:                    return null;
2605:                }
2606:            };
2607:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.