Skip to Main Content

Java Database Connectivity (JDBC)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

setTimestamp("23:00"), "ORA-01877: string is too long for internal buffer"

943610Mar 1 2013 — edited Oct 15 2014
ojdbc can send invalid timestamp values to Oracle via prepared statement parameters.
Oracle can't convert such values, raising ORA-01877. But Oracle can insert them into a table and return without conversion.
This happens when I create a java.sql.Timestamp value 23:00 <= x < 0:00 and < '2010-03-28'.
The value can be created on client or returned from Oracle, it doesn't matter.
Client:
OS: Windows 7 64
Timezone: "Europe/Moscow"

Java:
reproduced on: 1.6.0_31, 1.7.0_07
not reproduced on: 1.5.0_22, 1.4.2_16

driver:
reproduced on: ojdbc6-11.2.0.jar, ojdbc14-10.2.0.3.0.jar
not reproduced on: ojdbc5-11.2.0.1.0.jar
import java.sql.*;

public class Main
{
    private static final String driver = "oracle.jdbc.driver.OracleDriver";
    private static final String url = "jdbc:oracle:thin:@adcserv2:1521:PFMS";

    public static final String username = "scott";
    public static final String password = "tiger";

    public static void main(String[] args)
        throws Exception
    {
        Class.forName(driver);
        Connection cnn = DriverManager.getConnection(url, username, password);
        PreparedStatement st;
        ResultSet rs;
        Timestamp ts;

        st = cnn.prepareStatement("select to_timestamp('2010-03-26 23:00:00', 'yyyy-mm-dd HH24:MI:SS') from dual");
        rs = st.executeQuery();
        rs.next();
        ts = rs.getTimestamp(1);

        st = cnn.prepareStatement("select to_char(?, 'yyyy-mm-dd HH24:MI:SS.FF9') from dual");
        st.setTimestamp(1, ts);
        rs = st.executeQuery(); // <- ORA-01877: string is too long for internal buffer
        rs.next();
        System.out.println(rs.getString(1));
    }
}
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production     
PL/SQL Release 11.2.0.2.0 - Production                                           
CORE	11.2.0.2.0	Production                                                         
TNS for 64-bit Windows: Version 11.2.0.2.0 - Production                          
NLSRTL Version 11.2.0.2.0 - Production                                           
same with
Oracle Database 10g Enterprise Edition Release 10.2.0.2.0 - Prod
The valid timestamp CAN be sent to Oracle using the overloaded method:
setTimestamp(1, ts, null);
but it's not an option, because there's existing software that can't be changed. The only solution I can think of is patching the ojdbc.jar:
class OraclePreparedStatement {
public void setTimestamp(int paramInt, Timestamp paramTimestamp)
  throws SQLException
{
    setTimestampInternal(paramInt, paramTimestamp, null);
}
to call the overloaded method with null calendar.

Here's the dump of valid and invalid values. As you can see, the date part of invalid value is next day.
ALTER session SET NLS_TIMESTAMP_FORMAT="yyyy-mm-dd HH24:MI:SS.FF9";
select a, dump(a), s from testtstamp order by 1;
A                              DUMP(A)                                 S      
------------------------------ --------------------------------------- -------
2001-02-28 23:00:00.000000000  Typ=180 Len=7: 120,101,2,28,24,1,1      valid  
2001-02-28 23:00:00.000000000  Typ=180 Len=7: 120,101,3,1,0,1,1        invalid
2001-03-01 00:00:00.000000000  Typ=180 Len=7: 120,101,3,1,1,1,1        valid  
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Mar 30 2013
Added on Mar 1 2013
3 comments
4,312 views