private void initFromDatabase() throws SQLException, BlockStoreException { Statement s = conn.get().createStatement(); ResultSet rs; rs = s.executeQuery("SELECT value FROM settings WHERE name = '" + CHAIN_HEAD_SETTING + "'"); if (!rs.next()) { throw new BlockStoreException("corrupt Postgres block store - no chain head pointer"); } Sha256Hash hash = new Sha256Hash(rs.getBytes(1)); rs.close(); this.chainHeadBlock = get(hash); this.chainHeadHash = hash; if (this.chainHeadBlock == null) { throw new BlockStoreException("corrupt Postgres block store - head block not found"); } rs = s.executeQuery( "SELECT value FROM settings WHERE name = '" + VERIFIED_CHAIN_HEAD_SETTING + "'"); if (!rs.next()) { throw new BlockStoreException( "corrupt Postgres block store - no verified chain head pointer"); } hash = new Sha256Hash(rs.getBytes(1)); rs.close(); s.close(); this.verifiedChainHeadBlock = get(hash); this.verifiedChainHeadHash = hash; if (this.verifiedChainHeadBlock == null) { throw new BlockStoreException("corrupt Postgres block store - verified head block not found"); } }
public StoredTransactionOutput getTransactionOutput(Sha256Hash hash, long index) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "SELECT height, value, scriptBytes FROM openOutputs " + "WHERE hash = ? AND index = ?"); s.setBytes(1, hash.getBytes()); // index is actually an unsigned int s.setInt(2, (int) index); ResultSet results = s.executeQuery(); if (!results.next()) { return null; } // Parse it. int height = results.getInt(1); BigInteger value = new BigInteger(results.getBytes(2)); // Tell the StoredTransactionOutput that we are a coinbase, as that is encoded in height StoredTransactionOutput txout = new StoredTransactionOutput(hash, index, value, height, true, results.getBytes(3)); return txout; } catch (SQLException ex) { throw new BlockStoreException(ex); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
private void putUpdateStoredBlock(StoredBlock storedBlock, boolean wasUndoable) throws SQLException { try { PreparedStatement s = conn.get() .prepareStatement( "INSERT INTO headers(hash, chainWork, height, header, wasUndoable)" + " VALUES(?, ?, ?, ?, ?)"); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(storedBlock.getHeader().getHash().getBytes(), 3, hashBytes, 0, 28); s.setBytes(1, hashBytes); s.setBytes(2, storedBlock.getChainWork().toByteArray()); s.setInt(3, storedBlock.getHeight()); s.setBytes(4, storedBlock.getHeader().unsafeRimbitSerialize()); s.setBoolean(5, wasUndoable); s.executeUpdate(); s.close(); } catch (SQLException e) { // It is possible we try to add a duplicate StoredBlock if we upgraded // In that case, we just update the entry to mark it wasUndoable if (!(e.getSQLState().equals(POSTGRES_DUPLICATE_KEY_ERROR_CODE)) || !wasUndoable) throw e; PreparedStatement s = conn.get().prepareStatement("UPDATE headers SET wasUndoable=? WHERE hash=?"); s.setBoolean(1, true); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(storedBlock.getHeader().getHash().getBytes(), 3, hashBytes, 0, 28); s.setBytes(2, hashBytes); s.executeUpdate(); s.close(); } }
public void beginDatabaseBatchWrite() throws BlockStoreException { maybeConnect(); if (log.isDebugEnabled()) log.debug("Starting database batch write with connection: " + conn.get().toString()); try { conn.get().setAutoCommit(false); } catch (SQLException e) { throw new BlockStoreException(e); } }
/** 关闭连接 */ public static final void closeConnection() { Connection conn = conns.get(); try { if (conn != null && !conn.isClosed()) { conn.setAutoCommit(true); conn.close(); connectionContext.remove(Thread.currentThread().getId()); } } catch (SQLException e) { log.error("Unabled to close connection!!! ", e); } conns.set(null); }
private void createTables() throws SQLException, BlockStoreException { Statement s = conn.get().createStatement(); if (log.isDebugEnabled()) log.debug("PostgresFullPrunedBlockStore : CREATE headers table"); s.executeUpdate(CREATE_HEADERS_TABLE); if (log.isDebugEnabled()) log.debug("PostgresFullPrunedBlockStore : CREATE settings table"); s.executeUpdate(CREATE_SETTINGS_TABLE); if (log.isDebugEnabled()) log.debug("PostgresFullPrunedBlockStore : CREATE undoable block table"); s.executeUpdate(CREATE_UNDOABLE_TABLE); if (log.isDebugEnabled()) log.debug("PostgresFullPrunedBlockStore : CREATE undoable block index"); s.executeUpdate(CREATE_UNDOABLE_TABLE_INDEX); if (log.isDebugEnabled()) log.debug("PostgresFullPrunedBlockStore : CREATE open output table"); s.executeUpdate(CREATE_OPEN_OUTPUT_TABLE); // Create indexes.. s.executeUpdate(CREATE_HEADERS_HASH_INDEX); s.executeUpdate(CREATE_OUTPUT_ADDRESS_TYPE_INDEX); s.executeUpdate(CREATE_OUTPUTS_ADDRESS_INDEX); s.executeUpdate(CREATE_OUTPUTS_HASH_INDEX); s.executeUpdate(CREATE_OUTPUTS_HASH_INDEX_INDEX); s.executeUpdate(CREATE_UNDOABLE_HASH_INDEX); s.executeUpdate("INSERT INTO settings(name, value) VALUES('" + CHAIN_HEAD_SETTING + "', NULL)"); s.executeUpdate( "INSERT INTO settings(name, value) VALUES('" + VERIFIED_CHAIN_HEAD_SETTING + "', NULL)"); s.executeUpdate("INSERT INTO settings(name, value) VALUES('" + VERSION_SETTING + "', '03')"); s.close(); createNewStore(params); }
/** * Calculate the balance for a coinbase, to-address, or p2sh address. * * @param address The address to calculate the balance of * @return The balance of the address supplied. If the address has not been seen, or there are no * outputs open for this address, the return value is 0 * @throws BlockStoreException */ public BigInteger calculateBalanceForAddress(Address address) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "select sum(('x'||lpad(substr(value::text, 3, 50),16,'0'))::bit(64)::bigint) " + "from openoutputs where toaddress = ?"); s.setString(1, address.toString()); ResultSet rs = s.executeQuery(); if (rs.next()) { return BigInteger.valueOf(rs.getLong(1)); } else { throw new BlockStoreException("Failed to execute balance lookup"); } } catch (SQLException ex) { throw new BlockStoreException(ex); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Could not close statement"); } } }
private void pagination(Invocation invocation, StatementHandler target) throws SQLException { final MetaObject metaStatementHandler = getMetaObject(target); final BoundSql boundSql = target.getBoundSql(); Page<?> page = PAGE_THREAD_LOCAL.get(); if (page == null) { page = findPageParameter(boundSql.getParameterObject()); } // 如果传入的参数中有分页对象且sql语句中有select,才做分页处理 String sql = boundSql.getSql().toLowerCase(); if (sql.startsWith("select") && page != null) { // 采用物理分页后,就不需要mybatis的内存分页了,所以重置下面的两个参数 metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET); metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT); // 设置分页对象里的总记录数和总页数 Connection connection = (Connection) invocation.getArgs()[0]; MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement"); if (page.isCountTotal()) { int recordsTotal = getTotalCount(sql, connection, mappedStatement, boundSql); page.setTotalNum(recordsTotal); } // 最后重写sql String pageSql = buildPageSql(sql, page); metaStatementHandler.setValue("delegate.boundSql.sql", pageSql); } }
public void abortDatabaseBatchWrite() throws BlockStoreException { maybeConnect(); if (log.isDebugEnabled()) log.debug("Rollback database batch write with connection: " + conn.get().toString()); try { if (!conn.get().getAutoCommit()) { conn.get().rollback(); conn.get().setAutoCommit(true); } else { log.warn("Warning: Rollback attempt without transaction"); } } catch (SQLException e) { throw new BlockStoreException(e); } }
private synchronized void maybeConnect() throws BlockStoreException { try { if (conn.get() != null) return; Properties props = new Properties(); props.setProperty("user", this.username); props.setProperty("password", this.password); conn.set(DriverManager.getConnection(connectionURL, props)); Connection connection = conn.get(); allConnections.add(conn.get()); log.info("Made a new connection to database " + connectionURL); } catch (SQLException ex) { throw new BlockStoreException(ex); } }
public static final Connection getConnection() throws SQLException { Connection conn = conns.get(); if (conn == null || conn.isClosed()) { conn = _getConnection(); if (conn == null) throw new SQLException("Unabled to get connection."); conns.set(conn); // RequestContext ctx = RequestContext.get(); // connectionContext.put( // Thread.currentThread().getId(), // new ConnectionContext(new Exception(), (ctx != null) ? ctx // .ip() : null, (ctx != null) ? ctx.uri() : null, // (ctx != null) ? ctx.request().getParameterMap() // : null)); } return (show_sql && !Proxy.isProxyClass(conn.getClass())) ? new _DebugConnection(conn).getConnection() : conn; }
private boolean tableExists(String table) throws SQLException { Statement s = conn.get().createStatement(); try { ResultSet results = s.executeQuery("SELECT * FROM " + table + " WHERE 1 = 2"); results.close(); return true; } catch (SQLException ex) { return false; } finally { s.close(); } }
private void removeUndoableBlocksWhereHeightIsLessThan(int height) throws BlockStoreException { try { PreparedStatement s = conn.get().prepareStatement("DELETE FROM undoableBlocks WHERE height <= ?"); s.setInt(1, height); if (log.isDebugEnabled()) log.debug("Deleting undoable undoable block with height <= " + height); s.executeUpdate(); s.close(); } catch (SQLException ex) { throw new BlockStoreException(ex); } }
@SuppressWarnings({"rawtypes", "unchecked"}) @Override public Object intercept(Invocation invocation) throws Throwable { final String name = invocation.getMethod().getName(); final Object target = invocation.getTarget(); if (target instanceof StatementHandler) { pagination(invocation, (StatementHandler) target); } else if (target instanceof Executor) { autoMap(invocation, name); } else if (target instanceof ResultSetHandler) { Object result = invocation.proceed(); if (result instanceof List) { Page page = PAGE_THREAD_LOCAL.get(); if (page != null) { page.addAll((List) result); PAGE_THREAD_LOCAL.remove(); return page; } } return result; } return invocation.proceed(); }
public void resetStore() throws BlockStoreException { maybeConnect(); try { Statement s = conn.get().createStatement(); s.execute("DROP TABLE settings"); s.execute("DROP TABLE headers"); s.execute("DROP TABLE undoableBlocks"); s.execute("DROP TABLE openOutputs"); s.close(); createTables(); initFromDatabase(); } catch (SQLException ex) { throw new RuntimeException(ex); } }
public StoredBlock get(Sha256Hash hash, boolean wasUndoableOnly) throws BlockStoreException { // Optimize for chain head if (chainHeadHash != null && chainHeadHash.equals(hash)) return chainHeadBlock; if (verifiedChainHeadHash != null && verifiedChainHeadHash.equals(hash)) return verifiedChainHeadBlock; maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "SELECT chainWork, height, header, wasUndoable FROM headers WHERE hash = ?"); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(hash.getBytes(), 3, hashBytes, 0, 28); s.setBytes(1, hashBytes); ResultSet results = s.executeQuery(); if (!results.next()) { return null; } // Parse it. if (wasUndoableOnly && !results.getBoolean(4)) return null; BigInteger chainWork = new BigInteger(results.getBytes(1)); int height = results.getInt(2); Block b = new Block(params, results.getBytes(3)); b.verifyHeader(); StoredBlock stored = new StoredBlock(b, chainWork, height); return stored; } catch (SQLException ex) { throw new BlockStoreException(ex); } catch (ProtocolException e) { // Corrupted database. throw new BlockStoreException(e); } catch (VerificationException e) { // Should not be able to happen unless the database contains bad // blocks. throw new BlockStoreException(e); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
public void setChainHead(StoredBlock chainHead) throws BlockStoreException { Sha256Hash hash = chainHead.getHeader().getHash(); this.chainHeadHash = hash; this.chainHeadBlock = chainHead; maybeConnect(); try { PreparedStatement s = conn.get().prepareStatement("UPDATE settings SET value = ? WHERE name = ?"); s.setString(2, CHAIN_HEAD_SETTING); s.setBytes(1, hash.getBytes()); s.executeUpdate(); s.close(); } catch (SQLException ex) { throw new BlockStoreException(ex); } }
public void setVerifiedChainHead(StoredBlock chainHead) throws BlockStoreException { Sha256Hash hash = chainHead.getHeader().getHash(); this.verifiedChainHeadHash = hash; this.verifiedChainHeadBlock = chainHead; maybeConnect(); try { PreparedStatement s = conn.get().prepareStatement("UPDATE settings SET value = ? WHERE name = ?"); s.setString(2, VERIFIED_CHAIN_HEAD_SETTING); s.setBytes(1, hash.getBytes()); s.executeUpdate(); s.close(); } catch (SQLException ex) { throw new BlockStoreException(ex); } if (this.chainHeadBlock.getHeight() < chainHead.getHeight()) setChainHead(chainHead); removeUndoableBlocksWhereHeightIsLessThan(chainHead.getHeight() - fullStoreDepth); }
/** * 从传递的参数中找Page对象,并返回 * * @param paramObj * @return */ public Page<?> findPageParameter(Object paramObj) { Page<?> page = null; if (paramObj instanceof Page) { page = (Page<?>) paramObj; } else if (paramObj instanceof Map) { Map<?, ?> m = (Map<?, ?>) paramObj; for (Object o : m.values()) { if (o instanceof Page) { page = (Page<?>) o; break; } } } if (page != null) { PAGE_THREAD_LOCAL.set(page); } return page; }
public void removeUnspentTransactionOutput(StoredTransactionOutput out) throws BlockStoreException { maybeConnect(); // TODO: This should only need one query (maybe a stored procedure) if (getTransactionOutput(out.getHash(), out.getIndex()) == null) throw new BlockStoreException( "Tried to remove a StoredTransactionOutput from PostgresFullPrunedBlockStore that it didn't have!"); try { PreparedStatement s = conn.get().prepareStatement("DELETE FROM openOutputs WHERE hash = ? AND index = ?"); s.setBytes(1, out.getHash().getBytes()); // index is actually an unsigned int s.setInt(2, (int) out.getIndex()); s.executeUpdate(); s.close(); } catch (SQLException e) { throw new BlockStoreException(e); } }
/** * Convert a timestamp from a different Timezone. * * @param value the timestamp value. * @param target the Calendar containing the TimeZone. * @return The new timestamp value as a <code>long</code>. */ public static long timeFromZone(java.util.Date value, Calendar target) { java.util.Date tmp = target.getTime(); try { GregorianCalendar cal = (GregorianCalendar) calendar.get(); target.setTime(value); if (!Driver.JDBC3 && value instanceof Timestamp) { // Not Running under 1.4 so need to add milliseconds target.set(Calendar.MILLISECOND, ((Timestamp) value).getNanos() / 1000000); } cal.set(Calendar.HOUR_OF_DAY, target.get(Calendar.HOUR_OF_DAY)); cal.set(Calendar.MINUTE, target.get(Calendar.MINUTE)); cal.set(Calendar.SECOND, target.get(Calendar.SECOND)); cal.set(Calendar.MILLISECOND, target.get(Calendar.MILLISECOND)); cal.set(Calendar.YEAR, target.get(Calendar.YEAR)); cal.set(Calendar.MONTH, target.get(Calendar.MONTH)); cal.set(Calendar.DAY_OF_MONTH, target.get(Calendar.DAY_OF_MONTH)); return cal.getTime().getTime(); } finally { target.setTime(tmp); } }
public boolean hasUnspentOutputs(Sha256Hash hash, int numOutputs) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get().prepareStatement("SELECT COUNT(*) FROM openOutputs WHERE hash = ?"); s.setBytes(1, hash.getBytes()); ResultSet results = s.executeQuery(); if (!results.next()) { throw new BlockStoreException("Got no results from a COUNT(*) query"); } int count = results.getInt(1); return count != 0; } catch (SQLException ex) { throw new BlockStoreException(ex); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
/** * Dumps information about the size of actual data in the database to standard output The only * truly useless data counted is printed in the form "N in id indexes" This does not take database * indexes into account */ public void dumpSizes() throws SQLException, BlockStoreException { maybeConnect(); Statement s = conn.get().createStatement(); long size = 0; long totalSize = 0; int count = 0; ResultSet rs = s.executeQuery("SELECT name, value FROM settings"); while (rs.next()) { size += rs.getString(1).length(); size += rs.getBytes(2).length; count++; } rs.close(); System.out.printf( "Settings size: %d, count: %d, average size: %f%n", size, count, (double) size / count); totalSize += size; size = 0; count = 0; rs = s.executeQuery("SELECT chainWork, header FROM headers"); while (rs.next()) { size += 28; // hash size += rs.getBytes(1).length; size += 4; // height size += rs.getBytes(2).length; count++; } rs.close(); System.out.printf( "Headers size: %d, count: %d, average size: %f%n", size, count, (double) size / count); totalSize += size; size = 0; count = 0; rs = s.executeQuery("SELECT txOutChanges, transactions FROM undoableBlocks"); while (rs.next()) { size += 28; // hash size += 4; // height byte[] txOutChanges = rs.getBytes(1); byte[] transactions = rs.getBytes(2); if (txOutChanges == null) size += transactions.length; else size += txOutChanges.length; // size += the space to represent NULL count++; } rs.close(); System.out.printf( "Undoable Blocks size: %d, count: %d, average size: %f%n", size, count, (double) size / count); totalSize += size; size = 0; count = 0; long scriptSize = 0; rs = s.executeQuery("SELECT value, scriptBytes FROM openOutputs"); while (rs.next()) { size += 32; // hash size += 4; // index size += 4; // height size += rs.getBytes(1).length; size += rs.getBytes(2).length; scriptSize += rs.getBytes(2).length; count++; } rs.close(); System.out.printf( "Open Outputs size: %d, count: %d, average size: %f, average script size: %f (%d in id indexes)%n", size, count, (double) size / count, (double) scriptSize / count, count * 8); totalSize += size; System.out.println("Total Size: " + totalSize); s.close(); }
public void put(StoredBlock storedBlock, StoredUndoableBlock undoableBlock) throws BlockStoreException { maybeConnect(); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(storedBlock.getHeader().getHash().getBytes(), 3, hashBytes, 0, 28); int height = storedBlock.getHeight(); byte[] transactions = null; byte[] txOutChanges = null; try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); if (undoableBlock.getTxOutChanges() != null) { undoableBlock.getTxOutChanges().serializeToStream(bos); txOutChanges = bos.toByteArray(); } else { int numTxn = undoableBlock.getTransactions().size(); bos.write((int) (0xFF & (numTxn >> 0))); bos.write((int) (0xFF & (numTxn >> 8))); bos.write((int) (0xFF & (numTxn >> 16))); bos.write((int) (0xFF & (numTxn >> 24))); for (Transaction tx : undoableBlock.getTransactions()) tx.rimbitSerialize(bos); transactions = bos.toByteArray(); } bos.close(); } catch (IOException e) { throw new BlockStoreException(e); } try { if (log.isDebugEnabled()) log.debug("Looking for undoable block with hash: " + Utils.bytesToHexString(hashBytes)); PreparedStatement findS = conn.get().prepareStatement("select 1 from undoableBlocks where hash = ?"); findS.setBytes(1, hashBytes); ResultSet rs = findS.executeQuery(); if (rs.next()) { // We already have this output, update it. findS.close(); // Postgres insert-or-updates are very complex (and finnicky). This level of transaction // isolation // seems to work for rimbitj PreparedStatement s = conn.get() .prepareStatement( "UPDATE undoableBlocks SET txOutChanges=?, transactions=?" + " WHERE hash = ?"); s.setBytes(3, hashBytes); if (log.isDebugEnabled()) log.debug("Updating undoable block with hash: " + Utils.bytesToHexString(hashBytes)); if (transactions == null) { s.setBytes(1, txOutChanges); s.setNull(2, Types.BINARY); } else { s.setNull(1, Types.BINARY); s.setBytes(2, transactions); } s.executeUpdate(); s.close(); return; } PreparedStatement s = conn.get() .prepareStatement( "INSERT INTO undoableBlocks(hash, height, txOutChanges, transactions)" + " VALUES(?, ?, ?, ?)"); s.setBytes(1, hashBytes); s.setInt(2, height); if (log.isDebugEnabled()) log.debug( "Inserting undoable block with hash: " + Utils.bytesToHexString(hashBytes) + " at height " + height); if (transactions == null) { s.setBytes(3, txOutChanges); s.setNull(4, Types.BINARY); } else { s.setNull(3, Types.BINARY); s.setBytes(4, transactions); } s.executeUpdate(); s.close(); try { putUpdateStoredBlock(storedBlock, true); } catch (SQLException e) { throw new BlockStoreException(e); } } catch (SQLException e) { if (!e.getSQLState().equals(POSTGRES_DUPLICATE_KEY_ERROR_CODE)) throw new BlockStoreException(e); } }
public StoredUndoableBlock getUndoBlock(Sha256Hash hash) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "SELECT txOutChanges, transactions FROM undoableBlocks WHERE hash = ?"); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(hash.getBytes(), 3, hashBytes, 0, 28); s.setBytes(1, hashBytes); ResultSet results = s.executeQuery(); if (!results.next()) { return null; } // Parse it. byte[] txOutChanges = results.getBytes(1); byte[] transactions = results.getBytes(2); StoredUndoableBlock block; if (txOutChanges == null) { int offset = 0; int numTxn = ((transactions[offset++] & 0xFF) << 0) | ((transactions[offset++] & 0xFF) << 8) | ((transactions[offset++] & 0xFF) << 16) | ((transactions[offset++] & 0xFF) << 24); List<Transaction> transactionList = new LinkedList<Transaction>(); for (int i = 0; i < numTxn; i++) { Transaction tx = new Transaction(params, transactions, offset); transactionList.add(tx); offset += tx.getMessageSize(); } block = new StoredUndoableBlock(hash, transactionList); } else { TransactionOutputChanges outChangesObject = new TransactionOutputChanges(new ByteArrayInputStream(txOutChanges)); block = new StoredUndoableBlock(hash, outChangesObject); } return block; } catch (SQLException ex) { throw new BlockStoreException(ex); } catch (NullPointerException e) { // Corrupted database. throw new BlockStoreException(e); } catch (ClassCastException e) { // Corrupted database. throw new BlockStoreException(e); } catch (ProtocolException e) { // Corrupted database. throw new BlockStoreException(e); } catch (IOException e) { // Corrupted database. throw new BlockStoreException(e); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
/** * Convert an existing data object to the specified JDBC type. * * @param callerReference an object reference to the caller of this method; must be a <code> * Connection</code>, <code>Statement</code> or <code>ResultSet</code> * @param x the data object to convert * @param jdbcType the required type constant from <code>java.sql.Types</code> * @return the converted data object * @throws SQLException if the conversion is not supported or fails */ static Object convert(Object callerReference, Object x, int jdbcType, String charSet) throws SQLException { // handle null value if (x == null) { switch (jdbcType) { case java.sql.Types.BIT: case JtdsStatement.BOOLEAN: return Boolean.FALSE; case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: return INTEGER_ZERO; case java.sql.Types.BIGINT: return LONG_ZERO; case java.sql.Types.REAL: return FLOAT_ZERO; case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: return DOUBLE_ZERO; default: return null; } } try { switch (jdbcType) { case java.sql.Types.TINYINT: if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO; } else if (x instanceof Byte) { return new Integer(((Byte) x).byteValue() & 0xFF); } else { long val; if (x instanceof Number) { val = ((Number) x).longValue(); } else if (x instanceof String) { val = new Long(((String) x).trim()).longValue(); } else { break; } if (val < Byte.MIN_VALUE || val > Byte.MAX_VALUE) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Integer(new Long(val).intValue()); } } case java.sql.Types.SMALLINT: if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO; } else if (x instanceof Short) { return new Integer(((Short) x).shortValue()); } else if (x instanceof Byte) { return new Integer(((Byte) x).byteValue() & 0xFF); } else { long val; if (x instanceof Number) { val = ((Number) x).longValue(); } else if (x instanceof String) { val = new Long(((String) x).trim()).longValue(); } else { break; } if (val < Short.MIN_VALUE || val > Short.MAX_VALUE) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Integer(new Long(val).intValue()); } } case java.sql.Types.INTEGER: if (x instanceof Integer) { return x; } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? INTEGER_ONE : INTEGER_ZERO; } else if (x instanceof Short) { return new Integer(((Short) x).shortValue()); } else if (x instanceof Byte) { return new Integer(((Byte) x).byteValue() & 0xFF); } else { long val; if (x instanceof Number) { val = ((Number) x).longValue(); } else if (x instanceof String) { val = new Long(((String) x).trim()).longValue(); } else { break; } if (val < Integer.MIN_VALUE || val > Integer.MAX_VALUE) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Integer(new Long(val).intValue()); } } case java.sql.Types.BIGINT: if (x instanceof BigDecimal) { BigDecimal val = (BigDecimal) x; if (val.compareTo(MIN_VALUE_LONG_BD) < 0 || val.compareTo(MAX_VALUE_LONG_BD) > 0) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Long(val.longValue()); } } else if (x instanceof Long) { return x; } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? LONG_ONE : LONG_ZERO; } else if (x instanceof Byte) { return new Long(((Byte) x).byteValue() & 0xFF); } else if (x instanceof BigInteger) { BigInteger val = (BigInteger) x; if (val.compareTo(MIN_VALUE_LONG_BI) < 0 || val.compareTo(MAX_VALUE_LONG_BI) > 0) { throw new SQLException( Messages.get("error.convert.numericoverflow", x, getJdbcTypeName(jdbcType)), "22003"); } else { return new Long(val.longValue()); } } else if (x instanceof Number) { return new Long(((Number) x).longValue()); } else if (x instanceof String) { return new Long(((String) x).trim()); } else { break; } case java.sql.Types.REAL: if (x instanceof Float) { return x; } else if (x instanceof Byte) { return new Float(((Byte) x).byteValue() & 0xFF); } else if (x instanceof Number) { return new Float(((Number) x).floatValue()); } else if (x instanceof String) { return new Float(((String) x).trim()); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? FLOAT_ONE : FLOAT_ZERO; } break; case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: if (x instanceof Double) { return x; } else if (x instanceof Byte) { return new Double(((Byte) x).byteValue() & 0xFF); } else if (x instanceof Number) { return new Double(((Number) x).doubleValue()); } else if (x instanceof String) { return new Double(((String) x).trim()); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? DOUBLE_ONE : DOUBLE_ZERO; } break; case java.sql.Types.NUMERIC: case java.sql.Types.DECIMAL: if (x instanceof BigDecimal) { return x; } else if (x instanceof Number) { return new BigDecimal(x.toString()); } else if (x instanceof String) { return new BigDecimal((String) x); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? BIG_DECIMAL_ONE : BIG_DECIMAL_ZERO; } break; case java.sql.Types.VARCHAR: case java.sql.Types.CHAR: if (x instanceof String) { return x; } else if (x instanceof Number) { return x.toString(); } else if (x instanceof Boolean) { return ((Boolean) x).booleanValue() ? "1" : "0"; } else if (x instanceof Clob) { Clob clob = (Clob) x; long length = clob.length(); if (length > Integer.MAX_VALUE) { throw new SQLException(Messages.get("error.normalize.lobtoobig"), "22000"); } return clob.getSubString(1, (int) length); } else if (x instanceof Blob) { Blob blob = (Blob) x; long length = blob.length(); if (length > Integer.MAX_VALUE) { throw new SQLException(Messages.get("error.normalize.lobtoobig"), "22000"); } x = blob.getBytes(1, (int) length); } if (x instanceof byte[]) { return toHex((byte[]) x); } return x.toString(); // Last hope! case java.sql.Types.BIT: case JtdsStatement.BOOLEAN: if (x instanceof Boolean) { return x; } else if (x instanceof Number) { return (((Number) x).intValue() == 0) ? Boolean.FALSE : Boolean.TRUE; } else if (x instanceof String) { String tmp = ((String) x).trim(); return ("1".equals(tmp) || "true".equalsIgnoreCase(tmp)) ? Boolean.TRUE : Boolean.FALSE; } break; case java.sql.Types.VARBINARY: case java.sql.Types.BINARY: if (x instanceof byte[]) { return x; } else if (x instanceof Blob) { Blob blob = (Blob) x; return blob.getBytes(1, (int) blob.length()); } else if (x instanceof Clob) { Clob clob = (Clob) x; long length = clob.length(); if (length > Integer.MAX_VALUE) { throw new SQLException(Messages.get("error.normalize.lobtoobig"), "22000"); } x = clob.getSubString(1, (int) length); } if (x instanceof String) { // // Strictly speaking this conversion is not required by // the JDBC standard but jTDS has always supported it. // if (charSet == null) { charSet = "ISO-8859-1"; } try { return ((String) x).getBytes(charSet); } catch (UnsupportedEncodingException e) { return ((String) x).getBytes(); } } else if (x instanceof UniqueIdentifier) { return ((UniqueIdentifier) x).getBytes(); } break; case java.sql.Types.TIMESTAMP: if (x instanceof DateTime) { return ((DateTime) x).toTimestamp(); } else if (x instanceof java.sql.Timestamp) { return x; } else if (x instanceof java.sql.Date) { return new java.sql.Timestamp(((java.sql.Date) x).getTime()); } else if (x instanceof java.sql.Time) { return new java.sql.Timestamp(((java.sql.Time) x).getTime()); } else if (x instanceof java.lang.String) { return java.sql.Timestamp.valueOf(((String) x).trim()); } break; case java.sql.Types.DATE: if (x instanceof DateTime) { return ((DateTime) x).toDate(); } else if (x instanceof java.sql.Date) { return x; } else if (x instanceof java.sql.Time) { return DATE_ZERO; } else if (x instanceof java.sql.Timestamp) { GregorianCalendar cal = (GregorianCalendar) calendar.get(); cal.setTime((java.util.Date) x); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); // VM1.4+ only return new java.sql.Date(cal.getTimeInMillis()); return new java.sql.Date(cal.getTime().getTime()); } else if (x instanceof java.lang.String) { return java.sql.Date.valueOf(((String) x).trim()); } break; case java.sql.Types.TIME: if (x instanceof DateTime) { return ((DateTime) x).toTime(); } else if (x instanceof java.sql.Time) { return x; } else if (x instanceof java.sql.Date) { return TIME_ZERO; } else if (x instanceof java.sql.Timestamp) { GregorianCalendar cal = (GregorianCalendar) calendar.get(); // VM 1.4+ only cal.setTimeInMillis(((java.sql.Timestamp)x).getTime()); cal.setTime((java.util.Date) x); cal.set(Calendar.YEAR, 1970); cal.set(Calendar.MONTH, 0); cal.set(Calendar.DAY_OF_MONTH, 1); // VM 1.4+ only return new java.sql.Time(cal.getTimeInMillis());*/ return new java.sql.Time(cal.getTime().getTime()); } else if (x instanceof java.lang.String) { return java.sql.Time.valueOf(((String) x).trim()); } break; case java.sql.Types.OTHER: return x; case java.sql.Types.JAVA_OBJECT: throw new SQLException( Messages.get( "error.convert.badtypes", x.getClass().getName(), getJdbcTypeName(jdbcType)), "22005"); case java.sql.Types.LONGVARBINARY: case java.sql.Types.BLOB: if (x instanceof Blob) { return x; } else if (x instanceof byte[]) { return new BlobImpl(getConnection(callerReference), (byte[]) x); } else if (x instanceof Clob) { // // Convert CLOB to BLOB. Not required by the standard but we will // do it anyway. // Clob clob = (Clob) x; try { if (charSet == null) { charSet = "ISO-8859-1"; } Reader rdr = clob.getCharacterStream(); BlobImpl blob = new BlobImpl(getConnection(callerReference)); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(blob.setBinaryStream(1), charSet)); // TODO Use a buffer to improve performance int c; while ((c = rdr.read()) >= 0) { out.write(c); } out.close(); rdr.close(); return blob; } catch (UnsupportedEncodingException e) { // Unlikely to happen but fall back on in memory copy x = clob.getSubString(1, (int) clob.length()); } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } if (x instanceof String) { // // Strictly speaking this conversion is also not required by // the JDBC standard but jTDS has always supported it. // BlobImpl blob = new BlobImpl(getConnection(callerReference)); String data = (String) x; if (charSet == null) { charSet = "ISO-8859-1"; } try { blob.setBytes(1, data.getBytes(charSet)); } catch (UnsupportedEncodingException e) { blob.setBytes(1, data.getBytes()); } return blob; } break; case java.sql.Types.LONGVARCHAR: case java.sql.Types.CLOB: if (x instanceof Clob) { return x; } else if (x instanceof Blob) { // // Convert BLOB to CLOB // Blob blob = (Blob) x; try { InputStream is = blob.getBinaryStream(); ClobImpl clob = new ClobImpl(getConnection(callerReference)); Writer out = clob.setCharacterStream(1); // TODO Use a buffer to improve performance int b; // These reads/writes are buffered by the underlying blob buffers while ((b = is.read()) >= 0) { out.write(hex[b >> 4]); out.write(hex[b & 0x0F]); } out.close(); is.close(); return clob; } catch (IOException e) { throw new SQLException( Messages.get("error.generic.ioerror", e.getMessage()), "HY000"); } } else if (x instanceof Boolean) { x = ((Boolean) x).booleanValue() ? "1" : "0"; } else if (!(x instanceof byte[])) { x = x.toString(); } if (x instanceof byte[]) { ClobImpl clob = new ClobImpl(getConnection(callerReference)); clob.setString(1, toHex((byte[]) x)); return clob; } else if (x instanceof String) { return new ClobImpl(getConnection(callerReference), (String) x); } break; default: throw new SQLException( Messages.get("error.convert.badtypeconst", getJdbcTypeName(jdbcType)), "HY004"); } throw new SQLException( Messages.get("error.convert.badtypes", x.getClass().getName(), getJdbcTypeName(jdbcType)), "22005"); } catch (NumberFormatException nfe) { throw new SQLException( Messages.get("error.convert.badnumber", getJdbcTypeName(jdbcType)), "22000"); } }
public void addUnspentTransactionOutput(StoredTransactionOutput out) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; // Calculate the toAddress (if any) String dbAddress = ""; int type = 0; Script outputScript = null; try { outputScript = new Script(out.getScriptBytes()); } catch (ScriptException e) { // Unparseable, but this isn't an error - it's an output not containing an address log.info("Could not parse script for output: " + out.getHash().toString()); } if (outputScript != null && (outputScript.isSentToAddress() || outputScript.isSentToRawPubKey() || outputScript.isPayToScriptHash())) { if (outputScript.isSentToAddress()) { Address targetAddr = new Address(params, outputScript.getPubKeyHash()); dbAddress = targetAddr.toString(); type = 1; } else if (outputScript.isSentToRawPubKey()) { /* * Note we use the deprecated getFromAddress here. Coinbase outputs seem to have the target address * in the pubkey of the script - perhaps we can rename this function? */ dbAddress = outputScript.getFromAddress(params).toString(); type = 2; } else if (outputScript.isPayToScriptHash()) { dbAddress = Address.fromP2SHHash(params, outputScript.getPubKeyHash()).toString(); type = 3; } } try { s = conn.get() .prepareStatement( "INSERT INTO openOutputs (hash, index, height, value, scriptBytes, toAddress, addressTargetable) " + "VALUES (?, ?, ?, ?, ?, ?, ?)"); s.setBytes(1, out.getHash().getBytes()); // index is actually an unsigned int s.setInt(2, (int) out.getIndex()); s.setInt(3, out.getHeight()); s.setBytes(4, out.getValue().toByteArray()); s.setBytes(5, out.getScriptBytes()); s.setString(6, dbAddress); s.setInt(7, type); s.executeUpdate(); s.close(); } catch (SQLException e) { if (!(e.getSQLState().equals(POSTGRES_DUPLICATE_KEY_ERROR_CODE))) throw new BlockStoreException(e); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException(e); } } }