Advertisement
aadddrr

Untitled

Oct 15th, 2018
151
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 92.76 KB | None | 0 0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * Copyright (c) 2003-2008, PostgreSQL Global Development Group
  4. *
  5. * IDENTIFICATION
  6. * $PostgreSQL: pgjdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java,v 1.108 2009/11/19 00:51:26 jurka Exp $
  7. *
  8. *-------------------------------------------------------------------------
  9. */
  10. package org.postgresql.jdbc2;
  11.  
  12. import java.io.CharArrayReader;
  13. import java.io.InputStream;
  14. import java.io.IOException;
  15. import java.io.InputStreamReader;
  16. import java.io.UnsupportedEncodingException;
  17. import java.io.ByteArrayInputStream;
  18. import java.math.BigDecimal;
  19. import java.math.BigInteger;
  20. import java.sql.*;
  21. import java.util.HashMap;
  22. import java.util.Iterator;
  23. import java.util.StringTokenizer;
  24. import java.util.Vector;
  25. import java.util.Calendar;
  26. import java.util.Locale;
  27. import org.postgresql.core.*;
  28. import org.postgresql.largeobject.*;
  29. import org.postgresql.util.PGobject;
  30. import org.postgresql.util.PGbytea;
  31. import org.postgresql.util.PGtokenizer;
  32. import org.postgresql.util.PSQLException;
  33. import org.postgresql.util.PSQLState;
  34. import org.postgresql.util.GT;
  35.  
  36.  
  37. public abstract class AbstractJdbc2ResultSet implements BaseResultSet, org.postgresql.PGRefCursorResultSet
  38. {
  39.  
  40. //needed for updateable result set support
  41. private boolean updateable = false;
  42. private boolean doingUpdates = false;
  43. private HashMap updateValues = null;
  44. private boolean usingOID = false; // are we using the OID for the primary key?
  45. private Vector primaryKeys; // list of primary keys
  46. private boolean singleTable = false;
  47. private String onlyTable = "";
  48. private String tableName = null;
  49. private PreparedStatement updateStatement = null;
  50. private PreparedStatement insertStatement = null;
  51. private PreparedStatement deleteStatement = null;
  52. private PreparedStatement selectStatement = null;
  53. private final int resultsettype;
  54. private final int resultsetconcurrency;
  55. private int fetchdirection = ResultSet.FETCH_UNKNOWN;
  56. protected final BaseConnection connection; // the connection we belong to
  57. protected final BaseStatement statement; // the statement we belong to
  58. protected final Field fields[]; // Field metadata for this resultset.
  59. protected final Query originalQuery; // Query we originated from
  60.  
  61. protected final int maxRows; // Maximum rows in this resultset (might be 0).
  62. protected final int maxFieldSize; // Maximum field size in this resultset (might be 0).
  63.  
  64. protected Vector rows; // Current page of results.
  65. protected int current_row = -1; // Index into 'rows' of our currrent row (0-based)
  66. protected int row_offset; // Offset of row 0 in the actual resultset
  67. protected byte[][] this_row; // copy of the current result row
  68. protected SQLWarning warnings = null; // The warning chain
  69. /**
  70. * True if the last obtained column value was SQL NULL as specified by
  71. * {@link #wasNull}. The value is always updated by the
  72. * {@link #checkResultSet} method.
  73. */
  74. protected boolean wasNullFlag = false;
  75. protected boolean onInsertRow = false; // are we on the insert row (for JDBC2 updatable resultsets)?
  76.  
  77. private byte[][] rowBuffer = null; // updateable rowbuffer
  78.  
  79. protected int fetchSize; // Current fetch size (might be 0).
  80. protected ResultCursor cursor; // Cursor for fetching additional data.
  81.  
  82. private HashMap columnLabelToIndexMap = null; // Speed up findColumn by caching lookups.
  83. // A map for column labels (Field.getColumnLabel()).
  84.  
  85. private HashMap columnNameToIndexMap = null; // Map for column names (Field.getColumnName()).
  86.  
  87. public abstract ResultSetMetaData getMetaData() throws SQLException;
  88.  
  89.  
  90. public AbstractJdbc2ResultSet(Query originalQuery, BaseStatement statement, Field[] fields, Vector tuples,
  91. ResultCursor cursor, int maxRows, int maxFieldSize,
  92. int rsType, int rsConcurrency) throws SQLException
  93. {
  94. this.originalQuery = originalQuery;
  95. this.connection = (BaseConnection) statement.getConnection();
  96. this.statement = statement;
  97. this.fields = fields;
  98. this.rows = tuples;
  99. this.cursor = cursor;
  100. this.maxRows = maxRows;
  101. this.maxFieldSize = maxFieldSize;
  102. this.resultsettype = rsType;
  103. this.resultsetconcurrency = rsConcurrency;
  104. }
  105.  
  106. public java.net.URL getURL(int columnIndex) throws SQLException
  107. {
  108. checkClosed();
  109. throw org.postgresql.Driver.notImplemented(this.getClass(), "getURL(int)");
  110. }
  111.  
  112.  
  113. public java.net.URL getURL(String columnName) throws SQLException
  114. {
  115. return getURL(findColumn(columnName));
  116. }
  117.  
  118. protected Object internalGetObject(int columnIndex, Field field) throws SQLException
  119. {
  120. switch (getSQLType(columnIndex))
  121. {
  122. case Types.BIT:
  123. // Also Types.BOOLEAN in JDBC3
  124. return getBoolean(columnIndex) ? Boolean.TRUE : Boolean.FALSE;
  125. case Types.TINYINT:
  126. case Types.SMALLINT:
  127. case Types.INTEGER:
  128. return new Integer(getInt(columnIndex));
  129. case Types.BIGINT:
  130. return new Long(getLong(columnIndex));
  131. case Types.NUMERIC:
  132. case Types.DECIMAL:
  133. return getBigDecimal
  134. (columnIndex, (field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
  135. case Types.REAL:
  136. return new Float(getFloat(columnIndex));
  137. case Types.FLOAT:
  138. case Types.DOUBLE:
  139. return new Double(getDouble(columnIndex));
  140. case Types.CHAR:
  141. case Types.VARCHAR:
  142. case Types.LONGVARCHAR:
  143. return getString(columnIndex);
  144. case Types.DATE:
  145. return getDate(columnIndex);
  146. case Types.TIME:
  147. return getTime(columnIndex);
  148. case Types.TIMESTAMP:
  149. return getTimestamp(columnIndex, null);
  150. case Types.BINARY:
  151. case Types.VARBINARY:
  152. case Types.LONGVARBINARY:
  153. return getBytes(columnIndex);
  154. case Types.ARRAY:
  155. return getArray(columnIndex);
  156. case Types.CLOB:
  157. return getClob(columnIndex);
  158. case Types.BLOB:
  159. return getBlob(columnIndex);
  160.  
  161. default:
  162. String type = getPGType(columnIndex);
  163.  
  164. // if the backend doesn't know the type then coerce to String
  165. if (type.equals("unknown"))
  166. return getString(columnIndex);
  167.  
  168. if (type.equals("uuid"))
  169. return getUUID(getString(columnIndex));
  170.  
  171. // Specialized support for ref cursors is neater.
  172. if (type.equals("refcursor"))
  173. {
  174. // Fetch all results.
  175. String cursorName = getString(columnIndex);
  176.  
  177. StringBuffer sb = new StringBuffer("FETCH ALL IN ");
  178. Utils.appendEscapedIdentifier(sb, cursorName);
  179.  
  180. // nb: no BEGIN triggered here. This is fine. If someone
  181. // committed, and the cursor was not holdable (closing the
  182. // cursor), we avoid starting a new xact and promptly causing
  183. // it to fail. If the cursor *was* holdable, we don't want a
  184. // new xact anyway since holdable cursor state isn't affected
  185. // by xact boundaries. If our caller didn't commit at all, or
  186. // autocommit was on, then we wouldn't issue a BEGIN anyway.
  187. //
  188. // We take the scrollability from the statement, but until
  189. // we have updatable cursors it must be readonly.
  190. ResultSet rs = connection.execSQLQuery(sb.toString(), resultsettype, ResultSet.CONCUR_READ_ONLY);
  191. //
  192. // In long running transactions these backend cursors take up memory space
  193. // we could close in rs.close(), but if the transaction is closed before the result set, then
  194. // the cursor no longer exists
  195.  
  196. sb.setLength(0);
  197. sb.append("CLOSE ");
  198. Utils.appendEscapedIdentifier(sb, cursorName);
  199. connection.execSQLUpdate(sb.toString());
  200. ((AbstractJdbc2ResultSet)rs).setRefCursor(cursorName);
  201. return rs;
  202. }
  203.  
  204. // Caller determines what to do (JDBC3 overrides in this case)
  205. return null;
  206. }
  207. }
  208.  
  209. private void checkScrollable() throws SQLException
  210. {
  211. checkClosed();
  212. if (resultsettype == ResultSet.TYPE_FORWARD_ONLY)
  213. throw new PSQLException(GT.tr("Operation requires a scrollable ResultSet, but this ResultSet is FORWARD_ONLY."),
  214. PSQLState.INVALID_CURSOR_STATE);
  215. }
  216.  
  217. public boolean absolute(int index) throws SQLException
  218. {
  219. checkScrollable();
  220.  
  221. // index is 1-based, but internally we use 0-based indices
  222. int internalIndex;
  223.  
  224. if (index == 0)
  225. {
  226. beforeFirst();
  227. return false;
  228. }
  229.  
  230. final int rows_size = rows.size();
  231.  
  232. //if index<0, count from the end of the result set, but check
  233. //to be sure that it is not beyond the first index
  234. if (index < 0)
  235. {
  236. if (index >= -rows_size)
  237. internalIndex = rows_size + index;
  238. else
  239. {
  240. beforeFirst();
  241. return false;
  242. }
  243. }
  244. else
  245. {
  246. //must be the case that index>0,
  247. //find the correct place, assuming that
  248. //the index is not too large
  249. if (index <= rows_size)
  250. internalIndex = index - 1;
  251. else
  252. {
  253. afterLast();
  254. return false;
  255. }
  256. }
  257.  
  258. current_row = internalIndex;
  259. initRowBuffer();
  260. onInsertRow = false;
  261.  
  262. return true;
  263. }
  264.  
  265.  
  266. public void afterLast() throws SQLException
  267. {
  268. checkScrollable();
  269.  
  270. final int rows_size = rows.size();
  271. if (rows_size > 0)
  272. current_row = rows_size;
  273.  
  274. onInsertRow = false;
  275. this_row = null;
  276. rowBuffer = null;
  277. }
  278.  
  279.  
  280. public void beforeFirst() throws SQLException
  281. {
  282. checkScrollable();
  283.  
  284. if (rows.size() > 0)
  285. current_row = -1;
  286.  
  287. onInsertRow = false;
  288. this_row = null;
  289. rowBuffer = null;
  290. }
  291.  
  292.  
  293. public boolean first() throws SQLException
  294. {
  295. checkScrollable();
  296.  
  297. if (rows.size() <= 0)
  298. return false;
  299.  
  300. current_row = 0;
  301. initRowBuffer();
  302. onInsertRow = false;
  303.  
  304. return true;
  305. }
  306.  
  307.  
  308. public java.sql.Array getArray(String colName) throws SQLException
  309. {
  310. return getArray(findColumn(colName));
  311. }
  312.  
  313.  
  314. public java.sql.Array getArray(int i) throws SQLException
  315. {
  316. checkResultSet( i );
  317. if (wasNullFlag)
  318. return null;
  319.  
  320. return createArray(i);
  321. }
  322.  
  323.  
  324. public java.math.BigDecimal getBigDecimal(int columnIndex) throws SQLException
  325. {
  326. return getBigDecimal(columnIndex, -1);
  327. }
  328.  
  329.  
  330. public java.math.BigDecimal getBigDecimal(String columnName) throws SQLException
  331. {
  332. return getBigDecimal(findColumn(columnName));
  333. }
  334.  
  335.  
  336. public Blob getBlob(String columnName) throws SQLException
  337. {
  338. return getBlob(findColumn(columnName));
  339. }
  340.  
  341.  
  342. public abstract Blob getBlob(int i) throws SQLException;
  343.  
  344.  
  345. public java.io.Reader getCharacterStream(String columnName) throws SQLException
  346. {
  347. return getCharacterStream(findColumn(columnName));
  348. }
  349.  
  350.  
  351. public java.io.Reader getCharacterStream(int i) throws SQLException
  352. {
  353. checkResultSet( i );
  354. if (wasNullFlag)
  355. return null;
  356.  
  357. if (((AbstractJdbc2Connection) connection).haveMinimumCompatibleVersion("7.2"))
  358. {
  359. //Version 7.2 supports AsciiStream for all the PG text types
  360. //As the spec/javadoc for this method indicate this is to be used for
  361. //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
  362. //long string datatype, but with toast the text datatype is capable of
  363. //handling very large values. Thus the implementation ends up calling
  364. //getString() since there is no current way to stream the value from the server
  365. return new CharArrayReader(getString(i).toCharArray());
  366. }
  367. else
  368. {
  369. // In 7.1 Handle as BLOBS so return the LargeObject input stream
  370. Encoding encoding = connection.getEncoding();
  371. InputStream input = getBinaryStream(i);
  372.  
  373. try
  374. {
  375. return encoding.getDecodingReader(input);
  376. }
  377. catch (IOException ioe)
  378. {
  379. throw new PSQLException(GT.tr("Unexpected error while decoding character data from a large object."), PSQLState.UNEXPECTED_ERROR, ioe);
  380. }
  381. }
  382. }
  383.  
  384.  
  385. public Clob getClob(String columnName) throws SQLException
  386. {
  387. return getClob(findColumn(columnName));
  388. }
  389.  
  390.  
  391. public abstract Clob getClob(int i) throws SQLException;
  392.  
  393.  
  394. public int getConcurrency() throws SQLException
  395. {
  396. checkClosed();
  397. return resultsetconcurrency;
  398. }
  399.  
  400.  
  401. public java.sql.Date getDate(int i, java.util.Calendar cal) throws SQLException
  402. {
  403. checkResultSet(i);
  404. if (wasNullFlag)
  405. return null;
  406.  
  407. if (cal != null)
  408. cal = (Calendar)cal.clone();
  409.  
  410. return connection.getTimestampUtils().toDate(cal, getString(i));
  411. }
  412.  
  413.  
  414. public Time getTime(int i, java.util.Calendar cal) throws SQLException
  415. {
  416. checkResultSet(i);
  417. if (wasNullFlag)
  418. return null;
  419.  
  420. if (cal != null)
  421. cal = (Calendar)cal.clone();
  422.  
  423. return connection.getTimestampUtils().toTime(cal, getString(i));
  424. }
  425.  
  426.  
  427. public Timestamp getTimestamp(int i, java.util.Calendar cal) throws SQLException
  428. {
  429. checkResultSet(i);
  430. if (wasNullFlag)
  431. return null;
  432.  
  433. if (cal != null)
  434. cal = (Calendar)cal.clone();
  435.  
  436. // If this is actually a timestamptz, the server-provided timezone will override
  437. // the one we pass in, which is the desired behaviour. Otherwise, we'll
  438. // interpret the timezone-less value in the provided timezone.
  439. return connection.getTimestampUtils().toTimestamp(cal, getString(i));
  440. }
  441.  
  442.  
  443. public java.sql.Date getDate(String c, java.util.Calendar cal) throws SQLException
  444. {
  445. return getDate(findColumn(c), cal);
  446. }
  447.  
  448.  
  449. public Time getTime(String c, java.util.Calendar cal) throws SQLException
  450. {
  451. return getTime(findColumn(c), cal);
  452. }
  453.  
  454.  
  455. public Timestamp getTimestamp(String c, java.util.Calendar cal) throws SQLException
  456. {
  457. return getTimestamp(findColumn(c), cal);
  458. }
  459.  
  460.  
  461. public int getFetchDirection() throws SQLException
  462. {
  463. checkClosed();
  464. return fetchdirection;
  465. }
  466.  
  467.  
  468. public Object getObjectImpl(String columnName, java.util.Map map) throws SQLException
  469. {
  470. return getObjectImpl(findColumn(columnName), map);
  471. }
  472.  
  473.  
  474. /*
  475. * This checks against map for the type of column i, and if found returns
  476. * an object based on that mapping. The class must implement the SQLData
  477. * interface.
  478. */
  479. public Object getObjectImpl(int i, java.util.Map map) throws SQLException
  480. {
  481. checkClosed();
  482. if (map == null || map.isEmpty()) {
  483. return getObject(i);
  484. }
  485. throw org.postgresql.Driver.notImplemented(this.getClass(), "getObjectImpl(int,Map)");
  486. }
  487.  
  488.  
  489. public Ref getRef(String columnName) throws SQLException
  490. {
  491. return getRef(findColumn(columnName));
  492. }
  493.  
  494.  
  495. public Ref getRef(int i) throws SQLException
  496. {
  497. checkClosed();
  498. //The backend doesn't yet have SQL3 REF types
  499. throw org.postgresql.Driver.notImplemented(this.getClass(), "getRef(int)");
  500. }
  501.  
  502.  
  503. public int getRow() throws SQLException
  504. {
  505. checkClosed();
  506.  
  507. if (onInsertRow)
  508. return 0;
  509.  
  510. final int rows_size = rows.size();
  511.  
  512. if (current_row < 0 || current_row >= rows_size)
  513. return 0;
  514.  
  515. return row_offset + current_row + 1;
  516. }
  517.  
  518.  
  519. // This one needs some thought, as not all ResultSets come from a statement
  520. public Statement getStatement() throws SQLException
  521. {
  522. checkClosed();
  523. return (Statement) statement;
  524. }
  525.  
  526.  
  527. public int getType() throws SQLException
  528. {
  529. checkClosed();
  530. return resultsettype;
  531. }
  532.  
  533.  
  534. public boolean isAfterLast() throws SQLException
  535. {
  536. checkClosed();
  537. if (onInsertRow)
  538. return false;
  539.  
  540. final int rows_size = rows.size();
  541. return (current_row >= rows_size && rows_size > 0);
  542. }
  543.  
  544.  
  545. public boolean isBeforeFirst() throws SQLException
  546. {
  547. checkClosed();
  548. if (onInsertRow)
  549. return false;
  550.  
  551. return ((row_offset + current_row) < 0 && rows.size() > 0);
  552. }
  553.  
  554.  
  555. public boolean isFirst() throws SQLException
  556. {
  557. checkClosed();
  558. if (onInsertRow)
  559. return false;
  560.  
  561. return ((row_offset + current_row) == 0);
  562. }
  563.  
  564.  
  565. public boolean isLast() throws SQLException
  566. {
  567. checkClosed();
  568. if (onInsertRow)
  569. return false;
  570.  
  571. final int rows_size = rows.size();
  572.  
  573. if (rows_size == 0)
  574. return false; // No rows.
  575.  
  576. if (current_row != (rows_size - 1))
  577. return false; // Not on the last row of this block.
  578.  
  579. // We are on the last row of the current block.
  580.  
  581. if (cursor == null)
  582. {
  583. // This is the last block and therefore the last row.
  584. return true;
  585. }
  586.  
  587. if (maxRows > 0 && row_offset + current_row == maxRows)
  588. {
  589. // We are implicitly limited by maxRows.
  590. return true;
  591. }
  592.  
  593. // Now the more painful case begins.
  594. // We are on the last row of the current block, but we don't know if the
  595. // current block is the last block; we must try to fetch some more data to
  596. // find out.
  597.  
  598. // We do a fetch of the next block, then prepend the current row to that
  599. // block (so current_row == 0). This works as the current row
  600. // must be the last row of the current block if we got this far.
  601.  
  602. row_offset += rows_size - 1; // Discarding all but one row.
  603.  
  604. // Work out how many rows maxRows will let us fetch.
  605. int fetchRows = fetchSize;
  606. if (maxRows != 0)
  607. {
  608. if (fetchRows == 0 || row_offset + fetchRows > maxRows) // Fetch would exceed maxRows, limit it.
  609. fetchRows = maxRows - row_offset;
  610. }
  611.  
  612. // Do the actual fetch.
  613. connection.getQueryExecutor().fetch(cursor, new CursorResultHandler(), fetchRows);
  614.  
  615. // Now prepend our one saved row and move to it.
  616. rows.insertElementAt(this_row, 0);
  617. current_row = 0;
  618.  
  619. // Finally, now we can tell if we're the last row or not.
  620. return (rows.size() == 1);
  621. }
  622.  
  623. public boolean last() throws SQLException
  624. {
  625. checkScrollable();
  626.  
  627. final int rows_size = rows.size();
  628. if (rows_size <= 0)
  629. return false;
  630.  
  631. current_row = rows_size - 1;
  632. initRowBuffer();
  633. onInsertRow = false;
  634.  
  635. return true;
  636. }
  637.  
  638.  
  639. public boolean previous() throws SQLException
  640. {
  641. checkScrollable();
  642.  
  643. if (onInsertRow)
  644. throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),
  645. PSQLState.INVALID_CURSOR_STATE);
  646.  
  647. if (current_row -1 < 0)
  648. {
  649. current_row = -1;
  650. this_row = null;
  651. rowBuffer = null;
  652. return false;
  653. }
  654. else
  655. {
  656. current_row--;
  657. }
  658. initRowBuffer();
  659. return true;
  660. }
  661.  
  662.  
  663. public boolean relative(int rows) throws SQLException
  664. {
  665. checkScrollable();
  666.  
  667. if (onInsertRow)
  668. throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),
  669. PSQLState.INVALID_CURSOR_STATE);
  670.  
  671. //have to add 1 since absolute expects a 1-based index
  672. return absolute(current_row + 1 + rows);
  673. }
  674.  
  675.  
  676. public void setFetchDirection(int direction) throws SQLException
  677. {
  678. checkClosed();
  679. switch (direction)
  680. {
  681. case ResultSet.FETCH_FORWARD:
  682. break;
  683. case ResultSet.FETCH_REVERSE:
  684. case ResultSet.FETCH_UNKNOWN:
  685. checkScrollable();
  686. break;
  687. default:
  688. throw new PSQLException(GT.tr("Invalid fetch direction constant: {0}.", new Integer(direction)),
  689. PSQLState.INVALID_PARAMETER_VALUE);
  690. }
  691.  
  692. this.fetchdirection = direction;
  693. }
  694.  
  695.  
  696. public synchronized void cancelRowUpdates()
  697. throws SQLException
  698. {
  699. checkClosed();
  700. if (onInsertRow)
  701. {
  702. throw new PSQLException(GT.tr("Cannot call cancelRowUpdates() when on the insert row."),
  703. PSQLState.INVALID_CURSOR_STATE);
  704. }
  705.  
  706. if (doingUpdates)
  707. {
  708. doingUpdates = false;
  709.  
  710. clearRowBuffer(true);
  711. }
  712. }
  713.  
  714.  
  715. public synchronized void deleteRow()
  716. throws SQLException
  717. {
  718. checkUpdateable();
  719.  
  720. if (onInsertRow)
  721. {
  722. throw new PSQLException(GT.tr("Cannot call deleteRow() when on the insert row."),
  723. PSQLState.INVALID_CURSOR_STATE);
  724. }
  725.  
  726. if (isBeforeFirst())
  727. {
  728. throw new PSQLException(GT.tr("Currently positioned before the start of the ResultSet. You cannot call deleteRow() here."),
  729. PSQLState.INVALID_CURSOR_STATE);
  730. }
  731. if (isAfterLast())
  732. {
  733. throw new PSQLException(GT.tr("Currently positioned after the end of the ResultSet. You cannot call deleteRow() here."),
  734. PSQLState.INVALID_CURSOR_STATE);
  735. }
  736. if (rows.size() == 0)
  737. {
  738. throw new PSQLException(GT.tr("There are no rows in this ResultSet."),
  739. PSQLState.INVALID_CURSOR_STATE);
  740. }
  741.  
  742.  
  743. int numKeys = primaryKeys.size();
  744. if ( deleteStatement == null )
  745. {
  746.  
  747.  
  748. StringBuffer deleteSQL = new StringBuffer("DELETE FROM " ).append(onlyTable).append(tableName).append(" where " );
  749.  
  750. for ( int i = 0; i < numKeys; i++ )
  751. {
  752. Utils.appendEscapedIdentifier(deleteSQL, ((PrimaryKey)primaryKeys.get(i)).name);
  753. deleteSQL.append(" = ?");
  754. if ( i < numKeys - 1 )
  755. {
  756. deleteSQL.append( " and " );
  757. }
  758. }
  759.  
  760. deleteStatement = ((java.sql.Connection) connection).prepareStatement(deleteSQL.toString());
  761. }
  762. deleteStatement.clearParameters();
  763.  
  764. for ( int i = 0; i < numKeys; i++ )
  765. {
  766. deleteStatement.setObject(i + 1, ((PrimaryKey) primaryKeys.get(i)).getValue());
  767. }
  768.  
  769.  
  770. deleteStatement.executeUpdate();
  771.  
  772. rows.removeElementAt(current_row);
  773. current_row--;
  774. moveToCurrentRow();
  775. }
  776.  
  777.  
  778. public synchronized void insertRow()
  779. throws SQLException
  780. {
  781. checkUpdateable();
  782.  
  783. if (!onInsertRow)
  784. {
  785. throw new PSQLException(GT.tr("Not on the insert row."), PSQLState.INVALID_CURSOR_STATE);
  786. }
  787. else if (updateValues.size() == 0)
  788. {
  789. throw new PSQLException(GT.tr("You must specify at least one column value to insert a row."),
  790. PSQLState.INVALID_PARAMETER_VALUE);
  791. }
  792. else
  793. {
  794.  
  795. // loop through the keys in the insertTable and create the sql statement
  796. // we have to create the sql every time since the user could insert different
  797. // columns each time
  798.  
  799. StringBuffer insertSQL = new StringBuffer("INSERT INTO ").append(tableName).append(" (");
  800. StringBuffer paramSQL = new StringBuffer(") values (" );
  801.  
  802. Iterator columnNames = updateValues.keySet().iterator();
  803. int numColumns = updateValues.size();
  804.  
  805. for ( int i = 0; columnNames.hasNext(); i++ )
  806. {
  807. String columnName = (String) columnNames.next();
  808.  
  809. Utils.appendEscapedIdentifier(insertSQL, columnName);
  810. if ( i < numColumns - 1 )
  811. {
  812. insertSQL.append(", ");
  813. paramSQL.append("?,");
  814. }
  815. else
  816. {
  817. paramSQL.append("?)");
  818. }
  819.  
  820. }
  821.  
  822. insertSQL.append(paramSQL.toString());
  823. insertStatement = ((java.sql.Connection) connection).prepareStatement(insertSQL.toString());
  824.  
  825. Iterator keys = updateValues.keySet().iterator();
  826.  
  827. for ( int i = 1; keys.hasNext(); i++)
  828. {
  829. String key = (String) keys.next();
  830. Object o = updateValues.get(key);
  831. insertStatement.setObject(i, o);
  832. }
  833.  
  834. insertStatement.executeUpdate();
  835.  
  836. if ( usingOID )
  837. {
  838. // we have to get the last inserted OID and put it in the resultset
  839.  
  840. long insertedOID = ((AbstractJdbc2Statement) insertStatement).getLastOID();
  841.  
  842. updateValues.put("oid", new Long(insertedOID) );
  843.  
  844. }
  845.  
  846. // update the underlying row to the new inserted data
  847. updateRowBuffer();
  848.  
  849. rows.addElement(rowBuffer);
  850.  
  851. // we should now reflect the current data in this_row
  852. // that way getXXX will get the newly inserted data
  853. this_row = rowBuffer;
  854.  
  855. // need to clear this in case of another insert
  856. clearRowBuffer(false);
  857.  
  858.  
  859. }
  860. }
  861.  
  862.  
  863. public synchronized void moveToCurrentRow()
  864. throws SQLException
  865. {
  866. checkUpdateable();
  867.  
  868. if (current_row < 0 || current_row >= rows.size())
  869. {
  870. this_row = null;
  871. rowBuffer = null;
  872. }
  873. else
  874. {
  875. initRowBuffer();
  876. }
  877.  
  878. onInsertRow = false;
  879. doingUpdates = false;
  880. }
  881.  
  882.  
  883. public synchronized void moveToInsertRow()
  884. throws SQLException
  885. {
  886. checkUpdateable();
  887.  
  888. if (insertStatement != null)
  889. {
  890. insertStatement = null;
  891. }
  892.  
  893.  
  894. // make sure the underlying data is null
  895. clearRowBuffer(false);
  896.  
  897. onInsertRow = true;
  898. doingUpdates = false;
  899.  
  900. }
  901.  
  902.  
  903. private synchronized void clearRowBuffer(boolean copyCurrentRow)
  904. throws SQLException
  905. {
  906. // rowBuffer is the temporary storage for the row
  907. rowBuffer = new byte[fields.length][];
  908.  
  909. // inserts want an empty array while updates want a copy of the current row
  910. if (copyCurrentRow)
  911. {
  912. System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
  913. }
  914.  
  915. // clear the updateValues hashTable for the next set of updates
  916. updateValues.clear();
  917.  
  918. }
  919.  
  920.  
  921. public boolean rowDeleted() throws SQLException
  922. {
  923. checkClosed();
  924. return false;
  925. }
  926.  
  927.  
  928. public boolean rowInserted() throws SQLException
  929. {
  930. checkClosed();
  931. return false;
  932. }
  933.  
  934.  
  935. public boolean rowUpdated() throws SQLException
  936. {
  937. checkClosed();
  938. return false;
  939. }
  940.  
  941.  
  942. public synchronized void updateAsciiStream(int columnIndex,
  943. java.io.InputStream x,
  944. int length
  945. )
  946. throws SQLException
  947. {
  948. if (x == null)
  949. {
  950. updateNull(columnIndex);
  951. return ;
  952. }
  953.  
  954. try
  955. {
  956. InputStreamReader reader = new InputStreamReader(x, "ASCII");
  957. char data[] = new char[length];
  958. int numRead = 0;
  959. while (true)
  960. {
  961. int n = reader.read(data, numRead, length - numRead);
  962. if (n == -1)
  963. break;
  964.  
  965. numRead += n;
  966.  
  967. if (numRead == length)
  968. break;
  969. }
  970. updateString(columnIndex, new String(data, 0, numRead));
  971. }
  972. catch (UnsupportedEncodingException uee)
  973. {
  974. throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}","ASCII"), PSQLState.UNEXPECTED_ERROR, uee);
  975. }
  976. catch (IOException ie)
  977. {
  978. throw new PSQLException(GT.tr("Provided InputStream failed."), null, ie);
  979. }
  980. }
  981.  
  982.  
  983. public synchronized void updateBigDecimal(int columnIndex,
  984. java.math.BigDecimal x )
  985. throws SQLException
  986. {
  987. updateValue(columnIndex, x);
  988. }
  989.  
  990.  
  991. public synchronized void updateBinaryStream(int columnIndex,
  992. java.io.InputStream x,
  993. int length
  994. )
  995. throws SQLException
  996. {
  997. if (x == null)
  998. {
  999. updateNull(columnIndex);
  1000. return ;
  1001. }
  1002.  
  1003. byte data[] = new byte[length];
  1004. int numRead = 0;
  1005. try
  1006. {
  1007. while (true)
  1008. {
  1009. int n = x.read(data, numRead, length - numRead);
  1010. if (n == -1)
  1011. break;
  1012.  
  1013. numRead += n;
  1014.  
  1015. if (numRead == length)
  1016. break;
  1017. }
  1018. }
  1019. catch (IOException ie)
  1020. {
  1021. throw new PSQLException(GT.tr("Provided InputStream failed."), null, ie);
  1022. }
  1023.  
  1024. if (numRead == length)
  1025. {
  1026. updateBytes(columnIndex, data);
  1027. }
  1028. else
  1029. {
  1030. // the stream contained less data than they said
  1031. // perhaps this is an error?
  1032. byte data2[] = new byte[numRead];
  1033. System.arraycopy(data, 0, data2, 0, numRead);
  1034. updateBytes(columnIndex, data2);
  1035. }
  1036. }
  1037.  
  1038.  
  1039. public synchronized void updateBoolean(int columnIndex, boolean x)
  1040. throws SQLException
  1041. {
  1042. updateValue(columnIndex, new Boolean(x));
  1043. }
  1044.  
  1045.  
  1046. public synchronized void updateByte(int columnIndex, byte x)
  1047. throws SQLException
  1048. {
  1049. updateValue(columnIndex, String.valueOf(x));
  1050. }
  1051.  
  1052.  
  1053. public synchronized void updateBytes(int columnIndex, byte[] x)
  1054. throws SQLException
  1055. {
  1056. updateValue(columnIndex, x);
  1057. }
  1058.  
  1059.  
  1060. public synchronized void updateCharacterStream(int columnIndex,
  1061. java.io.Reader x,
  1062. int length
  1063. )
  1064. throws SQLException
  1065. {
  1066. if (x == null)
  1067. {
  1068. updateNull(columnIndex);
  1069. return ;
  1070. }
  1071.  
  1072. try
  1073. {
  1074. char data[] = new char[length];
  1075. int numRead = 0;
  1076. while (true)
  1077. {
  1078. int n = x.read(data, numRead, length - numRead);
  1079. if (n == -1)
  1080. break;
  1081.  
  1082. numRead += n;
  1083.  
  1084. if (numRead == length)
  1085. break;
  1086. }
  1087. updateString(columnIndex, new String(data, 0, numRead));
  1088. }
  1089. catch (IOException ie)
  1090. {
  1091. throw new PSQLException(GT.tr("Provided Reader failed."), null, ie);
  1092. }
  1093. }
  1094.  
  1095.  
  1096. public synchronized void updateDate(int columnIndex, java.sql.Date x)
  1097. throws SQLException
  1098. {
  1099. updateValue(columnIndex, x);
  1100. }
  1101.  
  1102.  
  1103. public synchronized void updateDouble(int columnIndex, double x)
  1104. throws SQLException
  1105. {
  1106. updateValue(columnIndex, new Double(x));
  1107. }
  1108.  
  1109.  
  1110. public synchronized void updateFloat(int columnIndex, float x)
  1111. throws SQLException
  1112. {
  1113. updateValue(columnIndex, new Float(x));
  1114. }
  1115.  
  1116.  
  1117. public synchronized void updateInt(int columnIndex, int x)
  1118. throws SQLException
  1119. {
  1120. updateValue(columnIndex, new Integer(x));
  1121. }
  1122.  
  1123.  
  1124. public synchronized void updateLong(int columnIndex, long x)
  1125. throws SQLException
  1126. {
  1127. updateValue(columnIndex, new Long(x));
  1128. }
  1129.  
  1130.  
  1131. public synchronized void updateNull(int columnIndex)
  1132. throws SQLException
  1133. {
  1134. checkColumnIndex(columnIndex);
  1135. String columnTypeName = connection.getTypeInfo().getPGType(fields[columnIndex - 1].getOID());
  1136. updateValue(columnIndex, new NullObject(columnTypeName));
  1137. }
  1138.  
  1139.  
  1140. public synchronized void updateObject(int columnIndex, Object x)
  1141. throws SQLException
  1142. {
  1143. updateValue(columnIndex, x);
  1144. }
  1145.  
  1146.  
  1147. public synchronized void updateObject(int columnIndex, Object x, int scale)
  1148. throws SQLException
  1149. {
  1150. this.updateObject(columnIndex, x);
  1151.  
  1152. }
  1153.  
  1154.  
  1155. public void refreshRow() throws SQLException
  1156. {
  1157. checkUpdateable();
  1158. if (onInsertRow)
  1159. throw new PSQLException(GT.tr("Can''t refresh the insert row."),
  1160. PSQLState.INVALID_CURSOR_STATE);
  1161.  
  1162. if (isBeforeFirst() || isAfterLast() || rows.size() == 0)
  1163. return ;
  1164.  
  1165. StringBuffer selectSQL = new StringBuffer( "select ");
  1166.  
  1167. final int numColumns = java.lang.reflect.Array.getLength(fields);
  1168.  
  1169. for (int i = 0; i < numColumns; i++ )
  1170. {
  1171. selectSQL.append( fields[i].getColumnName(connection) );
  1172.  
  1173. if ( i < numColumns - 1 )
  1174. {
  1175.  
  1176. selectSQL.append(", ");
  1177. }
  1178.  
  1179. }
  1180. selectSQL.append(" from " ).append(onlyTable).append(tableName).append(" where ");
  1181.  
  1182. int numKeys = primaryKeys.size();
  1183.  
  1184. for ( int i = 0; i < numKeys; i++ )
  1185. {
  1186.  
  1187. PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
  1188. selectSQL.append(primaryKey.name).append("= ?");
  1189.  
  1190. if ( i < numKeys - 1 )
  1191. {
  1192. selectSQL.append(" and ");
  1193. }
  1194. }
  1195. if ( connection.getLogger().logDebug() )
  1196. connection.getLogger().debug("selecting " + selectSQL.toString());
  1197. selectStatement = ((java.sql.Connection) connection).prepareStatement(selectSQL.toString());
  1198.  
  1199.  
  1200. for ( int j = 0, i = 1; j < numKeys; j++, i++)
  1201. {
  1202. selectStatement.setObject( i, ((PrimaryKey) primaryKeys.get(j)).getValue() );
  1203. }
  1204.  
  1205. AbstractJdbc2ResultSet rs = (AbstractJdbc2ResultSet) selectStatement.executeQuery();
  1206.  
  1207. if ( rs.next() )
  1208. {
  1209. rowBuffer = rs.this_row;
  1210. }
  1211.  
  1212. rows.setElementAt( rowBuffer, current_row );
  1213. this_row = rowBuffer;
  1214.  
  1215. connection.getLogger().debug("done updates");
  1216.  
  1217. rs.close();
  1218. selectStatement.close();
  1219. selectStatement = null;
  1220.  
  1221. }
  1222.  
  1223.  
  1224. public synchronized void updateRow()
  1225. throws SQLException
  1226. {
  1227. checkUpdateable();
  1228.  
  1229. if (onInsertRow)
  1230. {
  1231. throw new PSQLException(GT.tr("Cannot call updateRow() when on the insert row."),
  1232. PSQLState.INVALID_CURSOR_STATE);
  1233. }
  1234.  
  1235. if (isBeforeFirst() || isAfterLast() || rows.size() == 0)
  1236. {
  1237. throw new PSQLException(GT.tr("Cannot update the ResultSet because it is either before the start or after the end of the results."),
  1238. PSQLState.INVALID_CURSOR_STATE);
  1239. }
  1240.  
  1241. if (!doingUpdates)
  1242. return; // No work pending.
  1243.  
  1244. StringBuffer updateSQL = new StringBuffer("UPDATE " + onlyTable + tableName + " SET ");
  1245.  
  1246. int numColumns = updateValues.size();
  1247. Iterator columns = updateValues.keySet().iterator();
  1248.  
  1249. for (int i = 0; columns.hasNext(); i++ )
  1250. {
  1251. String column = (String) columns.next();
  1252. Utils.appendEscapedIdentifier(updateSQL, column);
  1253. updateSQL.append(" = ?");
  1254.  
  1255. if ( i < numColumns - 1 )
  1256. updateSQL.append(", ");
  1257. }
  1258.  
  1259. updateSQL.append( " WHERE " );
  1260.  
  1261. int numKeys = primaryKeys.size();
  1262.  
  1263. for ( int i = 0; i < numKeys; i++ )
  1264. {
  1265. PrimaryKey primaryKey = ((PrimaryKey) primaryKeys.get(i));
  1266. Utils.appendEscapedIdentifier(updateSQL, primaryKey.name);
  1267. updateSQL.append(" = ?");
  1268.  
  1269. if ( i < numKeys - 1 )
  1270. updateSQL.append(" and ");
  1271. }
  1272.  
  1273. if ( connection.getLogger().logDebug() )
  1274. connection.getLogger().debug("updating " + updateSQL.toString());
  1275. updateStatement = ((java.sql.Connection) connection).prepareStatement(updateSQL.toString());
  1276.  
  1277. int i = 0;
  1278. Iterator iterator = updateValues.values().iterator();
  1279. for (; iterator.hasNext(); i++)
  1280. {
  1281. Object o = iterator.next();
  1282. updateStatement.setObject( i + 1, o );
  1283. }
  1284.  
  1285. for ( int j = 0; j < numKeys; j++, i++)
  1286. {
  1287. updateStatement.setObject( i + 1, ((PrimaryKey) primaryKeys.get(j)).getValue() );
  1288. }
  1289.  
  1290. updateStatement.executeUpdate();
  1291. updateStatement.close();
  1292. updateStatement = null;
  1293.  
  1294. updateRowBuffer();
  1295.  
  1296. connection.getLogger().debug("copying data");
  1297. System.arraycopy(rowBuffer, 0, this_row, 0, rowBuffer.length);
  1298. rows.setElementAt( rowBuffer, current_row );
  1299.  
  1300. connection.getLogger().debug("done updates");
  1301. updateValues.clear();
  1302. doingUpdates = false;
  1303. }
  1304.  
  1305.  
  1306. public synchronized void updateShort(int columnIndex, short x)
  1307. throws SQLException
  1308. {
  1309. updateValue(columnIndex, new Short(x));
  1310. }
  1311.  
  1312.  
  1313. public synchronized void updateString(int columnIndex, String x)
  1314. throws SQLException
  1315. {
  1316. updateValue(columnIndex, x);
  1317. }
  1318.  
  1319.  
  1320. public synchronized void updateTime(int columnIndex, Time x)
  1321. throws SQLException
  1322. {
  1323. updateValue(columnIndex, x);
  1324. }
  1325.  
  1326.  
  1327. public synchronized void updateTimestamp(int columnIndex, Timestamp x)
  1328. throws SQLException
  1329. {
  1330. updateValue(columnIndex, x);
  1331.  
  1332. }
  1333.  
  1334.  
  1335. public synchronized void updateNull(String columnName)
  1336. throws SQLException
  1337. {
  1338. updateNull(findColumn(columnName));
  1339. }
  1340.  
  1341.  
  1342. public synchronized void updateBoolean(String columnName, boolean x)
  1343. throws SQLException
  1344. {
  1345. updateBoolean(findColumn(columnName), x);
  1346. }
  1347.  
  1348.  
  1349. public synchronized void updateByte(String columnName, byte x)
  1350. throws SQLException
  1351. {
  1352. updateByte(findColumn(columnName), x);
  1353. }
  1354.  
  1355.  
  1356. public synchronized void updateShort(String columnName, short x)
  1357. throws SQLException
  1358. {
  1359. updateShort(findColumn(columnName), x);
  1360. }
  1361.  
  1362.  
  1363. public synchronized void updateInt(String columnName, int x)
  1364. throws SQLException
  1365. {
  1366. updateInt(findColumn(columnName), x);
  1367. }
  1368.  
  1369.  
  1370. public synchronized void updateLong(String columnName, long x)
  1371. throws SQLException
  1372. {
  1373. updateLong(findColumn(columnName), x);
  1374. }
  1375.  
  1376.  
  1377. public synchronized void updateFloat(String columnName, float x)
  1378. throws SQLException
  1379. {
  1380. updateFloat(findColumn(columnName), x);
  1381. }
  1382.  
  1383.  
  1384. public synchronized void updateDouble(String columnName, double x)
  1385. throws SQLException
  1386. {
  1387. updateDouble(findColumn(columnName), x);
  1388. }
  1389.  
  1390.  
  1391. public synchronized void updateBigDecimal(String columnName, BigDecimal x)
  1392. throws SQLException
  1393. {
  1394. updateBigDecimal(findColumn(columnName), x);
  1395. }
  1396.  
  1397.  
  1398. public synchronized void updateString(String columnName, String x)
  1399. throws SQLException
  1400. {
  1401. updateString(findColumn(columnName), x);
  1402. }
  1403.  
  1404.  
  1405. public synchronized void updateBytes(String columnName, byte x[])
  1406. throws SQLException
  1407. {
  1408. updateBytes(findColumn(columnName), x);
  1409. }
  1410.  
  1411.  
  1412. public synchronized void updateDate(String columnName, java.sql.Date x)
  1413. throws SQLException
  1414. {
  1415. updateDate(findColumn(columnName), x);
  1416. }
  1417.  
  1418.  
  1419. public synchronized void updateTime(String columnName, java.sql.Time x)
  1420. throws SQLException
  1421. {
  1422. updateTime(findColumn(columnName), x);
  1423. }
  1424.  
  1425.  
  1426. public synchronized void updateTimestamp(String columnName, java.sql.Timestamp x)
  1427. throws SQLException
  1428. {
  1429. updateTimestamp(findColumn(columnName), x);
  1430. }
  1431.  
  1432.  
  1433. public synchronized void updateAsciiStream(
  1434. String columnName,
  1435. java.io.InputStream x,
  1436. int length)
  1437. throws SQLException
  1438. {
  1439. updateAsciiStream(findColumn(columnName), x, length);
  1440. }
  1441.  
  1442.  
  1443. public synchronized void updateBinaryStream(
  1444. String columnName,
  1445. java.io.InputStream x,
  1446. int length)
  1447. throws SQLException
  1448. {
  1449. updateBinaryStream(findColumn(columnName), x, length);
  1450. }
  1451.  
  1452.  
  1453. public synchronized void updateCharacterStream(
  1454. String columnName,
  1455. java.io.Reader reader,
  1456. int length)
  1457. throws SQLException
  1458. {
  1459. updateCharacterStream(findColumn(columnName), reader, length);
  1460. }
  1461.  
  1462.  
  1463. public synchronized void updateObject(String columnName, Object x, int scale)
  1464. throws SQLException
  1465. {
  1466. updateObject(findColumn(columnName), x);
  1467. }
  1468.  
  1469.  
  1470. public synchronized void updateObject(String columnName, Object x)
  1471. throws SQLException
  1472. {
  1473. updateObject(findColumn(columnName), x);
  1474. }
  1475.  
  1476.  
  1477. /**
  1478. * Is this ResultSet updateable?
  1479. */
  1480.  
  1481. boolean isUpdateable() throws SQLException
  1482. {
  1483. checkClosed();
  1484.  
  1485. if (resultsetconcurrency == ResultSet.CONCUR_READ_ONLY)
  1486. throw new PSQLException(GT.tr("ResultSets with concurrency CONCUR_READ_ONLY cannot be updated."),
  1487. PSQLState.INVALID_CURSOR_STATE);
  1488.  
  1489. if (updateable)
  1490. return true;
  1491.  
  1492. connection.getLogger().debug("checking if rs is updateable");
  1493.  
  1494. parseQuery();
  1495.  
  1496. if ( singleTable == false )
  1497. {
  1498. connection.getLogger().debug("not a single table");
  1499. return false;
  1500. }
  1501.  
  1502. connection.getLogger().debug("getting primary keys");
  1503.  
  1504. //
  1505. // Contains the primary key?
  1506. //
  1507.  
  1508. primaryKeys = new Vector();
  1509.  
  1510. // this is not stricty jdbc spec, but it will make things much faster if used
  1511. // the user has to select oid, * from table and then we will just use oid
  1512.  
  1513.  
  1514. usingOID = false;
  1515. int oidIndex = findColumnIndexByLabel( "oid" ); // 0 if not present
  1516.  
  1517. int i = 0;
  1518.  
  1519. // if we find the oid then just use it
  1520.  
  1521. //oidIndex will be >0 if the oid was in the select list
  1522. if ( oidIndex > 0 )
  1523. {
  1524. i++;
  1525. primaryKeys.add( new PrimaryKey( oidIndex, "oid" ) );
  1526. usingOID = true;
  1527. }
  1528. else
  1529. {
  1530. // otherwise go and get the primary keys and create a hashtable of keys
  1531. String[] s = quotelessTableName(tableName);
  1532. String quotelessTableName = s[0];
  1533. String quotelessSchemaName = s[1];
  1534. java.sql.ResultSet rs = ((java.sql.Connection) connection).getMetaData().getPrimaryKeys("", quotelessSchemaName, quotelessTableName);
  1535. for (; rs.next(); i++ )
  1536. {
  1537. String columnName = rs.getString(4); // get the columnName
  1538. int index = findColumnIndexByName( columnName );
  1539.  
  1540. if ( index > 0 )
  1541. {
  1542. primaryKeys.add( new PrimaryKey(index, columnName ) ); // get the primary key information
  1543. }
  1544. }
  1545.  
  1546. rs.close();
  1547. }
  1548.  
  1549. if ( connection.getLogger().logDebug() )
  1550. connection.getLogger().debug( "no of keys=" + i );
  1551.  
  1552. if ( i < 1 )
  1553. {
  1554. throw new PSQLException(GT.tr("No primary key found for table {0}.", tableName),
  1555. PSQLState.DATA_ERROR);
  1556. }
  1557.  
  1558. updateable = primaryKeys.size() > 0;
  1559.  
  1560. if ( connection.getLogger().logDebug() )
  1561. connection.getLogger().debug( "checking primary key " + updateable );
  1562.  
  1563. return updateable;
  1564. }
  1565.  
  1566. /** Cracks out the table name and schema (if it exists) from a fully
  1567. * qualified table name.
  1568. * @param fullname string that we are trying to crack. Test cases:<pre>
  1569. * Table: table ()
  1570. * "Table": Table ()
  1571. * Schema.Table: table (schema)
  1572. * "Schema"."Table": Table (Schema)
  1573. * "Schema"."Dot.Table": Dot.Table (Schema)
  1574. * Schema."Dot.Table": Dot.Table (schema)
  1575. * </pre>
  1576. * @return String array with element zero always being the tablename and
  1577. * element 1 the schema name which may be a zero length string.
  1578. */
  1579. public static String[] quotelessTableName(String fullname) {
  1580. StringBuffer buf = new StringBuffer(fullname);
  1581. String[] parts = new String[] {null, ""};
  1582. StringBuffer acc = new StringBuffer();
  1583. boolean betweenQuotes = false;
  1584. for (int i = 0; i < buf.length(); i++)
  1585. {
  1586. char c = buf.charAt(i);
  1587. switch (c)
  1588. {
  1589. case '"':
  1590. if ((i < buf.length() - 1) && (buf.charAt(i + 1) == '"'))
  1591. {
  1592. // two consecutive quotes - keep one
  1593. i++;
  1594. acc.append(c); // keep the quote
  1595. }
  1596. else
  1597. { // Discard it
  1598. betweenQuotes = !betweenQuotes;
  1599. }
  1600. break;
  1601. case '.':
  1602. if (betweenQuotes)
  1603. { // Keep it
  1604. acc.append(c);
  1605. }
  1606. else
  1607. { // Have schema name
  1608. parts[1] = acc.toString();
  1609. acc = new StringBuffer();
  1610. }
  1611. break;
  1612. default:
  1613. acc.append((betweenQuotes) ? c : Character.toLowerCase(c));
  1614. break;
  1615. }
  1616. }
  1617. // Always put table in slot 0
  1618. parts[0] = acc.toString();
  1619. return parts;
  1620. }
  1621.  
  1622. private void parseQuery()
  1623. {
  1624. String l_sql = originalQuery.toString(null);
  1625. StringTokenizer st = new StringTokenizer(l_sql, " \r\t\n");
  1626. boolean tableFound = false, tablesChecked = false;
  1627. String name = "";
  1628.  
  1629. singleTable = true;
  1630.  
  1631. while ( !tableFound && !tablesChecked && st.hasMoreTokens() )
  1632. {
  1633. name = st.nextToken();
  1634. if ( !tableFound )
  1635. {
  1636. if ("from".equalsIgnoreCase(name))
  1637. {
  1638. tableName = st.nextToken();
  1639. if ("only".equalsIgnoreCase(tableName)) {
  1640. tableName = st.nextToken();
  1641. onlyTable = "ONLY ";
  1642. }
  1643. tableFound = true;
  1644. }
  1645. }
  1646. else
  1647. {
  1648. tablesChecked = true;
  1649. // if the very next token is , then there are multiple tables
  1650. singleTable = !name.equalsIgnoreCase(",");
  1651. }
  1652. }
  1653. }
  1654.  
  1655.  
  1656. private void updateRowBuffer() throws SQLException
  1657. {
  1658.  
  1659. Iterator columns = updateValues.keySet().iterator();
  1660.  
  1661. while ( columns.hasNext() )
  1662. {
  1663. String columnName = (String) columns.next();
  1664. // Wrong: int columnIndex = findColumn( columnName ) - 1;
  1665. // it looks for column labels, but updateValues.keySet() contains
  1666. // column _names_.
  1667. // Changed into this:
  1668. int columnIndex = findColumnIndexByName( columnName ) - 1;
  1669.  
  1670. Object valueObject = updateValues.get(columnName);
  1671. if (valueObject instanceof NullObject)
  1672. {
  1673. rowBuffer[columnIndex] = null;
  1674. }
  1675. else
  1676. {
  1677. switch ( getSQLType(columnIndex + 1) )
  1678. {
  1679.  
  1680. case Types.DECIMAL:
  1681. case Types.BIGINT:
  1682. case Types.DOUBLE:
  1683. case Types.BIT:
  1684. case Types.VARCHAR:
  1685. case Types.SMALLINT:
  1686. case Types.FLOAT:
  1687. case Types.INTEGER:
  1688. case Types.CHAR:
  1689. case Types.NUMERIC:
  1690. case Types.REAL:
  1691. case Types.TINYINT:
  1692. case Types.ARRAY:
  1693. case Types.OTHER:
  1694. rowBuffer[columnIndex] = connection.encodeString(String.valueOf( valueObject));
  1695. break;
  1696.  
  1697. //
  1698. // toString() isn't enough for date and time types; we must format it correctly
  1699. // or we won't be able to re-parse it.
  1700. //
  1701.  
  1702. case Types.DATE:
  1703. rowBuffer[columnIndex] =
  1704. connection.encodeString(connection.getTimestampUtils().toString(null, (Date)valueObject));
  1705. break;
  1706.  
  1707. case Types.TIME:
  1708. rowBuffer[columnIndex] =
  1709. connection.encodeString(connection.getTimestampUtils().toString(null, (Time)valueObject));
  1710. break;
  1711.  
  1712. case Types.TIMESTAMP:
  1713. rowBuffer[columnIndex] =
  1714. connection.encodeString(connection.getTimestampUtils().toString(null, (Timestamp)valueObject));
  1715. break;
  1716.  
  1717. case Types.NULL:
  1718. // Should never happen?
  1719. break;
  1720.  
  1721. case Types.BINARY:
  1722. case Types.LONGVARBINARY:
  1723. case Types.VARBINARY:
  1724. if (fields[columnIndex].getFormat() == Field.BINARY_FORMAT) {
  1725. rowBuffer[columnIndex] = (byte[]) valueObject;
  1726. } else {
  1727. try {
  1728. rowBuffer[columnIndex] = PGbytea.toPGString((byte[]) valueObject).getBytes("ISO-8859-1");
  1729. } catch (UnsupportedEncodingException e) {
  1730. throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}", "ISO-8859-1"), PSQLState.UNEXPECTED_ERROR, e);
  1731. }
  1732. }
  1733. break;
  1734.  
  1735. default:
  1736. rowBuffer[columnIndex] = (byte[]) valueObject;
  1737. }
  1738.  
  1739. }
  1740. }
  1741. }
  1742.  
  1743. public class CursorResultHandler implements ResultHandler {
  1744. private SQLException error;
  1745.  
  1746. public void handleResultRows(Query fromQuery, Field[] fields, Vector tuples, ResultCursor cursor) {
  1747. AbstractJdbc2ResultSet.this.rows = tuples;
  1748. AbstractJdbc2ResultSet.this.cursor = cursor;
  1749. }
  1750.  
  1751. public void handleCommandStatus(String status, int updateCount, long insertOID) {
  1752. handleError(new PSQLException(GT.tr("Unexpected command status: {0}.", status),
  1753. PSQLState.PROTOCOL_VIOLATION));
  1754. }
  1755.  
  1756. public void handleWarning(SQLWarning warning) {
  1757. AbstractJdbc2ResultSet.this.addWarning(warning);
  1758. }
  1759.  
  1760. public void handleError(SQLException newError) {
  1761. if (error == null)
  1762. error = newError;
  1763. else
  1764. error.setNextException(newError);
  1765. }
  1766.  
  1767. public void handleCompletion() throws SQLException {
  1768. if (error != null)
  1769. throw error;
  1770. }
  1771. };
  1772.  
  1773.  
  1774. public BaseStatement getPGStatement() {
  1775. return statement;
  1776. }
  1777.  
  1778. //
  1779. // Backwards compatibility with PGRefCursorResultSet
  1780. //
  1781.  
  1782. private String refCursorName;
  1783.  
  1784. public String getRefCursor() {
  1785. // Can't check this because the PGRefCursorResultSet
  1786. // interface doesn't allow throwing a SQLException
  1787. //
  1788. // checkClosed();
  1789. return refCursorName;
  1790. }
  1791.  
  1792. private void setRefCursor(String refCursorName) {
  1793. this.refCursorName = refCursorName;
  1794. }
  1795.  
  1796. public void setFetchSize(int rows) throws SQLException
  1797. {
  1798. checkClosed();
  1799. if (rows < 0)
  1800. throw new PSQLException(GT.tr("Fetch size must be a value greater to or equal to 0."),
  1801. PSQLState.INVALID_PARAMETER_VALUE);
  1802. fetchSize = rows;
  1803. }
  1804.  
  1805. public int getFetchSize() throws SQLException
  1806. {
  1807. checkClosed();
  1808. return fetchSize;
  1809. }
  1810.  
  1811. public boolean next() throws SQLException
  1812. {
  1813. checkClosed();
  1814.  
  1815. if (onInsertRow)
  1816. throw new PSQLException(GT.tr("Can''t use relative move methods while on the insert row."),
  1817. PSQLState.INVALID_CURSOR_STATE);
  1818.  
  1819. if (current_row + 1 >= rows.size())
  1820. {
  1821. if (cursor == null || (maxRows > 0 && row_offset + rows.size() >= maxRows))
  1822. {
  1823. current_row = rows.size();
  1824. this_row = null;
  1825. rowBuffer = null;
  1826. return false; // End of the resultset.
  1827. }
  1828.  
  1829. // Ask for some more data.
  1830. row_offset += rows.size(); // We are discarding some data.
  1831.  
  1832. int fetchRows = fetchSize;
  1833. if (maxRows != 0)
  1834. {
  1835. if (fetchRows == 0 || row_offset + fetchRows > maxRows) // Fetch would exceed maxRows, limit it.
  1836. fetchRows = maxRows - row_offset;
  1837. }
  1838.  
  1839. // Execute the fetch and update this resultset.
  1840. connection.getQueryExecutor().fetch(cursor, new CursorResultHandler(), fetchRows);
  1841.  
  1842. current_row = 0;
  1843.  
  1844. // Test the new rows array.
  1845. if (rows.size() == 0)
  1846. {
  1847. this_row = null;
  1848. rowBuffer = null;
  1849. return false;
  1850. }
  1851. }
  1852. else
  1853. {
  1854. current_row++;
  1855. }
  1856.  
  1857. initRowBuffer();
  1858. return true;
  1859. }
  1860.  
  1861. public void close() throws SQLException
  1862. {
  1863. //release resources held (memory for tuples)
  1864. rows = null;
  1865. if (cursor != null) {
  1866. cursor.close();
  1867. cursor = null;
  1868. }
  1869. }
  1870.  
  1871. public boolean wasNull() throws SQLException
  1872. {
  1873. checkClosed();
  1874. return wasNullFlag;
  1875. }
  1876.  
  1877. public String getString(int columnIndex) throws SQLException
  1878. {
  1879. checkResultSet( columnIndex );
  1880. if (wasNullFlag)
  1881. return null;
  1882.  
  1883. Encoding encoding = connection.getEncoding();
  1884. try
  1885. {
  1886. return trimString(columnIndex, encoding.decode(this_row[columnIndex - 1]));
  1887. }
  1888. catch (IOException ioe)
  1889. {
  1890. throw new PSQLException(GT.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."), PSQLState.DATA_ERROR, ioe);
  1891. }
  1892. }
  1893.  
  1894. public boolean getBoolean(int columnIndex) throws SQLException
  1895. {
  1896. checkResultSet(columnIndex);
  1897. if (wasNullFlag)
  1898. return false; // SQL NULL
  1899.  
  1900. return toBoolean( getString(columnIndex) );
  1901. }
  1902.  
  1903. private static final BigInteger BYTEMAX = new BigInteger(Byte.toString(Byte.MAX_VALUE));
  1904. private static final BigInteger BYTEMIN = new BigInteger(Byte.toString(Byte.MIN_VALUE));
  1905.  
  1906. public byte getByte(int columnIndex) throws SQLException
  1907. {
  1908. checkResultSet(columnIndex);
  1909. if (wasNullFlag)
  1910. return 0; // SQL NULL
  1911.  
  1912. String s = getString(columnIndex);
  1913.  
  1914. if (s != null )
  1915. {
  1916. s = s.trim();
  1917. if ( s.length() == 0 )
  1918. return 0;
  1919. try
  1920. {
  1921. // try the optimal parse
  1922. return Byte.parseByte(s);
  1923. }
  1924. catch (NumberFormatException e)
  1925. {
  1926. // didn't work, assume the column is not a byte
  1927. try
  1928. {
  1929. BigDecimal n = new BigDecimal(s);
  1930. BigInteger i = n.toBigInteger();
  1931.  
  1932. int gt = i.compareTo(BYTEMAX);
  1933. int lt = i.compareTo(BYTEMIN);
  1934.  
  1935. if ( gt > 0 || lt < 0 )
  1936. {
  1937. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"byte",s}),
  1938. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  1939. }
  1940. return i.byteValue();
  1941. }
  1942. catch ( NumberFormatException ex )
  1943. {
  1944. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"byte",s}),
  1945. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  1946. }
  1947. }
  1948. }
  1949. return 0; // SQL NULL
  1950. }
  1951.  
  1952. private static final BigInteger SHORTMAX = new BigInteger(Short.toString(Short.MAX_VALUE));
  1953. private static final BigInteger SHORTMIN = new BigInteger(Short.toString(Short.MIN_VALUE));
  1954.  
  1955. public short getShort(int columnIndex) throws SQLException
  1956. {
  1957. checkResultSet(columnIndex);
  1958. if (wasNullFlag)
  1959. return 0; // SQL NULL
  1960.  
  1961. String s = getFixedString(columnIndex);
  1962.  
  1963. if (s != null)
  1964. {
  1965. s = s.trim();
  1966. try
  1967. {
  1968. return Short.parseShort(s);
  1969. }
  1970. catch (NumberFormatException e)
  1971. {
  1972. try
  1973. {
  1974. BigDecimal n = new BigDecimal(s);
  1975. BigInteger i = n.toBigInteger();
  1976. int gt = i.compareTo(SHORTMAX);
  1977. int lt = i.compareTo(SHORTMIN);
  1978.  
  1979. if ( gt > 0 || lt < 0 )
  1980. {
  1981. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"short",s}),
  1982. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  1983. }
  1984. return i.shortValue();
  1985.  
  1986. }
  1987. catch ( NumberFormatException ne )
  1988. {
  1989. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"short",s}),
  1990. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  1991. }
  1992. }
  1993. }
  1994. return 0; // SQL NULL
  1995. }
  1996.  
  1997. public int getInt(int columnIndex) throws SQLException
  1998. {
  1999. checkResultSet(columnIndex);
  2000. if (wasNullFlag)
  2001. return 0; // SQL NULL
  2002.  
  2003. Encoding encoding = connection.getEncoding();
  2004. if (encoding.hasAsciiNumbers()) {
  2005. try {
  2006. return getFastInt(columnIndex);
  2007. } catch (NumberFormatException ex) {
  2008. }
  2009. }
  2010. return toInt( getFixedString(columnIndex) );
  2011. }
  2012.  
  2013. public long getLong(int columnIndex) throws SQLException
  2014. {
  2015. checkResultSet(columnIndex);
  2016. if (wasNullFlag)
  2017. return 0; // SQL NULL
  2018.  
  2019. Encoding encoding = connection.getEncoding();
  2020. if (encoding.hasAsciiNumbers()) {
  2021. try {
  2022. return getFastLong(columnIndex);
  2023. } catch (NumberFormatException ex) {
  2024. }
  2025. }
  2026. return toLong( getFixedString(columnIndex) );
  2027. }
  2028.  
  2029. /**
  2030. * A dummy exception thrown when fast byte[] to number parsing fails and
  2031. * no value can be returned. The exact stack trace does not matter because
  2032. * the exception is always caught and is not visible to users.
  2033. */
  2034. private static final NumberFormatException FAST_NUMBER_FAILED =
  2035. new NumberFormatException();
  2036.  
  2037. /**
  2038. * Optimised byte[] to number parser. This code does not
  2039. * handle null values, so the caller must do checkResultSet
  2040. * and handle null values prior to calling this function.
  2041. *
  2042. * @param columnIndex The column to parse.
  2043. * @return The parsed number.
  2044. * @throws SQLException If an error occurs while fetching column.
  2045. * @throws NumberFormatException If the number is invalid or the
  2046. * out of range for fast parsing. The value must then be parsed by
  2047. * {@link #toLong(String)}.
  2048. */
  2049. private long getFastLong(int columnIndex) throws SQLException,
  2050. NumberFormatException {
  2051.  
  2052. byte[] bytes = this_row[columnIndex - 1];
  2053.  
  2054. if (bytes.length == 0) {
  2055. throw FAST_NUMBER_FAILED;
  2056. }
  2057.  
  2058. long val = 0;
  2059. int start;
  2060. boolean neg;
  2061. if (bytes[0] == '-') {
  2062. neg = true;
  2063. start = 1;
  2064. if (bytes.length == 1 || bytes.length > 19) {
  2065. throw FAST_NUMBER_FAILED;
  2066. }
  2067. } else {
  2068. start = 0;
  2069. neg = false;
  2070. if (bytes.length > 18) {
  2071. throw FAST_NUMBER_FAILED;
  2072. }
  2073. }
  2074.  
  2075. while (start < bytes.length) {
  2076. byte b = bytes[start++];
  2077. if (b < '0' || b > '9') {
  2078. throw FAST_NUMBER_FAILED;
  2079. }
  2080.  
  2081. val *= 10;
  2082. val += b - '0';
  2083. }
  2084.  
  2085. if (neg) {
  2086. val = -val;
  2087. }
  2088.  
  2089. return val;
  2090. }
  2091.  
  2092. /**
  2093. * Optimised byte[] to number parser. This code does not
  2094. * handle null values, so the caller must do checkResultSet
  2095. * and handle null values prior to calling this function.
  2096. *
  2097. * @param columnIndex The column to parse.
  2098. * @return The parsed number.
  2099. * @throws SQLException If an error occurs while fetching column.
  2100. * @throws NumberFormatException If the number is invalid or the
  2101. * out of range for fast parsing. The value must then be parsed by
  2102. * {@link #toInt(String)}.
  2103. */
  2104. private int getFastInt(int columnIndex) throws SQLException,
  2105. NumberFormatException {
  2106.  
  2107. byte[] bytes = this_row[columnIndex - 1];
  2108.  
  2109. if (bytes.length == 0) {
  2110. throw FAST_NUMBER_FAILED;
  2111. }
  2112.  
  2113. int val = 0;
  2114. int start;
  2115. boolean neg;
  2116. if (bytes[0] == '-') {
  2117. neg = true;
  2118. start = 1;
  2119. if (bytes.length == 1 || bytes.length > 10) {
  2120. throw FAST_NUMBER_FAILED;
  2121. }
  2122. } else {
  2123. start = 0;
  2124. neg = false;
  2125. if (bytes.length > 9) {
  2126. throw FAST_NUMBER_FAILED;
  2127. }
  2128. }
  2129.  
  2130. while (start < bytes.length) {
  2131. byte b = bytes[start++];
  2132. if (b < '0' || b > '9') {
  2133. throw FAST_NUMBER_FAILED;
  2134. }
  2135.  
  2136. val *= 10;
  2137. val += b - '0';
  2138. }
  2139.  
  2140. if (neg) {
  2141. val = -val;
  2142. }
  2143.  
  2144. return val;
  2145. }
  2146.  
  2147. /**
  2148. * Optimised byte[] to number parser. This code does not
  2149. * handle null values, so the caller must do checkResultSet
  2150. * and handle null values prior to calling this function.
  2151. *
  2152. * @param columnIndex The column to parse.
  2153. * @return The parsed number.
  2154. * @throws SQLException If an error occurs while fetching column.
  2155. * @throws NumberFormatException If the number is invalid or the
  2156. * out of range for fast parsing. The value must then be parsed by
  2157. * {@link #toBigDecimal(String)}.
  2158. */
  2159. private BigDecimal getFastBigDecimal(int columnIndex) throws SQLException,
  2160. NumberFormatException {
  2161.  
  2162. byte[] bytes = this_row[columnIndex - 1];
  2163.  
  2164. if (bytes.length == 0) {
  2165. throw FAST_NUMBER_FAILED;
  2166. }
  2167.  
  2168. int scale = 0;
  2169. long val = 0;
  2170. int start;
  2171. boolean neg;
  2172. if (bytes[0] == '-') {
  2173. neg = true;
  2174. start = 1;
  2175. if (bytes.length == 1 || bytes.length > 19) {
  2176. throw FAST_NUMBER_FAILED;
  2177. }
  2178. } else {
  2179. start = 0;
  2180. neg = false;
  2181. if (bytes.length > 18) {
  2182. throw FAST_NUMBER_FAILED;
  2183. }
  2184. }
  2185.  
  2186. int periodsSeen = 0;
  2187. while (start < bytes.length) {
  2188. byte b = bytes[start++];
  2189. if (b < '0' || b > '9') {
  2190. if (b == '.') {
  2191. scale = bytes.length - start;
  2192. periodsSeen++;
  2193. continue;
  2194. } else
  2195. throw FAST_NUMBER_FAILED;
  2196. }
  2197. val *= 10;
  2198. val += b - '0';
  2199. }
  2200.  
  2201. int numNonSignChars = neg ? bytes.length - 1 : bytes.length;
  2202. if (periodsSeen > 1 || periodsSeen == numNonSignChars)
  2203. throw FAST_NUMBER_FAILED;
  2204.  
  2205. if (neg) {
  2206. val = -val;
  2207. }
  2208.  
  2209. return BigDecimal.valueOf(val, scale);
  2210. }
  2211.  
  2212. public float getFloat(int columnIndex) throws SQLException
  2213. {
  2214. checkResultSet(columnIndex);
  2215. if (wasNullFlag)
  2216. return 0; // SQL NULL
  2217.  
  2218. return toFloat( getFixedString(columnIndex) );
  2219. }
  2220.  
  2221. public double getDouble(int columnIndex) throws SQLException
  2222. {
  2223. checkResultSet(columnIndex);
  2224. if (wasNullFlag)
  2225. return 0; // SQL NULL
  2226.  
  2227. return toDouble( getFixedString(columnIndex) );
  2228. }
  2229.  
  2230. public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException
  2231. {
  2232. checkResultSet(columnIndex);
  2233. if (wasNullFlag)
  2234. return null;
  2235.  
  2236. Encoding encoding = connection.getEncoding();
  2237. if (encoding.hasAsciiNumbers()) {
  2238. try {
  2239. return getFastBigDecimal(columnIndex);
  2240. } catch (NumberFormatException ex) {
  2241. }
  2242. }
  2243.  
  2244. return toBigDecimal( getFixedString(columnIndex), scale );
  2245. }
  2246.  
  2247. /*
  2248. * Get the value of a column in the current row as a Java byte array.
  2249. *
  2250. * <p>In normal use, the bytes represent the raw values returned by the
  2251. * backend. However, if the column is an OID, then it is assumed to
  2252. * refer to a Large Object, and that object is returned as a byte array.
  2253. *
  2254. * <p><b>Be warned</b> If the large object is huge, then you may run out
  2255. * of memory.
  2256. *
  2257. * @param columnIndex the first column is 1, the second is 2, ...
  2258. * @return the column value; if the value is SQL NULL, the result
  2259. * is null
  2260. * @exception SQLException if a database access error occurs
  2261. */
  2262. public byte[] getBytes(int columnIndex) throws SQLException
  2263. {
  2264. checkResultSet( columnIndex );
  2265. if (wasNullFlag)
  2266. return null;
  2267.  
  2268. if (fields[columnIndex - 1].getFormat() == Field.BINARY_FORMAT)
  2269. {
  2270. //If the data is already binary then just return it
  2271. return this_row[columnIndex - 1];
  2272. }
  2273. else if (connection.haveMinimumCompatibleVersion("7.2"))
  2274. {
  2275. //Version 7.2 supports the bytea datatype for byte arrays
  2276. if (fields[columnIndex - 1].getOID() == Oid.BYTEA)
  2277. {
  2278. return trimBytes(columnIndex, PGbytea.toBytes(this_row[columnIndex - 1]));
  2279. }
  2280. else
  2281. {
  2282. return trimBytes(columnIndex, this_row[columnIndex - 1]);
  2283. }
  2284. }
  2285. else
  2286. {
  2287. //Version 7.1 and earlier supports LargeObjects for byte arrays
  2288. // Handle OID's as BLOBS
  2289. if ( fields[columnIndex - 1].getOID() == Oid.OID)
  2290. {
  2291. LargeObjectManager lom = connection.getLargeObjectAPI();
  2292. LargeObject lob = lom.open(getLong(columnIndex));
  2293. byte buf[] = lob.read(lob.size());
  2294. lob.close();
  2295. return trimBytes(columnIndex, buf);
  2296. }
  2297. else
  2298. {
  2299. return trimBytes(columnIndex, this_row[columnIndex - 1]);
  2300. }
  2301. }
  2302. }
  2303.  
  2304. public java.sql.Date getDate(int columnIndex) throws SQLException
  2305. {
  2306. return getDate(columnIndex, null);
  2307. }
  2308.  
  2309. public Time getTime(int columnIndex) throws SQLException
  2310. {
  2311. return getTime(columnIndex, null);
  2312. }
  2313.  
  2314. public Timestamp getTimestamp(int columnIndex) throws SQLException
  2315. {
  2316. return getTimestamp(columnIndex, null);
  2317. }
  2318.  
  2319. public InputStream getAsciiStream(int columnIndex) throws SQLException
  2320. {
  2321. checkResultSet( columnIndex );
  2322. if (wasNullFlag)
  2323. return null;
  2324.  
  2325. if (connection.haveMinimumCompatibleVersion("7.2"))
  2326. {
  2327. //Version 7.2 supports AsciiStream for all the PG text types
  2328. //As the spec/javadoc for this method indicate this is to be used for
  2329. //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
  2330. //long string datatype, but with toast the text datatype is capable of
  2331. //handling very large values. Thus the implementation ends up calling
  2332. //getString() since there is no current way to stream the value from the server
  2333. try
  2334. {
  2335. return new ByteArrayInputStream(getString(columnIndex).getBytes("ASCII"));
  2336. }
  2337. catch (UnsupportedEncodingException l_uee)
  2338. {
  2339. throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}","ASCII"), PSQLState.UNEXPECTED_ERROR, l_uee);
  2340. }
  2341. }
  2342. else
  2343. {
  2344. // In 7.1 Handle as BLOBS so return the LargeObject input stream
  2345. return getBinaryStream(columnIndex);
  2346. }
  2347. }
  2348.  
  2349. public InputStream getUnicodeStream(int columnIndex) throws SQLException
  2350. {
  2351. checkResultSet( columnIndex );
  2352. if (wasNullFlag)
  2353. return null;
  2354.  
  2355. if (connection.haveMinimumCompatibleVersion("7.2"))
  2356. {
  2357. //Version 7.2 supports AsciiStream for all the PG text types
  2358. //As the spec/javadoc for this method indicate this is to be used for
  2359. //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
  2360. //long string datatype, but with toast the text datatype is capable of
  2361. //handling very large values. Thus the implementation ends up calling
  2362. //getString() since there is no current way to stream the value from the server
  2363. try
  2364. {
  2365. return new ByteArrayInputStream(getString(columnIndex).getBytes("UTF-8"));
  2366. }
  2367. catch (UnsupportedEncodingException l_uee)
  2368. {
  2369. throw new PSQLException(GT.tr("The JVM claims not to support the encoding: {0}","UTF-8"), PSQLState.UNEXPECTED_ERROR, l_uee);
  2370. }
  2371. }
  2372. else
  2373. {
  2374. // In 7.1 Handle as BLOBS so return the LargeObject input stream
  2375. return getBinaryStream(columnIndex);
  2376. }
  2377. }
  2378.  
  2379. public InputStream getBinaryStream(int columnIndex) throws SQLException
  2380. {
  2381. checkResultSet( columnIndex );
  2382. if (wasNullFlag)
  2383. return null;
  2384.  
  2385. if (connection.haveMinimumCompatibleVersion("7.2"))
  2386. {
  2387. //Version 7.2 supports BinaryStream for all PG bytea type
  2388. //As the spec/javadoc for this method indicate this is to be used for
  2389. //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
  2390. //long binary datatype, but with toast the bytea datatype is capable of
  2391. //handling very large values. Thus the implementation ends up calling
  2392. //getBytes() since there is no current way to stream the value from the server
  2393. byte b[] = getBytes(columnIndex);
  2394. if (b != null)
  2395. return new ByteArrayInputStream(b);
  2396. }
  2397. else
  2398. {
  2399. // In 7.1 Handle as BLOBS so return the LargeObject input stream
  2400. if ( fields[columnIndex - 1].getOID() == Oid.OID)
  2401. {
  2402. LargeObjectManager lom = connection.getLargeObjectAPI();
  2403. LargeObject lob = lom.open(getLong(columnIndex));
  2404. return lob.getInputStream();
  2405. }
  2406. }
  2407. return null;
  2408. }
  2409.  
  2410. public String getString(String columnName) throws SQLException
  2411. {
  2412. return getString(findColumn(columnName));
  2413. }
  2414.  
  2415. public boolean getBoolean(String columnName) throws SQLException
  2416. {
  2417. return getBoolean(findColumn(columnName));
  2418. }
  2419.  
  2420. public byte getByte(String columnName) throws SQLException
  2421. {
  2422.  
  2423. return getByte(findColumn(columnName));
  2424. }
  2425.  
  2426. public short getShort(String columnName) throws SQLException
  2427. {
  2428. return getShort(findColumn(columnName));
  2429. }
  2430.  
  2431. public int getInt(String columnName) throws SQLException
  2432. {
  2433. return getInt(findColumn(columnName));
  2434. }
  2435.  
  2436. public long getLong(String columnName) throws SQLException
  2437. {
  2438. return getLong(findColumn(columnName));
  2439. }
  2440.  
  2441. public float getFloat(String columnName) throws SQLException
  2442. {
  2443. return getFloat(findColumn(columnName));
  2444. }
  2445.  
  2446. public double getDouble(String columnName) throws SQLException
  2447. {
  2448. return getDouble(findColumn(columnName));
  2449. }
  2450.  
  2451. public BigDecimal getBigDecimal(String columnName, int scale) throws SQLException
  2452. {
  2453. return getBigDecimal(findColumn(columnName), scale);
  2454. }
  2455.  
  2456. public byte[] getBytes(String columnName) throws SQLException
  2457. {
  2458. return getBytes(findColumn(columnName));
  2459. }
  2460.  
  2461. public java.sql.Date getDate(String columnName) throws SQLException
  2462. {
  2463. return getDate(findColumn(columnName), null);
  2464. }
  2465.  
  2466. public Time getTime(String columnName) throws SQLException
  2467. {
  2468. return getTime(findColumn(columnName), null);
  2469. }
  2470.  
  2471. public Timestamp getTimestamp(String columnName) throws SQLException
  2472. {
  2473. return getTimestamp(findColumn(columnName), null);
  2474. }
  2475.  
  2476. public InputStream getAsciiStream(String columnName) throws SQLException
  2477. {
  2478. return getAsciiStream(findColumn(columnName));
  2479. }
  2480.  
  2481. public InputStream getUnicodeStream(String columnName) throws SQLException
  2482. {
  2483. return getUnicodeStream(findColumn(columnName));
  2484. }
  2485.  
  2486. public InputStream getBinaryStream(String columnName) throws SQLException
  2487. {
  2488. return getBinaryStream(findColumn(columnName));
  2489. }
  2490.  
  2491. public SQLWarning getWarnings() throws SQLException
  2492. {
  2493. checkClosed();
  2494. return warnings;
  2495. }
  2496.  
  2497. public void clearWarnings() throws SQLException
  2498. {
  2499. checkClosed();
  2500. warnings = null;
  2501. }
  2502.  
  2503. protected void addWarning(SQLWarning warnings)
  2504. {
  2505. if (this.warnings != null)
  2506. this.warnings.setNextWarning(warnings);
  2507. else
  2508. this.warnings = warnings;
  2509. }
  2510.  
  2511. public String getCursorName() throws SQLException
  2512. {
  2513. checkClosed();
  2514. return null;
  2515. }
  2516.  
  2517. /*
  2518. * Get the value of a column in the current row as a Java object
  2519. *
  2520. * <p>This method will return the value of the given column as a
  2521. * Java object. The type of the Java object will be the default
  2522. * Java Object type corresponding to the column's SQL type, following
  2523. * the mapping specified in the JDBC specification.
  2524. *
  2525. * <p>This method may also be used to read database specific abstract
  2526. * data types.
  2527. *
  2528. * @param columnIndex the first column is 1, the second is 2...
  2529. * @return a Object holding the column value
  2530. * @exception SQLException if a database access error occurs
  2531. */
  2532. public Object getObject(int columnIndex) throws SQLException {
  2533. Field field;
  2534.  
  2535. checkResultSet(columnIndex);
  2536. if (wasNullFlag)
  2537. return null;
  2538.  
  2539. field = fields[columnIndex - 1];
  2540.  
  2541. // some fields can be null, mainly from those returned by MetaData methods
  2542. if (field == null)
  2543. {
  2544. wasNullFlag = true;
  2545. return null;
  2546. }
  2547.  
  2548. Object result = internalGetObject(columnIndex, field);
  2549. if (result != null)
  2550. return result;
  2551.  
  2552. return connection.getObject(getPGType(columnIndex), getString(columnIndex));
  2553. }
  2554.  
  2555. public Object getObject(String columnName) throws SQLException
  2556. {
  2557. return getObject(findColumn(columnName));
  2558. }
  2559.  
  2560. /*
  2561. * Map a ResultSet column name to a ResultSet column index
  2562. */
  2563. public int findColumn(String columnName) throws SQLException
  2564. {
  2565. checkClosed();
  2566.  
  2567. int col = findColumnIndexByLabel(columnName);
  2568. if (col == 0)
  2569. throw new PSQLException (GT.tr("The column name {0} was not found in this ResultSet.", columnName),
  2570. PSQLState.UNDEFINED_COLUMN);
  2571. return col;
  2572. }
  2573.  
  2574. private int findColumnIndexByLabel(String columnLabel)
  2575. {
  2576. if (columnLabelToIndexMap == null)
  2577. {
  2578. columnLabelToIndexMap = new HashMap(fields.length * 2);
  2579. // The JDBC spec says when you have duplicate columns names,
  2580. // the first one should be returned. So load the map in
  2581. // reverse order so the first ones will overwrite later ones.
  2582. for (int i = fields.length - 1; i >= 0; i--)
  2583. {
  2584. columnLabelToIndexMap.put(fields[i].getColumnLabel().toLowerCase(Locale.US), new Integer(i + 1));
  2585. }
  2586. }
  2587.  
  2588. Integer index = (Integer)columnLabelToIndexMap.get(columnLabel);
  2589. if (index != null)
  2590. {
  2591. return index.intValue();
  2592. }
  2593.  
  2594. index = (Integer)columnLabelToIndexMap.get(columnLabel.toLowerCase(Locale.US));
  2595. if (index != null)
  2596. {
  2597. columnLabelToIndexMap.put(columnLabel, index);
  2598. return index.intValue();
  2599. }
  2600.  
  2601. return 0;
  2602. }
  2603.  
  2604. // XXX Code copied from findColumnIndexByLabel().
  2605. // Not sure about whether or not this should also be case insensitive.
  2606. private int findColumnIndexByName(String columnName) throws SQLException
  2607. {
  2608. if (columnNameToIndexMap == null)
  2609. {
  2610. columnNameToIndexMap = new HashMap(fields.length * 2);
  2611. // The JDBC spec says when you have duplicate columns names,
  2612. // the first one should be returned. So load the map in
  2613. // reverse order so the first ones will overwrite later ones.
  2614. for (int i = fields.length - 1; i >= 0; i--)
  2615. {
  2616. columnNameToIndexMap.put(fields[i].getColumnName(connection).toLowerCase(Locale.US), new Integer(i + 1));
  2617. }
  2618. }
  2619.  
  2620. Integer index = (Integer)columnNameToIndexMap.get(columnName);
  2621. if (index != null)
  2622. {
  2623. return index.intValue();
  2624. }
  2625.  
  2626. index = (Integer)columnNameToIndexMap.get(columnName.toLowerCase(Locale.US));
  2627. if (index != null)
  2628. {
  2629. columnNameToIndexMap.put(columnName, index);
  2630. return index.intValue();
  2631. }
  2632.  
  2633. return 0;
  2634. }
  2635.  
  2636. /*
  2637. * returns the OID of a field.<p>
  2638. * It is used internally by the driver.
  2639. */
  2640. public int getColumnOID(int field)
  2641. {
  2642. return fields[field -1].getOID();
  2643. }
  2644.  
  2645. /*
  2646. * This is used to fix get*() methods on Money fields. It should only be
  2647. * used by those methods!
  2648. *
  2649. * It converts ($##.##) to -##.## and $##.## to ##.##
  2650. */
  2651. public String getFixedString(int col) throws SQLException
  2652. {
  2653. String s = getString(col);
  2654. if (s == null)
  2655. return null;
  2656.  
  2657. // if we don't have at least 2 characters it can't be money.
  2658. if (s.length() < 2)
  2659. return s;
  2660.  
  2661. // Handle Money
  2662. char ch = s.charAt(0);
  2663.  
  2664. // optimise for non-money type: return immediately with one check
  2665. // if the first char cannot be '(', '$' or '-'
  2666. if (ch > '-') {
  2667. return s;
  2668. }
  2669.  
  2670. if (ch == '(')
  2671. {
  2672. s = "-" + PGtokenizer.removePara(s).substring(1);
  2673. }
  2674. else if (ch == '$')
  2675. {
  2676. s = s.substring(1);
  2677. }
  2678. else if (ch == '-' && s.charAt(1) == '$')
  2679. {
  2680. s = "-" + s.substring(2);
  2681. }
  2682.  
  2683. return s;
  2684. }
  2685.  
  2686. protected String getPGType( int column ) throws SQLException
  2687. {
  2688. return connection.getTypeInfo().getPGType(fields[column - 1].getOID());
  2689. }
  2690.  
  2691. protected int getSQLType( int column ) throws SQLException
  2692. {
  2693. return connection.getTypeInfo().getSQLType(fields[column - 1].getOID());
  2694. }
  2695.  
  2696. private void checkUpdateable() throws SQLException
  2697. {
  2698. checkClosed();
  2699.  
  2700. if (!isUpdateable())
  2701. throw new PSQLException(GT.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."),
  2702. PSQLState.INVALID_CURSOR_STATE);
  2703.  
  2704. if (updateValues == null)
  2705. {
  2706. // allow every column to be updated without a rehash.
  2707. updateValues = new HashMap((int)(fields.length / 0.75), 0.75f);
  2708. }
  2709. }
  2710.  
  2711. protected void checkClosed() throws SQLException {
  2712. if (rows == null)
  2713. throw new PSQLException(GT.tr("This ResultSet is closed."), PSQLState.OBJECT_NOT_IN_STATE);
  2714. }
  2715.  
  2716. protected void checkColumnIndex(int column) throws SQLException
  2717. {
  2718. if ( column < 1 || column > fields.length )
  2719. throw new PSQLException(GT.tr("The column index is out of range: {0}, number of columns: {1}.", new Object[]{new Integer(column), new Integer(fields.length)}), PSQLState.INVALID_PARAMETER_VALUE );
  2720. }
  2721.  
  2722. /**
  2723. * Checks that the result set is not closed, it's positioned on a
  2724. * valid row and that the given column number is valid. Also
  2725. * updates the {@link #wasNullFlag} to correct value.
  2726. *
  2727. * @param column The column number to check. Range starts from 1.
  2728. * @throws SQLException If state or column is invalid.
  2729. */
  2730. protected void checkResultSet( int column ) throws SQLException
  2731. {
  2732. checkClosed();
  2733. if ( this_row == null )
  2734. throw new PSQLException(GT.tr("ResultSet not positioned properly, perhaps you need to call next."),
  2735. PSQLState.INVALID_CURSOR_STATE);
  2736. checkColumnIndex(column);
  2737. wasNullFlag = (this_row[column - 1] == null);
  2738. }
  2739.  
  2740. //----------------- Formatting Methods -------------------
  2741.  
  2742. public static boolean toBoolean(String s)
  2743. {
  2744. if (s != null)
  2745. {
  2746. s = s.trim();
  2747.  
  2748. if (s.equalsIgnoreCase("t") || s.equalsIgnoreCase("true") || s.equals("1"))
  2749. return true;
  2750.  
  2751. if (s.equalsIgnoreCase("f") || s.equalsIgnoreCase("false") || s.equals("0"))
  2752. return false;
  2753.  
  2754. try
  2755. {
  2756. if (Double.valueOf(s).doubleValue() == 1)
  2757. return true;
  2758. }
  2759. catch (NumberFormatException e)
  2760. {
  2761. }
  2762. }
  2763. return false; // SQL NULL
  2764. }
  2765.  
  2766. private static final BigInteger INTMAX = new BigInteger(Integer.toString(Integer.MAX_VALUE));
  2767. private static final BigInteger INTMIN = new BigInteger(Integer.toString(Integer.MIN_VALUE));
  2768.  
  2769. public static int toInt(String s) throws SQLException
  2770. {
  2771. if (s != null)
  2772. {
  2773. try
  2774. {
  2775. s = s.trim();
  2776. return Integer.parseInt(s);
  2777. }
  2778. catch (NumberFormatException e)
  2779. {
  2780. try
  2781. {
  2782. BigDecimal n = new BigDecimal(s);
  2783. BigInteger i = n.toBigInteger();
  2784.  
  2785. int gt = i.compareTo(INTMAX);
  2786. int lt = i.compareTo(INTMIN);
  2787.  
  2788. if (gt > 0 || lt < 0)
  2789. {
  2790. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"int",s}),
  2791. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2792. }
  2793. return i.intValue();
  2794.  
  2795. }
  2796. catch ( NumberFormatException ne )
  2797. {
  2798. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"int",s}),
  2799. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2800. }
  2801. }
  2802. }
  2803. return 0; // SQL NULL
  2804. }
  2805. private final static BigInteger LONGMAX = new BigInteger(Long.toString(Long.MAX_VALUE));
  2806. private final static BigInteger LONGMIN = new BigInteger(Long.toString(Long.MIN_VALUE));
  2807.  
  2808. public static long toLong(String s) throws SQLException
  2809. {
  2810. if (s != null)
  2811. {
  2812. try
  2813. {
  2814. s = s.trim();
  2815. return Long.parseLong(s);
  2816. }
  2817. catch (NumberFormatException e)
  2818. {
  2819. try
  2820. {
  2821. BigDecimal n = new BigDecimal(s);
  2822. BigInteger i = n.toBigInteger();
  2823. int gt = i.compareTo(LONGMAX);
  2824. int lt = i.compareTo(LONGMIN);
  2825.  
  2826. if ( gt > 0 || lt < 0 )
  2827. {
  2828. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"long",s}),
  2829. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2830. }
  2831. return i.longValue();
  2832. }
  2833. catch ( NumberFormatException ne )
  2834. {
  2835. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"long",s}),
  2836. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2837. }
  2838. }
  2839. }
  2840. return 0; // SQL NULL
  2841. }
  2842.  
  2843. public static BigDecimal toBigDecimal(String s, int scale) throws SQLException
  2844. {
  2845. BigDecimal val;
  2846. if (s != null)
  2847. {
  2848. try
  2849. {
  2850. s = s.trim();
  2851. val = new BigDecimal(s);
  2852. }
  2853. catch (NumberFormatException e)
  2854. {
  2855. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"BigDecimal",s}),
  2856. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2857. }
  2858. if (scale == -1)
  2859. return val;
  2860. try
  2861. {
  2862. return val.setScale(scale);
  2863. }
  2864. catch (ArithmeticException e)
  2865. {
  2866. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"BigDecimal",s}),
  2867. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2868. }
  2869. }
  2870. return null; // SQL NULL
  2871. }
  2872.  
  2873. public static float toFloat(String s) throws SQLException
  2874. {
  2875. if (s != null)
  2876. {
  2877. try
  2878. {
  2879. s = s.trim();
  2880. return Float.parseFloat(s);
  2881. }
  2882. catch (NumberFormatException e)
  2883. {
  2884. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"float",s}),
  2885. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2886. }
  2887. }
  2888. return 0; // SQL NULL
  2889. }
  2890.  
  2891. public static double toDouble(String s) throws SQLException
  2892. {
  2893. if (s != null)
  2894. {
  2895. try
  2896. {
  2897. s = s.trim();
  2898. return Double.parseDouble(s);
  2899. }
  2900. catch (NumberFormatException e)
  2901. {
  2902. throw new PSQLException(GT.tr("Bad value for type {0} : {1}", new Object[]{"double",s}),
  2903. PSQLState.NUMERIC_VALUE_OUT_OF_RANGE);
  2904. }
  2905. }
  2906. return 0; // SQL NULL
  2907. }
  2908.  
  2909. private void initRowBuffer()
  2910. {
  2911. this_row = (byte[][]) rows.elementAt(current_row);
  2912. // We only need a copy of the current row if we're going to
  2913. // modify it via an updatable resultset.
  2914. if (resultsetconcurrency == ResultSet.CONCUR_UPDATABLE) {
  2915. rowBuffer = new byte[this_row.length][];
  2916. System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length);
  2917. } else {
  2918. rowBuffer = null;
  2919. }
  2920. }
  2921.  
  2922. private boolean isColumnTrimmable(int columnIndex) throws SQLException
  2923. {
  2924. switch (getSQLType(columnIndex))
  2925. {
  2926. case Types.CHAR:
  2927. case Types.VARCHAR:
  2928. case Types.LONGVARCHAR:
  2929. case Types.BINARY:
  2930. case Types.VARBINARY:
  2931. case Types.LONGVARBINARY:
  2932. return true;
  2933. }
  2934. return false;
  2935. }
  2936.  
  2937. private byte[] trimBytes(int p_columnIndex, byte[] p_bytes) throws SQLException
  2938. {
  2939. //we need to trim if maxsize is set and the length is greater than maxsize and the
  2940. //type of this column is a candidate for trimming
  2941. if (maxFieldSize > 0 && p_bytes.length > maxFieldSize && isColumnTrimmable(p_columnIndex))
  2942. {
  2943. byte[] l_bytes = new byte[maxFieldSize];
  2944. System.arraycopy (p_bytes, 0, l_bytes, 0, maxFieldSize);
  2945. return l_bytes;
  2946. }
  2947. else
  2948. {
  2949. return p_bytes;
  2950. }
  2951. }
  2952.  
  2953. private String trimString(int p_columnIndex, String p_string) throws SQLException
  2954. {
  2955. //we need to trim if maxsize is set and the length is greater than maxsize and the
  2956. //type of this column is a candidate for trimming
  2957. if (maxFieldSize > 0 && p_string.length() > maxFieldSize && isColumnTrimmable(p_columnIndex))
  2958. {
  2959. return p_string.substring(0, maxFieldSize);
  2960. }
  2961. else
  2962. {
  2963. return p_string;
  2964. }
  2965. }
  2966.  
  2967. protected void updateValue(int columnIndex, Object value) throws SQLException {
  2968. checkUpdateable();
  2969.  
  2970. if (!onInsertRow && (isBeforeFirst() || isAfterLast() || rows.size() == 0))
  2971. {
  2972. throw new PSQLException(GT.tr("Cannot update the ResultSet because it is either before the start or after the end of the results."),
  2973. PSQLState.INVALID_CURSOR_STATE);
  2974. }
  2975.  
  2976. checkColumnIndex(columnIndex);
  2977.  
  2978. doingUpdates = !onInsertRow;
  2979. if (value == null)
  2980. updateNull(columnIndex);
  2981. else
  2982. updateValues.put(fields[columnIndex - 1].getColumnName(connection), value);
  2983. }
  2984.  
  2985. /**
  2986. * Newer JVMs will return a java.util.UUID object, but it isn't
  2987. * available in older versions.
  2988. */
  2989. protected Object getUUID(String data) throws SQLException
  2990. {
  2991. return data;
  2992. }
  2993.  
  2994. private class PrimaryKey
  2995. {
  2996. int index; // where in the result set is this primaryKey
  2997. String name; // what is the columnName of this primary Key
  2998.  
  2999. PrimaryKey( int index, String name)
  3000. {
  3001. this.index = index;
  3002. this.name = name;
  3003. }
  3004. Object getValue() throws SQLException
  3005. {
  3006. return getObject(index);
  3007. }
  3008. };
  3009.  
  3010. //
  3011. // We need to specify the type of NULL when updating a column to NULL, so
  3012. // NullObject is a simple extension of PGobject that always returns null
  3013. // values but retains column type info.
  3014. //
  3015.  
  3016. static class NullObject extends PGobject {
  3017. NullObject(String type) {
  3018. setType(type);
  3019. }
  3020.  
  3021. public String getValue() {
  3022. return null;
  3023. }
  3024. };
  3025. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement